diff options
author | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
commit | 41af1698c520ea38edf83e7c91f1e519d34f20c1 (patch) | |
tree | 05c516cb7514d80a5e8deccb07cd0f7c228b70d4 /include/clang | |
parent | cd1b175aa96d9d675c09fc54dfd96ba41e3f2279 (diff) | |
parent | 4d085086c74a8fbce197f61548f488a63f300933 (diff) |
Creating branches/google/testing and tags/google/testing/ from r317203
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/testing@317856 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang')
275 files changed, 14222 insertions, 2969 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5fa515d02d..1498c366d7 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -39,6 +39,8 @@ #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/XRayLists.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -88,7 +90,6 @@ class DiagnosticsEngine; class Expr; class MangleNumberingContext; class MaterializeTemporaryExpr; -class TargetInfo; // Decls class MangleContext; class ObjCIvarDecl; @@ -142,6 +143,8 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; mutable llvm::FoldingSet<DependentSizedExtVectorType> DependentSizedExtVectorTypes; + mutable llvm::FoldingSet<DependentAddressSpaceType> + DependentAddressSpaceTypes; mutable llvm::FoldingSet<VectorType> VectorTypes; mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&> @@ -176,12 +179,12 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; - mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage> + mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage> SubstTemplateTemplateParms; mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage, - ASTContext&> + ASTContext&> SubstTemplateTemplateParmPacks; - + /// \brief The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. @@ -203,17 +206,17 @@ class ASTContext : public RefCountedBase<ASTContext> { /// \brief A cache mapping from CXXRecordDecls to key functions. llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions; - + /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; - + /// \brief Mapping from ObjCMethod to its duplicate declaration in the same /// interface. llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls; /// \brief Mapping from __block VarDecls to their copy initialization expr. llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits; - + /// \brief Mapping from class scope functions specialization to their /// template patterns. llvm::DenseMap<const FunctionDecl*, FunctionDecl*> @@ -229,21 +232,21 @@ class ASTContext : public RefCountedBase<ASTContext> { /// is used in canonical template names. class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { TemplateTemplateParmDecl *Parm; - + public: - CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) + CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) : Parm(Parm) { } - + TemplateTemplateParmDecl *getParam() const { return Parm; } - + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); } - - static void Profile(llvm::FoldingSetNodeID &ID, + + static void Profile(llvm::FoldingSetNodeID &ID, TemplateTemplateParmDecl *Parm); }; mutable llvm::FoldingSet<CanonicalTemplateTemplateParm> CanonTemplateTemplateParms; - + TemplateTemplateParmDecl * getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; @@ -262,7 +265,7 @@ class ASTContext : public RefCountedBase<ASTContext> { /// \brief The typedef for the predefined \c id type. mutable TypedefDecl *ObjCIdDecl; - + /// \brief The typedef for the predefined \c SEL type. mutable TypedefDecl *ObjCSelDecl; @@ -271,7 +274,7 @@ class ASTContext : public RefCountedBase<ASTContext> { /// \brief The typedef for the predefined \c Protocol class in Objective-C. mutable ObjCInterfaceDecl *ObjCProtocolClassDecl; - + /// \brief The typedef for the predefined 'BOOL' type. mutable TypedefDecl *BOOLDecl; @@ -301,12 +304,12 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable TypedefDecl *CFConstantStringTypeDecl; mutable QualType ObjCSuperType; - + QualType ObjCNSStringType; /// \brief The typedef declaration for the Objective-C "instancetype" type. TypedefDecl *ObjCInstanceTypeDecl; - + /// \brief The type for the C FILE type. TypeDecl *FILEDecl; @@ -454,17 +457,17 @@ private: /// \brief Mapping that stores parameterIndex values for ParmVarDecls when /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable; - ParameterIndexTable ParamIndices; - + ParameterIndexTable ParamIndices; + ImportDecl *FirstLocalImport; ImportDecl *LastLocalImport; - + TranslationUnitDecl *TUDecl; mutable ExternCContextDecl *ExternCContext; mutable BuiltinTemplateDecl *MakeIntegerSeqDecl; mutable BuiltinTemplateDecl *TypePackElementDecl; - /// \brief The associated SourceManager object.a + /// \brief The associated SourceManager object. SourceManager &SourceMgr; /// \brief The language options used to create the AST associated with @@ -475,6 +478,10 @@ private: /// entities should not be instrumented. std::unique_ptr<SanitizerBlacklist> SanitizerBL; + /// \brief Function filtering mechanism to determine whether a given function + /// should be imbued with the XRay "always" or "never" attributes. + std::unique_ptr<XRayFunctionFilter> XRayFilter; + /// \brief The allocator used to create AST objects. /// /// AST objects are never destructed; rather, all memory associated with the @@ -489,9 +496,9 @@ private: CXXABI *createCXXABI(const TargetInfo &T); /// \brief The logical -> physical address space map. - const LangAS::Map *AddrSpaceMap; + const LangASMap *AddrSpaceMap; - /// \brief Address space map mangling must be used with language specific + /// \brief Address space map mangling must be used with language specific /// address spaces (e.g. OpenCL/CUDA) bool AddrSpaceMapMangling; @@ -503,7 +510,7 @@ private: const TargetInfo *Target; const TargetInfo *AuxTarget; clang::PrintingPolicy PrintingPolicy; - + public: IdentifierTable &Idents; SelectorTable &Selectors; @@ -607,7 +614,7 @@ public: void setPrintingPolicy(const clang::PrintingPolicy &Policy) { PrintingPolicy = Policy; } - + SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } @@ -622,7 +629,7 @@ public: return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T))); } void Deallocate(void *Ptr) const { } - + /// Return the total amount of physical memory allocated for representing /// AST nodes and type information. size_t getASTAllocatedMemory() const { @@ -630,7 +637,7 @@ public: } /// Return the total memory used for various side tables. size_t getSideTableAllocatedMemory() const; - + PartialDiagnostic::StorageAllocator &getDiagAllocator() { return DiagAllocator; } @@ -650,13 +657,17 @@ public: QualType getRealTypeForBitwidth(unsigned DestWidth) const; bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const; - + const LangOptions& getLangOpts() const { return LangOpts; } const SanitizerBlacklist &getSanitizerBlacklist() const { return *SanitizerBL; } + const XRayFunctionFilter &getXRayFilter() const { + return *XRayFilter; + } + DiagnosticsEngine &getDiagnostics() const; FullSourceLoc getFullLoc(SourceLocation Loc) const { @@ -865,7 +876,7 @@ public: FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); - + // Access to the set of methods overridden by the given C++ method. typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator; overridden_cxx_method_iterator @@ -881,7 +892,7 @@ public: /// \brief Note that the given C++ \p Method overrides the given \p /// Overridden method. - void addOverriddenMethod(const CXXMethodDecl *Method, + void addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden); /// \brief Return C++ or ObjC overridden methods for the given \p Method. @@ -894,7 +905,7 @@ public: void getOverriddenMethods( const NamedDecl *Method, SmallVectorImpl<const NamedDecl *> &Overridden) const; - + /// \brief Notify the AST context that a new import declaration has been /// parsed or implicitly created within this translation unit. void addedLocalImportDecl(ImportDecl *Import); @@ -902,7 +913,7 @@ public: static ImportDecl *getNextLocalImport(ImportDecl *Import) { return Import->NextLocalImport; } - + typedef llvm::iterator_range<import_iterator> import_range; import_range local_imports() const { return import_range(import_iterator(FirstLocalImport), import_iterator()); @@ -926,7 +937,7 @@ public: /// \brief Get the additional modules in which the definition \p Def has /// been merged. - ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) { + ArrayRef<Module*> getModulesWithMergedDefinition(const NamedDecl *Def) { auto MergedIt = MergedDefModules.find(Def); if (MergedIt == MergedDefModules.end()) return None; @@ -964,6 +975,7 @@ public: CanQualType UnsignedLongLongTy, UnsignedInt128Ty; CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty; CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON + CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType Float128ComplexTy; CanQualType VoidPtrTy, NullPtrTy; @@ -1058,7 +1070,14 @@ public: /// The resulting type has a union of the qualifiers from T and the address /// space. If T already has an address space specifier, it is silently /// replaced. - QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const; + + /// \brief Remove any existing address space on the type and returns the type + /// with qualifiers intact (or that's the idea anyway) + /// + /// The return type should be T with all prior qualifiers minus the address + /// space. + QualType removeAddrSpaceQualType(QualType T) const; /// \brief Apply Objective-C protocol qualifiers to the given type. /// \param allowOnPointerType specifies if we can apply protocol @@ -1182,15 +1201,15 @@ public: /// Returns true iff we need copy/dispose helpers for the given type. bool BlockRequiresCopying(QualType Ty, const VarDecl *D); - - + + /// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set /// to false in this case. If HasByrefExtendedLayout returns true, byref variable - /// has extended lifetime. + /// has extended lifetime. bool getByrefLifetime(QualType Ty, Qualifiers::ObjCLifetime &Lifetime, bool &HasByrefExtendedLayout) const; - + /// \brief Return the uniqued reference to the type for an lvalue reference /// to the specified type. QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true) @@ -1234,7 +1253,7 @@ public: QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, ArrayType::ArraySizeModifier ASM, unsigned IndexTypeQuals) const; - + /// \brief Returns a vla type where known sizes are replaced with [*]. QualType getVariableArrayDecayedType(QualType Ty) const; @@ -1260,6 +1279,10 @@ public: Expr *SizeExpr, SourceLocation AttrLoc) const; + QualType getDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttrLoc) const; + /// \brief Return a K&R style C function type like 'int()'. QualType getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const; @@ -1385,7 +1408,7 @@ public: QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl, ArrayRef<ObjCProtocolDecl *> protocols, QualType Canonical = QualType()) const; - + bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in /// QT's qualified-id protocol list adopt all protocols in IDecl's list @@ -1432,6 +1455,10 @@ public: /// The sizeof operator requires this (C99 6.5.3.4p4). CanQualType getSizeType() const; + /// \brief Return the unique signed counterpart of + /// the integer type corresponding to size_t. + CanQualType getSignedSizeType() const; + /// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in /// <stdint.h>. CanQualType getIntMaxType() const; @@ -1475,17 +1502,22 @@ public: /// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; + /// \brief Return the unique unsigned counterpart of "ptrdiff_t" + /// integer type. The standard (C11 7.21.6.1p7) refers to this type + /// in the definition of %tu format specifier. + QualType getUnsignedPointerDiffType() const; + /// \brief Return the unique type for "pid_t" defined in /// <sys/types.h>. We need this to compute the correct type for vfork(). QualType getProcessIDType() const; /// \brief Return the C structure type used to represent constant CFStrings. QualType getCFConstantStringType() const; - + /// \brief Returns the C struct type for objc_super QualType getObjCSuperType() const; void setObjCSuperType(QualType ST) { ObjCSuperType = ST; } - + /// Get the structure type used to representation CFStrings, or NULL /// if it hasn't yet been built. QualType getRawCFConstantStringType() const { @@ -1506,11 +1538,11 @@ public: QualType getObjCNSStringType() const { return ObjCNSStringType; } - + void setObjCNSStringType(QualType T) { ObjCNSStringType = T; } - + /// \brief Retrieve the type that \c id has been defined to, which may be /// different from the built-in \c id if \c id has been typedef'd. QualType getObjCIdRedefinitionType() const { @@ -1518,7 +1550,7 @@ public: return getObjCIdType(); return ObjCIdRedefinitionType; } - + /// \brief Set the user-written type that redefines \c id. void setObjCIdRedefinitionType(QualType RedefType) { ObjCIdRedefinitionType = RedefType; @@ -1531,7 +1563,7 @@ public: return getObjCClassType(); return ObjCClassRedefinitionType; } - + /// \brief Set the user-written type that redefines 'SEL'. void setObjCClassRedefinitionType(QualType RedefType) { ObjCClassRedefinitionType = RedefType; @@ -1544,7 +1576,7 @@ public: return getObjCSelType(); return ObjCSelRedefinitionType; } - + /// \brief Set the user-written type that redefines 'SEL'. void setObjCSelRedefinitionType(QualType RedefType) { ObjCSelRedefinitionType = RedefType; @@ -1568,6 +1600,24 @@ public: return NSCopyingName; } + CanQualType getNSUIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return UnsignedLongLongTy; + return UnsignedLongTy; + } + + CanQualType getNSIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return LongLongTy; + return LongTy; + } + /// Retrieve the identifier 'bool'. IdentifierInfo *getBoolName() const { if (!BoolName) @@ -1596,7 +1646,7 @@ public: /// \brief Retrieve the typedef declaration corresponding to the Objective-C /// "instancetype" type. TypedefDecl *getObjCInstanceTypeDecl(); - + /// \brief Set the type for the C FILE type. void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; } @@ -1681,7 +1731,7 @@ public: /// \brief Return the encoded type for this block declaration. std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const; - + /// getObjCEncodingForPropertyDecl - Return the encoded type for /// this method declaration. If non-NULL, Container must be either /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should @@ -1691,7 +1741,7 @@ public: bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, ObjCProtocolDecl *rProto) const; - + ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl( const ObjCPropertyDecl *PD, const Decl *Container) const; @@ -1703,7 +1753,7 @@ public: /// \brief Retrieve the typedef corresponding to the predefined \c id type /// in Objective-C. TypedefDecl *getObjCIdDecl() const; - + /// \brief Represents the Objective-CC \c id type. /// /// This is set up lazily, by Sema. \c id is always a (typedef for a) @@ -1715,26 +1765,26 @@ public: /// \brief Retrieve the typedef corresponding to the predefined 'SEL' type /// in Objective-C. TypedefDecl *getObjCSelDecl() const; - + /// \brief Retrieve the type that corresponds to the predefined Objective-C /// 'SEL' type. - QualType getObjCSelType() const { + QualType getObjCSelType() const { return getTypeDeclType(getObjCSelDecl()); } /// \brief Retrieve the typedef declaration corresponding to the predefined /// Objective-C 'Class' type. TypedefDecl *getObjCClassDecl() const; - + /// \brief Represents the Objective-C \c Class type. /// /// This is set up lazily, by Sema. \c Class is always a (typedef for a) /// pointer type, a pointer to a struct. - QualType getObjCClassType() const { + QualType getObjCClassType() const { return getTypeDeclType(getObjCClassDecl()); } - /// \brief Retrieve the Objective-C class declaration corresponding to + /// \brief Retrieve the Objective-C class declaration corresponding to /// the predefined \c Protocol class. ObjCInterfaceDecl *getObjCProtocolDecl() const; @@ -1752,12 +1802,12 @@ public: QualType getBOOLType() const { return getTypeDeclType(getBOOLDecl()); } - + /// \brief Retrieve the type of the Objective-C \c Protocol class. QualType getObjCProtoType() const { return getObjCInterfaceType(getObjCProtocolDecl()); } - + /// \brief Retrieve the C type declaration corresponding to the predefined /// \c __builtin_va_list type. TypedefDecl *getBuiltinVaListDecl() const; @@ -1820,7 +1870,7 @@ public: qs.addObjCLifetime(lifetime); return getQualifiedType(type, qs); } - + /// getUnqualifiedObjCPointerType - Returns version of /// Objective-C pointer type with lifetime qualifier removed. QualType getUnqualifiedObjCPointerType(QualType type) const { @@ -1831,7 +1881,7 @@ public: Qs.removeObjCLifetime(); return getQualifiedType(type.getUnqualifiedType(), Qs); } - + DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; @@ -1850,7 +1900,7 @@ public: TemplateName replacement) const; TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const; - + enum GetBuiltinTypeError { GE_None, ///< No error GE_Missing_stdio, ///< Missing a type from <stdio.h> @@ -1915,7 +1965,7 @@ public: uint64_t getCharWidth() const { return getTypeSize(CharTy); } - + /// \brief Convert a size in bits to a size in characters. CharUnits toCharUnitsFromBits(int64_t BitSize) const; @@ -1937,11 +1987,11 @@ public: /// example, from alignment attributes). unsigned getTypeAlignIfKnown(QualType T) const; - /// \brief Return the ABI-specified alignment of a (complete) type \p T, in + /// \brief Return the ABI-specified alignment of a (complete) type \p T, in /// characters. CharUnits getTypeAlignInChars(QualType T) const; CharUnits getTypeAlignInChars(const Type *T) const; - + // getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the // type is a record, its data size is returned. std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const; @@ -2041,15 +2091,20 @@ public: /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits. uint64_t getFieldOffset(const ValueDecl *FD) const; + /// Get the offset of an ObjCIvarDecl in bits. + uint64_t lookupFieldBitOffset(const ObjCInterfaceDecl *OID, + const ObjCImplementationDecl *ID, + const ObjCIvarDecl *Ivar) const; + bool isNearlyEmpty(const CXXRecordDecl *RD) const; VTableContextBase *getVTableContext(); MangleContext *createMangleContext(); - + void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const; - + unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const; void CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols); @@ -2125,7 +2180,7 @@ public: *SubTnullability == NullabilityKind::Unspecified || *SuperTnullability == NullabilityKind::Unspecified) return true; - + if (IsParam) { // Ok for the superclass method parameter to be "nonnull" and the subclass // method parameter to be "nullable" @@ -2144,9 +2199,9 @@ public: bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodImp); - + bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); - + /// \brief Retrieves the "canonical" nested name specifier for a /// given nested name specifier. /// @@ -2174,7 +2229,7 @@ public: getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; /// \brief Retrieves the default calling convention for the current target. - CallingConv getDefaultCallingConvention(bool isVariadic, + CallingConv getDefaultCallingConvention(bool IsVariadic, bool IsCXXMethod) const; /// \brief Retrieves the "canonical" template name that refers to a @@ -2200,7 +2255,7 @@ public: /// \brief Determine whether the given template names refer to the same /// template. bool hasSameTemplateName(TemplateName X, TemplateName Y); - + /// \brief Retrieve the "canonical" template argument. /// /// The canonical template argument is the simplest template argument @@ -2227,7 +2282,7 @@ public: const { return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T)); } - + /// \brief Return the innermost element type of an array type. /// /// For example, will return "int" for int[m][n] @@ -2246,14 +2301,14 @@ public: /// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], /// C++ [dcl.fct]p3). The adjusted parameter type is returned. QualType getAdjustedParameterType(QualType T) const; - + /// \brief Retrieve the parameter type as adjusted for use in the signature /// of a function, decaying array and function types and removing top-level /// cv-qualifiers. QualType getSignatureParameterType(QualType T) const; - + QualType getExceptionObjectType(QualType T) const; - + /// \brief Return the properly qualified result of decaying the specified /// array type to a pointer. /// @@ -2279,7 +2334,7 @@ public: /// promotion occurs. QualType isPromotableBitField(Expr *E) const; - /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1. + /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1. /// /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If /// \p LHS < \p RHS, return -1. @@ -2308,21 +2363,14 @@ public: return getTargetAddressSpace(Q.getAddressSpace()); } - unsigned getTargetAddressSpace(unsigned AS) const { - if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count) - return AS; - else - return (*AddrSpaceMap)[AS - LangAS::Offset]; - } + unsigned getTargetAddressSpace(LangAS AS) const; /// Get target-dependent integer value for null pointer which is used for /// constant folding. uint64_t getTargetNullPointerValue(QualType QT) const; - bool addressSpaceMapManglingFor(unsigned AS) const { - return AddrSpaceMapMangling || - AS < LangAS::Offset || - AS >= LangAS::Offset + LangAS::Count; + bool addressSpaceMapManglingFor(LangAS AS) const { + return AddrSpaceMapMangling || isTargetAddressSpace(AS); } private: @@ -2335,11 +2383,11 @@ public: //===--------------------------------------------------------------------===// /// Compatibility predicates used to check assignment expressions. - bool typesAreCompatible(QualType T1, QualType T2, + bool typesAreCompatible(QualType T1, QualType T2, bool CompareUnqualified = false); // C99 6.2.7p1 - bool propertyTypesAreCompatible(QualType, QualType); - bool typesAreBlockPointerCompatible(QualType, QualType); + bool propertyTypesAreCompatible(QualType, QualType); + bool typesAreBlockPointerCompatible(QualType, QualType); bool isObjCIdType(QualType T) const { return T == getObjCIdType(); @@ -2354,7 +2402,7 @@ public: bool ForCompare); bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS); - + // Check the safety of assignment from LHS to RHS bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT); @@ -2380,12 +2428,33 @@ public: QualType mergeTransparentUnionType(QualType, QualType, bool OfBlockPointer=false, bool Unqualified = false); - + QualType mergeObjCGCQualifiers(QualType, QualType); - - bool doFunctionTypesMatchOnExtParameterInfos( - const FunctionProtoType *FromFunctionType, - const FunctionProtoType *ToFunctionType); + + /// This function merges the ExtParameterInfo lists of two functions. It + /// returns true if the lists are compatible. The merged list is returned in + /// NewParamInfos. + /// + /// \param FirstFnType The type of the first function. + /// + /// \param SecondFnType The type of the second function. + /// + /// \param CanUseFirst This flag is set to true if the first function's + /// ExtParameterInfo list can be used as the composite list of + /// ExtParameterInfo. + /// + /// \param CanUseSecond This flag is set to true if the second function's + /// ExtParameterInfo list can be used as the composite list of + /// ExtParameterInfo. + /// + /// \param NewParamInfos The composite list of ExtParameterInfo. The list is + /// empty if none of the flags are set. + /// + bool mergeExtParameterInfo( + const FunctionProtoType *FirstFnType, + const FunctionProtoType *SecondFnType, + bool &CanUseFirst, bool &CanUseSecond, + SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos); void ResetObjCLayout(const ObjCContainerDecl *CD); @@ -2452,7 +2521,7 @@ public: /// an Objective-C method/property/ivar etc. that is part of an interface, /// otherwise returns null. const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const; - + /// \brief Set the copy inialization expression of a block var decl. void setBlockVarCopyInits(VarDecl*VD, Expr* Init); /// \brief Get the copy initialization expression of the VarDecl \p VD, or @@ -2476,10 +2545,10 @@ public: /// initialized to a given location, which defaults to the empty /// location. TypeSourceInfo * - getTrivialTypeSourceInfo(QualType T, + getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation()) const; - /// \brief Add a deallocation callback that will be invoked when the + /// \brief Add a deallocation callback that will be invoked when the /// ASTContext is destroyed. /// /// \param Callback A callback function that will be invoked on destruction. @@ -2507,7 +2576,7 @@ public: /// /// \returns true if the function/var must be CodeGen'ed/deserialized even if /// it is not used. - bool DeclMustBeEmitted(const Decl *D, bool ForModularCodegen = false); + bool DeclMustBeEmitted(const Decl *D); const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); @@ -2554,15 +2623,15 @@ public: /// \brief The number of implicitly-declared default constructors. static unsigned NumImplicitDefaultConstructors; - - /// \brief The number of implicitly-declared default constructors for + + /// \brief The number of implicitly-declared default constructors for /// which declarations were built. static unsigned NumImplicitDefaultConstructorsDeclared; /// \brief The number of implicitly-declared copy constructors. static unsigned NumImplicitCopyConstructors; - - /// \brief The number of implicitly-declared copy constructors for + + /// \brief The number of implicitly-declared copy constructors for /// which declarations were built. static unsigned NumImplicitCopyConstructorsDeclared; @@ -2575,25 +2644,25 @@ public: /// \brief The number of implicitly-declared copy assignment operators. static unsigned NumImplicitCopyAssignmentOperators; - - /// \brief The number of implicitly-declared copy assignment operators for + + /// \brief The number of implicitly-declared copy assignment operators for /// which declarations were built. static unsigned NumImplicitCopyAssignmentOperatorsDeclared; /// \brief The number of implicitly-declared move assignment operators. static unsigned NumImplicitMoveAssignmentOperators; - - /// \brief The number of implicitly-declared move assignment operators for + + /// \brief The number of implicitly-declared move assignment operators for /// which declarations were built. static unsigned NumImplicitMoveAssignmentOperatorsDeclared; /// \brief The number of implicitly-declared destructors. static unsigned NumImplicitDestructors; - - /// \brief The number of implicitly-declared destructors for which + + /// \brief The number of implicitly-declared destructors for which /// declarations were built. static unsigned NumImplicitDestructorsDeclared; - + public: /// \brief Initialize built-in types. /// @@ -2710,13 +2779,13 @@ public: }; /// \brief Utility function for constructing a nullary selector. -static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) { +inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); } /// \brief Utility function for constructing an unary selector. -static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) { +inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(1, &II); } diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index a8eff1a2fc..ed82b32342 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -22,6 +22,7 @@ namespace clang { class CXXRecordDecl; class Decl; class DeclContext; + class Expr; class FieldDecl; class FunctionDecl; class FunctionTemplateDecl; @@ -80,7 +81,8 @@ public: /// \brief A virtual destructor's operator delete has been resolved. virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) {} + const FunctionDecl *Delete, + Expr *ThisArg) {} /// \brief An implicit member got a definition. virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} diff --git a/include/clang/AST/ASTStructuralEquivalence.h b/include/clang/AST/ASTStructuralEquivalence.h new file mode 100644 index 0000000000..23674c65f3 --- /dev/null +++ b/include/clang/AST/ASTStructuralEquivalence.h @@ -0,0 +1,103 @@ +//===--- ASTStructuralEquivalence.h - ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StructuralEquivalenceContext class which checks for +// structural equivalence between types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H +#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include <deque> + +namespace clang { + +class ASTContext; +class Decl; +class DiagnosticBuilder; +class QualType; +class RecordDecl; +class SourceLocation; + +struct StructuralEquivalenceContext { + /// AST contexts for which we are checking structural equivalence. + ASTContext &FromCtx, &ToCtx; + + /// The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; + + /// Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque<Decl *> DeclsToCheck; + + /// Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls; + + /// Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + /// Whether warn or error on tag type mismatches. + bool ErrorOnTagTypeMismatch; + + /// Whether to complain about failures. + bool Complain; + + /// \c true if the last diagnostic came from ToCtx. + bool LastDiagFromC2; + + StructuralEquivalenceContext( + ASTContext &FromCtx, ASTContext &ToCtx, + llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls, + bool StrictTypeSpelling = false, bool Complain = true, + bool ErrorOnTagTypeMismatch = false) + : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling), + ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain), + LastDiagFromC2(false) {} + + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); + + /// Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + /// Find the index of the given anonymous struct/union within its + /// context. + /// + /// \returns Returns the index of this anonymous struct/union in its context, + /// including the next assigned index (if none of them match). Returns an + /// empty option if the context is not a record, i.e.. if the anonymous + /// struct/union is at namespace or block scope. + /// + /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It + /// probably makes more sense in some other common place then here. + static llvm::Optional<unsigned> + findUntaggedStructOrUnionIndex(RecordDecl *Anon); + +private: + /// Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); +}; +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def index 181131aba0..e4f5f7db2f 100644 --- a/include/clang/AST/BuiltinTypes.def +++ b/include/clang/AST/BuiltinTypes.def @@ -133,6 +133,9 @@ FLOATING_TYPE(Double, DoubleTy) // 'long double' FLOATING_TYPE(LongDouble, LongDoubleTy) +// '_Float16' +FLOATING_TYPE(Float16, HalfTy) + // '__float128' FLOATING_TYPE(Float128, Float128Ty) diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt index 260734f220..942d08d585 100644 --- a/include/clang/AST/CMakeLists.txt +++ b/include/clang/AST/CMakeLists.txt @@ -50,3 +50,6 @@ clang_tablegen(CommentCommandList.inc -gen-clang-comment-command-list SOURCE CommentCommands.td TARGET ClangCommentCommandList) +clang_tablegen(StmtDataCollectors.inc -gen-clang-data-collectors + SOURCE StmtDataCollectors.td + TARGET StmtDataCollectors) diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index 3cf058f26b..980608570f 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -127,7 +127,11 @@ class CXXBasePaths { /// class subobjects for that class type. The key of the map is /// the cv-unqualified canonical type of the base class subobject. llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects; - + + /// VisitedDependentRecords - Records the dependent records that have been + /// already visited. + llvm::SmallDenseSet<const CXXRecordDecl *, 4> VisitedDependentRecords; + /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find /// ambiguous paths while it is looking for a path from a derived /// type to a base type. @@ -161,7 +165,8 @@ class CXXBasePaths { void ComputeDeclsFound(); bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record, - CXXRecordDecl::BaseMatchesCallback BaseMatches); + CXXRecordDecl::BaseMatchesCallback BaseMatches, + bool LookupInDependent = false); public: typedef std::list<CXXBasePath>::iterator paths_iterator; diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 25f6172be9..023456e2e3 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -359,8 +359,7 @@ struct simplify_type< ::clang::CanQual<T> > { // Teach SmallPtrSet that CanQual<T> is "basically a pointer". template<typename T> -class PointerLikeTypeTraits<clang::CanQual<T> > { -public: +struct PointerLikeTypeTraits<clang::CanQual<T> > { static inline void *getAsVoidPointer(clang::CanQual<T> P) { return P.getAsOpaquePtr(); } diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h index 564c8ec9b9..ddead6046a 100644 --- a/include/clang/AST/CharUnits.h +++ b/include/clang/AST/CharUnits.h @@ -40,14 +40,14 @@ namespace clang { typedef int64_t QuantityType; private: - QuantityType Quantity; + QuantityType Quantity = 0; explicit CharUnits(QuantityType C) : Quantity(C) {} public: /// CharUnits - A default constructor. - CharUnits() : Quantity(0) {} + CharUnits() = default; /// Zero - Construct a CharUnits quantity of zero. static CharUnits Zero() { diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h index 6a803836e8..230e52739f 100644 --- a/include/clang/AST/CommentSema.h +++ b/include/clang/AST/CommentSema.h @@ -208,6 +208,10 @@ public: /// \returns \c true if declaration that this comment is attached to declares /// a function pointer. bool isFunctionPointerVarDecl(); + /// \returns \c true if the declaration that this comment is attached to + /// declares a variable or a field whose type is a function or a block + /// pointer. + bool isFunctionOrBlockPointerVarLikeDecl(); bool isFunctionOrMethodVariadic(); bool isObjCMethodDecl(); bool isObjCPropertyDecl(); diff --git a/include/clang/AST/DataCollection.h b/include/clang/AST/DataCollection.h new file mode 100644 index 0000000000..229ac2bd0f --- /dev/null +++ b/include/clang/AST/DataCollection.h @@ -0,0 +1,65 @@ +//===--- DatatCollection.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file declares helper methods for collecting data from AST nodes. +/// +/// To collect data from Stmt nodes, subclass ConstStmtVisitor and include +/// StmtDataCollectors.inc after defining the macros that you need. This +/// provides data collection implementations for most Stmt kinds. Note +/// that that code requires some conditions to be met: +/// +/// - There must be a method addData(const T &Data) that accepts strings, +/// integral types as well as QualType. All data is forwarded using +/// to this method. +/// - The ASTContext of the Stmt must be accessible by the name Context. +/// +/// It is also possible to override individual visit methods. Have a look at +/// the DataCollector in lib/Analysis/CloneDetection.cpp for a usage example. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DATACOLLECTION_H +#define LLVM_CLANG_AST_DATACOLLECTION_H + +#include "clang/AST/ASTContext.h" + +namespace clang { +namespace data_collection { + +/// Returns a string that represents all macro expansions that expanded into the +/// given SourceLocation. +/// +/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations +/// A and B are expanded from the same macros in the same order. +std::string getMacroStack(SourceLocation Loc, ASTContext &Context); + +/// Utility functions for implementing addData() for a consumer that has a +/// method update(StringRef) +template <class T> +void addDataToConsumer(T &DataConsumer, llvm::StringRef Str) { + DataConsumer.update(Str); +} + +template <class T> void addDataToConsumer(T &DataConsumer, const QualType &QT) { + addDataToConsumer(DataConsumer, QT.getAsString()); +} + +template <class T, class Type> +typename std::enable_if< + std::is_integral<Type>::value || std::is_enum<Type>::value || + std::is_convertible<Type, size_t>::value // for llvm::hash_code + >::type +addDataToConsumer(T &DataConsumer, Type Data) { + DataConsumer.update(StringRef(reinterpret_cast<char *>(&Data), sizeof(Data))); +} + +} // end namespace data_collection +} // end namespace clang + +#endif // LLVM_CLANG_AST_DATACOLLECTION_H diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index d1c77f5e08..ef0f502a35 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -301,16 +301,6 @@ public: using Decl::isModulePrivate; using Decl::setModulePrivate; - /// \brief Determine whether this declaration is hidden from name lookup. - bool isHidden() const { return Hidden; } - - /// \brief Set whether this declaration is hidden from name lookup. - void setHidden(bool Hide) { - assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) && - "declaration with no owning module can't be hidden"); - Hidden = Hide; - } - /// \brief Determine whether this declaration is a C++ class member. bool isCXXClassMember() const { const DeclContext *DC = getDeclContext(); @@ -349,6 +339,12 @@ public: return clang::isExternallyVisible(getLinkageInternal()); } + /// Determine whether this declaration can be redeclared in a + /// different translation unit. + bool isExternallyDeclarable() const { + return isExternallyVisible() && !getOwningModuleForLinkage(); + } + /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); @@ -359,7 +355,14 @@ public: /// Kinds of explicit visibility. enum ExplicitVisibilityKind { + /// Do an LV computation for, ultimately, a type. + /// Visibility may be restricted by type visibility settings and + /// the visibility of template arguments. VisibilityForType, + + /// Do an LV computation for, ultimately, a non-type declaration. + /// Visibility may be restricted by value visibility settings and + /// the visibility of template arguments. VisibilityForValue }; @@ -838,7 +841,7 @@ protected: /// Describes the kind of default argument for this parameter. By default /// this is none. If this is normal, then the default argument is stored in - /// the \c VarDecl initalizer expression unless we were unble to parse + /// the \c VarDecl initializer expression unless we were unable to parse /// (even an invalid) expression for the default argument. unsigned DefaultArgKind : 2; @@ -861,6 +864,7 @@ protected: class NonParmVarDeclBitfields { friend class VarDecl; + friend class ImplicitParamDecl; friend class ASTDeclReader; unsigned : NumVarDeclBits; @@ -904,6 +908,10 @@ protected: /// declared in the same block scope. This controls whether we should merge /// the type of this declaration with its previous declaration. unsigned PreviousDeclInSameBlockScope : 1; + + /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or + /// something else. + unsigned ImplicitParamKind : 3; }; union { @@ -966,9 +974,16 @@ public: /// hasLocalStorage - Returns true if a variable with function scope /// is a non-static local variable. bool hasLocalStorage() const { - if (getStorageClass() == SC_None) + if (getStorageClass() == SC_None) { + // OpenCL v1.2 s6.5.3: The __constant or constant address space name is + // used to describe variables allocated in global memory and which are + // accessed inside a kernel(s) as read-only variables. As such, variables + // in constant address space cannot have local storage. + if (getType().getAddressSpace() == LangAS::opencl_constant) + return false; // Second check is for C++11 [dcl.stc]p4. return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified; + } // Global Named Register (GNU extension) if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm()) @@ -1379,20 +1394,50 @@ public: class ImplicitParamDecl : public VarDecl { void anchor() override; + public: + /// Defines the kind of the implicit parameter: is this an implicit parameter + /// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured + /// context or something else. + enum ImplicitParamKind : unsigned { + ObjCSelf, /// Parameter for Objective-C 'self' argument + ObjCCmd, /// Parameter for Objective-C '_cmd' argument + CXXThis, /// Parameter for C++ 'this' argument + CXXVTT, /// Parameter for C++ virtual table pointers + CapturedContext, /// Parameter for captured context + Other, /// Other implicit parameter + }; + + /// Create implicit parameter. static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, - QualType T); + QualType T, ImplicitParamKind ParamKind); + static ImplicitParamDecl *Create(ASTContext &C, QualType T, + ImplicitParamKind ParamKind); static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, - IdentifierInfo *Id, QualType Type) - : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, - /*tinfo*/ nullptr, SC_None) { + IdentifierInfo *Id, QualType Type, + ImplicitParamKind ParamKind) + : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, + /*TInfo=*/nullptr, SC_None) { + NonParmVarDeclBits.ImplicitParamKind = ParamKind; setImplicit(); } + ImplicitParamDecl(ASTContext &C, QualType Type, ImplicitParamKind ParamKind) + : VarDecl(ImplicitParam, C, /*DC=*/nullptr, SourceLocation(), + SourceLocation(), /*Id=*/nullptr, Type, + /*TInfo=*/nullptr, SC_None) { + NonParmVarDeclBits.ImplicitParamKind = ParamKind; + setImplicit(); + } + + /// Returns the implicit parameter kind. + ImplicitParamKind getParameterKind() const { + return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind); + } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ImplicitParam; } @@ -1624,6 +1669,7 @@ private: unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; + unsigned InstantiationIsPending:1; /// \brief Indicates if the function uses __try. unsigned UsesSEHTry : 1; @@ -1632,11 +1678,18 @@ private: /// skipped. unsigned HasSkippedBody : 1; - /// Indicates if the function declaration will have a body, once we're done - /// parsing it. (We don't set it to false when we're done parsing, in the - /// hopes this is simpler.) - unsigned WillHaveBody : 1; - +protected: + // Since a Deduction Guide [C++17] will never have a body, we can share the + // storage, and use a different name. + union { + /// Indicates if the function declaration will have a body, once we're done + /// parsing it. + unsigned WillHaveBody : 1; + /// Indicates that the Deduction Guide is the implicitly generated 'copy + /// deduction candidate' (is used during overload resolution). + unsigned IsCopyDeductionCandidate : 1; + }; +private: /// \brief End part of this FunctionDecl's source range. /// /// We could compute the full range in getSourceRange(). However, when we're @@ -1719,6 +1772,7 @@ protected: IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), + InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1832,14 +1886,15 @@ public: return getBody(Definition); } - /// isThisDeclarationADefinition - Returns whether this specific - /// declaration of the function is also a definition. This does not - /// determine whether the function has been defined (e.g., in a - /// previous definition); for that information, use isDefined. Note - /// that this returns false for a defaulted function unless that function - /// has been implicitly defined (possibly as deleted). + /// Returns whether this specific declaration of the function is also a + /// definition that does not contain uninstantiated body. + /// + /// This does not determine whether the function has been defined (e.g., in a + /// previous definition); for that information, use isDefined. + /// bool isThisDeclarationADefinition() const { - return IsDeleted || Body || IsLateTemplateParsed; + return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed || + WillHaveBody || hasDefiningAttr(); } /// doesThisDeclarationHaveABody - Returns whether this specific @@ -1910,6 +1965,15 @@ public: bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } + /// \brief Whether the instantiation of this function is pending. + /// This bit is set when the decision to instantiate this function is made + /// and unset if and when the function body is created. That leaves out + /// cases where instantiation did not happen because the template definition + /// was not seen in this TU. This bit remains set in those cases, under the + /// assumption that the instantiation will happen in some other TU. + bool instantiationIsPending() const { return InstantiationIsPending; } + void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; } + /// \brief Indicates the function uses __try. bool usesSEHTry() const { return UsesSEHTry; } void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } @@ -1975,7 +2039,13 @@ public: /// These functions have special behavior under C++1y [expr.new]: /// An implementation is allowed to omit a call to a replaceable global /// allocation function. [...] - bool isReplaceableGlobalAllocationFunction() const; + /// + /// If this function is an aligned allocation/deallocation function, return + /// true through IsAligned. + bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; + + /// \brief Determine whether this is a destroying operator delete. + bool isDestroyingOperatorDelete() const; /// Compute the language linkage. LanguageLinkage getLanguageLinkage() const; @@ -2082,10 +2152,7 @@ public: const Attr *getUnusedResultAttr() const; /// \brief Returns true if this function or its return type has the - /// warn_unused_result attribute. If the return type has the attribute and - /// this function is a method of the return type's class, then false will be - /// returned to avoid spurious warnings on member methods such as assignment - /// operators. + /// warn_unused_result attribute. bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; } /// \brief Returns the storage class as written in the source. For the @@ -2321,9 +2388,9 @@ public: /// FieldDecl - An instance of this class is created by Sema::ActOnField to /// represent a member of a struct/union/class. class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { - // FIXME: This can be packed into the bitfields in Decl. + unsigned BitField : 1; unsigned Mutable : 1; - mutable unsigned CachedFieldIndex : 31; + mutable unsigned CachedFieldIndex : 30; /// The kinds of value we can store in InitializerOrBitWidth. /// @@ -2333,7 +2400,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { /// If the pointer is null, there's nothing special. Otherwise, /// this is a bitfield and the pointer is the Expr* storing the /// bit-width. - ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit, + ISK_NoInit = (unsigned) ICIS_NoInit, /// The pointer is an (optional due to delayed parsing) Expr* /// holding the copy-initializer. @@ -2348,27 +2415,34 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { ISK_CapturedVLAType, }; - /// \brief Storage for either the bit-width, the in-class - /// initializer, or the captured variable length array bound. - /// - /// We can safely combine these because in-class initializers are - /// not permitted for bit-fields, and both are exclusive with VLA - /// captures. + /// If this is a bitfield with a default member initializer, this + /// structure is used to represent the two expressions. + struct InitAndBitWidth { + Expr *Init; + Expr *BitWidth; + }; + + /// \brief Storage for either the bit-width, the in-class initializer, or + /// both (via InitAndBitWidth), or the captured variable length array bound. /// /// If the storage kind is ISK_InClassCopyInit or /// ISK_InClassListInit, but the initializer is null, then this - /// field has an in-class initializer which has not yet been parsed + /// field has an in-class initializer that has not yet been parsed /// and attached. + // FIXME: Tail-allocate this to reduce the size of FieldDecl in the + // overwhelmingly common case that we have none of these things. llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage; + protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - Mutable(Mutable), CachedFieldIndex(0), - InitStorage(BW, (InitStorageKind) InitStyle) { - assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); + BitField(false), Mutable(Mutable), CachedFieldIndex(0), + InitStorage(nullptr, (InitStorageKind) InitStyle) { + if (BW) + setBitWidth(BW); } public: @@ -2388,10 +2462,7 @@ public: bool isMutable() const { return Mutable; } /// \brief Determines whether this field is a bitfield. - bool isBitField() const { - return InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() != nullptr; - } + bool isBitField() const { return BitField; } /// @brief Determines whether this is an unnamed bitfield. bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } @@ -2403,66 +2474,76 @@ public: bool isAnonymousStructOrUnion() const; Expr *getBitWidth() const { - return isBitField() - ? static_cast<Expr *>(InitStorage.getPointer()) - : nullptr; + if (!BitField) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (getInClassInitStyle()) + return static_cast<InitAndBitWidth*>(Ptr)->BitWidth; + return static_cast<Expr*>(Ptr); } unsigned getBitWidthValue(const ASTContext &Ctx) const; /// setBitWidth - Set the bit-field width for this member. // Note: used by some clients (i.e., do not remove it). void setBitWidth(Expr *Width) { - assert(InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); - InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); + assert(!hasCapturedVLAType() && !BitField && + "bit width or captured type already set"); + assert(Width && "no bit width specified"); + InitStorage.setPointer( + InitStorage.getInt() + ? new (getASTContext()) + InitAndBitWidth{getInClassInitializer(), Width} + : static_cast<void*>(Width)); + BitField = true; } /// removeBitWidth - Remove the bit-field width from this member. // Note: used by some clients (i.e., do not remove it). void removeBitWidth() { assert(isBitField() && "no bitfield width to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + InitStorage.setPointer(getInClassInitializer()); + BitField = false; } - /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which - /// this field has. + /// Get the kind of (C++11) default member initializer that this field has. InClassInitStyle getInClassInitStyle() const { InitStorageKind storageKind = InitStorage.getInt(); return (storageKind == ISK_CapturedVLAType ? ICIS_NoInit : (InClassInitStyle) storageKind); } - /// hasInClassInitializer - Determine whether this member has a C++11 in-class - /// initializer. + /// Determine whether this member has a C++11 default member initializer. bool hasInClassInitializer() const { return getInClassInitStyle() != ICIS_NoInit; } - /// getInClassInitializer - Get the C++11 in-class initializer for this - /// member, or null if one has not been set. If a valid declaration has an - /// in-class initializer, but this returns null, then we have not parsed and - /// attached it yet. + /// Get the C++11 default member initializer for this member, or null if one + /// has not been set. If a valid declaration has a default member initializer, + /// but this returns null, then we have not parsed and attached it yet. Expr *getInClassInitializer() const { - return hasInClassInitializer() - ? static_cast<Expr *>(InitStorage.getPointer()) - : nullptr; + if (!hasInClassInitializer()) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (BitField) + return static_cast<InitAndBitWidth*>(Ptr)->Init; + return static_cast<Expr*>(Ptr); } /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. void setInClassInitializer(Expr *Init) { - assert(hasInClassInitializer() && - InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); - InitStorage.setPointer(Init); + assert(hasInClassInitializer() && !getInClassInitializer()); + if (BitField) + static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init; + else + InitStorage.setPointer(Init); } /// removeInClassInitializer - Remove the C++11 in-class initializer from this /// member. void removeInClassInitializer() { assert(hasInClassInitializer() && "no initializer to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit); } /// \brief Determine whether this member captures the variable length array @@ -2481,7 +2562,7 @@ public: void setCapturedVLAType(const VariableArrayType *VLAType); /// getParent - Returns the parent of this field declaration, which - /// is the struct in which this method is defined. + /// is the struct in which this field is defined. const RecordDecl *getParent() const { return cast<RecordDecl>(getDeclContext()); } @@ -2641,12 +2722,17 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo; llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo; + // FIXME: This can be packed into the bitfields in Decl. + /// If 0, we have not computed IsTransparentTag. + /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1). + mutable unsigned CacheIsTransparentTag : 2; + protected: TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), - MaybeModedTInfo(TInfo) {} + MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {} typedef Redeclarable<TypedefNameDecl> redeclarable_base; TypedefNameDecl *getNextRedeclarationImpl() override { @@ -2699,11 +2785,22 @@ public: /// this typedef declaration. TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const; + /// Determines if this typedef shares a name and spelling location with its + /// underlying tag type, as is the case with the NS_ENUM macro. + bool isTransparentTag() const { + if (CacheIsTransparentTag) + return CacheIsTransparentTag & 0x2; + return isTransparentTagSlow(); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstTypedefName && K <= lastTypedefName; } + +private: + bool isTransparentTagSlow() const; }; /// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef' @@ -3235,6 +3332,18 @@ public: return isCompleteDefinition() || isFixed(); } + /// Returns true if this enum is either annotated with + /// enum_extensibility(closed) or isn't annotated with enum_extensibility. + bool isClosed() const; + + /// Returns true if this enum is annotated with flag_enum and isn't annotated + /// with enum_extensibility(open). + bool isClosedFlag() const; + + /// Returns true if this enum is annotated with neither flag_enum nor + /// enum_extensibility(open). + bool isClosedNonFlag() const; + /// \brief Retrieve the enum definition from which this enumeration could /// be instantiated, if it is an instantiation (rather than a non-template). EnumDecl *getTemplateInstantiationPattern() const; @@ -3431,7 +3540,7 @@ public: return K >= firstRecord && K <= lastRecord; } - /// isMsStrust - Get whether or not this is an ms_struct which can + /// \brief Get whether or not this is an ms_struct which can /// be turned on with an attribute, pragma, or -mms-bitfields /// commandline option. bool isMsStruct(const ASTContext &C) const; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index c88cb6a8fd..47515a848a 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -34,6 +34,7 @@ class DeclarationName; class DependentDiagnostic; class EnumDecl; class ExportDecl; +class ExternalSourceSymbolAttr; class FunctionDecl; class FunctionType; enum Linkage : unsigned char; @@ -201,26 +202,33 @@ public: OBJC_TQ_CSNullability = 0x40 }; -protected: - // Enumeration values used in the bits stored in NextInContextAndBits. - enum { - /// \brief Whether this declaration is a top-level declaration (function, - /// global variable, etc.) that is lexically inside an objc container - /// definition. - TopLevelDeclInObjCContainerFlag = 0x01, - - /// \brief Whether this declaration is private to the module in which it was - /// defined. - ModulePrivateFlag = 0x02 + /// The kind of ownership a declaration has, for visibility purposes. + /// This enumeration is designed such that higher values represent higher + /// levels of name hiding. + enum class ModuleOwnershipKind : unsigned { + /// This declaration is not owned by a module. + Unowned, + /// This declaration has an owning module, but is globally visible + /// (typically because its owning module is visible and we know that + /// modules cannot later become hidden in this compilation). + /// After serialization and deserialization, this will be converted + /// to VisibleWhenImported. + Visible, + /// This declaration has an owning module, and is visible when that + /// module is imported. + VisibleWhenImported, + /// This declaration has an owning module, but is only visible to + /// lookups that occur within that module. + ModulePrivate }; - + +protected: /// \brief The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// - /// The extra two bits are used for the TopLevelDeclInObjCContainer and - /// ModulePrivate bits. - llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits; + /// The extra two bits are used for the ModuleOwnershipKind. + llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits; private: friend class DeclContext; @@ -281,6 +289,11 @@ private: /// are regarded as "referenced" but not "used". unsigned Referenced : 1; + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + unsigned TopLevelDeclInObjCContainer : 1; + /// \brief Whether statistic collection is enabled. static bool StatisticsEnabled; @@ -293,11 +306,6 @@ protected: /// \brief Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; - /// \brief Whether this declaration is hidden from normal name lookup, e.g., - /// because it is was loaded from an AST file is either module-private or - /// because its submodule has not been made visible. - unsigned Hidden : 1; - /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 13; @@ -331,26 +339,38 @@ protected: private: bool AccessDeclContextSanity() const; -protected: + /// Get the module ownership kind to use for a local lexical child of \p DC, + /// which may be either a local or (rarely) an imported declaration. + static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) { + if (DC) { + auto *D = cast<Decl>(DC); + auto MOK = D->getModuleOwnershipKind(); + if (MOK != ModuleOwnershipKind::Unowned && + (!D->isFromASTFile() || D->hasLocalOwningModuleStorage())) + return MOK; + // If D is not local and we have no local module storage, then we don't + // need to track module ownership at all. + } + return ModuleOwnershipKind::Unowned; + } +protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) - : NextInContextAndBits(), DeclCtx(DC), - Loc(L), DeclKind(DK), InvalidDecl(0), - HasAttrs(false), Implicit(false), Used(false), Referenced(false), - Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndLinkage(0) - { + : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)), + DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), + Implicit(false), Used(false), Referenced(false), + TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } Decl(Kind DK, EmptyShell Empty) - : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), - HasAttrs(false), Implicit(false), Used(false), Referenced(false), - Access(AS_none), FromASTFile(0), Hidden(0), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndLinkage(0) - { + : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false), + Implicit(false), Used(false), Referenced(false), + TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } @@ -550,22 +570,21 @@ public: /// global variable, etc.) that is lexically inside an objc container /// definition. bool isTopLevelDeclInObjCContainer() const { - return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag; + return TopLevelDeclInObjCContainer; } void setTopLevelDeclInObjCContainer(bool V = true) { - unsigned Bits = NextInContextAndBits.getInt(); - if (V) - Bits |= TopLevelDeclInObjCContainerFlag; - else - Bits &= ~TopLevelDeclInObjCContainerFlag; - NextInContextAndBits.setInt(Bits); + TopLevelDeclInObjCContainer = V; } + /// \brief Looks on this and related declarations for an applicable + /// external source symbol attribute. + ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const; + /// \brief Whether this declaration was marked as being private to the /// module in which it was defined. bool isModulePrivate() const { - return NextInContextAndBits.getInt() & ModulePrivateFlag; + return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } /// \brief Whether this declaration is exported (by virtue of being lexically @@ -580,15 +599,14 @@ public: const Attr *getDefiningAttr() const; protected: - /// \brief Specify whether this declaration was marked as being private + /// \brief Specify that this declaration was marked as being private /// to the module in which it was defined. - void setModulePrivate(bool MP = true) { - unsigned Bits = NextInContextAndBits.getInt(); - if (MP) - Bits |= ModulePrivateFlag; - else - Bits &= ~ModulePrivateFlag; - NextInContextAndBits.setInt(Bits); + void setModulePrivate() { + // The module-private specifier has no effect on unowned declarations. + // FIXME: We should track this in some way for source fidelity. + if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned) + return; + setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } /// \brief Set the owning module ID. @@ -616,6 +634,14 @@ public: getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple()) const; + /// \brief Retrieve the version of the target platform in which this + /// declaration was introduced. + /// + /// \returns An empty version tuple if this declaration has no 'introduced' + /// availability attributes, or the version tuple that's specified in the + /// attribute otherwise. + VersionTuple getVersionIntroduced() const; + /// \brief Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, @@ -679,7 +705,7 @@ public: /// \brief Get the imported owning module, if this decl is from an imported /// (non-local) module. Module *getImportedOwningModule() const { - if (!isFromASTFile()) + if (!isFromASTFile() || !hasOwningModule()) return nullptr; return getOwningModuleSlow(); @@ -688,16 +714,66 @@ public: /// \brief Get the local owning module, if known. Returns nullptr if owner is /// not yet known or declaration is not from a module. Module *getLocalOwningModule() const { - if (isFromASTFile() || !Hidden) + if (isFromASTFile() || !hasOwningModule()) return nullptr; + + assert(hasLocalOwningModuleStorage() && + "owned local decl but no local module storage"); return reinterpret_cast<Module *const *>(this)[-1]; } void setLocalOwningModule(Module *M) { - assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() && + assert(!isFromASTFile() && hasOwningModule() && + hasLocalOwningModuleStorage() && "should not have a cached owning module"); reinterpret_cast<Module **>(this)[-1] = M; } + /// Is this declaration owned by some module? + bool hasOwningModule() const { + return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; + } + + /// Get the module that owns this declaration (for visibility purposes). + Module *getOwningModule() const { + return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); + } + + /// Get the module that owns this declaration for linkage purposes. + /// There only ever is such a module under the C++ Modules TS. + /// + /// \param IgnoreLinkage Ignore the linkage of the entity; assume that + /// all declarations in a global module fragment are unowned. + Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; + + /// \brief Determine whether this declaration might be hidden from name + /// lookup. Note that the declaration might be visible even if this returns + /// \c false, if the owning module is visible within the query context. + // FIXME: Rename this to make it clearer what it does. + bool isHidden() const { + return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible; + } + + /// Set that this declaration is globally visible, even if it came from a + /// module that is not visible. + void setVisibleDespiteOwningModule() { + if (isHidden()) + setModuleOwnershipKind(ModuleOwnershipKind::Visible); + } + + /// \brief Get the kind of module ownership for this declaration. + ModuleOwnershipKind getModuleOwnershipKind() const { + return NextInContextAndBits.getInt(); + } + + /// \brief Set whether this declaration is hidden from name lookup. + void setModuleOwnershipKind(ModuleOwnershipKind MOK) { + assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned && + MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() && + !hasLocalOwningModuleStorage()) && + "no storage available for owning module for this declaration"); + NextInContextAndBits.setInt(MOK); + } + unsigned getIdentifierNamespace() const { return IdentifierNamespace; } @@ -933,13 +1009,15 @@ public: /// declaration, but in the semantic context of the enclosing namespace /// scope. void setLocalExternDecl() { - assert((IdentifierNamespace == IDNS_Ordinary || - IdentifierNamespace == IDNS_OrdinaryFriend) && - "namespace is not ordinary"); - Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~IDNS_Ordinary; + // It's OK for the declaration to still have the "invisible friend" flag or + // the "conflicts with tag declarations in this scope" flag for the outer + // scope. + assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 && + "namespace is not ordinary"); + IdentifierNamespace |= IDNS_LocalExtern; if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) IdentifierNamespace |= IDNS_Ordinary; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index d663dbeea8..d9b8ac274d 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -73,8 +73,7 @@ public: namespace llvm { // Provide PointerLikeTypeTraits for non-cvr pointers. template<> - class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { - public: + struct PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) { return F.get(); } @@ -375,6 +374,7 @@ class CXXRecordDecl : public RecordDecl { /// \brief These flags are \c true if a defaulted corresponding special /// member can't be fully analyzed without performing overload resolution. /// @{ + unsigned NeedOverloadResolutionForCopyConstructor : 1; unsigned NeedOverloadResolutionForMoveConstructor : 1; unsigned NeedOverloadResolutionForMoveAssignment : 1; unsigned NeedOverloadResolutionForDestructor : 1; @@ -383,6 +383,7 @@ class CXXRecordDecl : public RecordDecl { /// \brief These flags are \c true if an implicit defaulted corresponding /// special member would be defined as deleted. /// @{ + unsigned DefaultedCopyConstructorIsDeleted : 1; unsigned DefaultedMoveConstructorIsDeleted : 1; unsigned DefaultedMoveAssignmentIsDeleted : 1; unsigned DefaultedDestructorIsDeleted : 1; @@ -415,6 +416,12 @@ class CXXRecordDecl : public RecordDecl { /// constructor. unsigned HasDefaultedDefaultConstructor : 1; + /// \brief True if this class can be passed in a non-address-preserving + /// fashion (such as in registers) according to the C++ language rules. + /// This does not imply anything about how the ABI in use will actually + /// pass an object of this class. + unsigned CanPassInRegisters : 1; + /// \brief True if a defaulted default constructor for this class would /// be constexpr. unsigned DefaultedDefaultConstructorIsConstexpr : 1; @@ -464,6 +471,8 @@ class CXXRecordDecl : public RecordDecl { /// \brief Whether we are currently parsing base specifiers. unsigned IsParsingBaseSpecifiers : 1; + unsigned HasODRHash : 1; + /// \brief A hash of parts of the class to help in ODR checking. unsigned ODRHash; @@ -712,8 +721,7 @@ public: return data().IsParsingBaseSpecifiers; } - void computeODRHash(); - unsigned getODRHash() const { return data().ODRHash; } + unsigned getODRHash() const; /// \brief Sets the base classes of this struct or class. void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); @@ -810,18 +818,53 @@ public: return data().FirstFriend.isValid(); } + /// \brief \c true if a defaulted copy constructor for this class would be + /// deleted. + bool defaultedCopyConstructorIsDeleted() const { + assert((!needsOverloadResolutionForCopyConstructor() || + (data().DeclaredSpecialMembers & SMF_CopyConstructor)) && + "this property has not yet been computed by Sema"); + return data().DefaultedCopyConstructorIsDeleted; + } + + /// \brief \c true if a defaulted move constructor for this class would be + /// deleted. + bool defaultedMoveConstructorIsDeleted() const { + assert((!needsOverloadResolutionForMoveConstructor() || + (data().DeclaredSpecialMembers & SMF_MoveConstructor)) && + "this property has not yet been computed by Sema"); + return data().DefaultedMoveConstructorIsDeleted; + } + + /// \brief \c true if a defaulted destructor for this class would be deleted. + bool defaultedDestructorIsDeleted() const { + assert((!needsOverloadResolutionForDestructor() || + (data().DeclaredSpecialMembers & SMF_Destructor)) && + "this property has not yet been computed by Sema"); + return data().DefaultedDestructorIsDeleted; + } + + /// \brief \c true if we know for sure that this class has a single, + /// accessible, unambiguous copy constructor that is not deleted. + bool hasSimpleCopyConstructor() const { + return !hasUserDeclaredCopyConstructor() && + !data().DefaultedCopyConstructorIsDeleted; + } + /// \brief \c true if we know for sure that this class has a single, /// accessible, unambiguous move constructor that is not deleted. bool hasSimpleMoveConstructor() const { return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() && !data().DefaultedMoveConstructorIsDeleted; } + /// \brief \c true if we know for sure that this class has a single, /// accessible, unambiguous move assignment operator that is not deleted. bool hasSimpleMoveAssignment() const { return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() && !data().DefaultedMoveAssignmentIsDeleted; } + /// \brief \c true if we know for sure that this class has an accessible /// destructor that is not deleted. bool hasSimpleDestructor() const { @@ -877,7 +920,16 @@ public: /// \brief Determine whether we need to eagerly declare a defaulted copy /// constructor for this class. bool needsOverloadResolutionForCopyConstructor() const { - return data().HasMutableFields; + // C++17 [class.copy.ctor]p6: + // If the class definition declares a move constructor or move assignment + // operator, the implicitly declared copy constructor is defined as + // deleted. + // In MSVC mode, sometimes a declared move assignment does not delete an + // implicit copy constructor, so defer this choice to Sema. + if (data().UserDeclaredSpecialMembers & + (SMF_MoveConstructor | SMF_MoveAssignment)) + return true; + return data().NeedOverloadResolutionForCopyConstructor; } /// \brief Determine whether an implicit copy constructor for this type @@ -918,7 +970,16 @@ public: needsImplicitMoveConstructor(); } - /// \brief Set that we attempted to declare an implicitly move + /// \brief Set that we attempted to declare an implicit copy + /// constructor, but overload resolution failed so we deleted it. + void setImplicitCopyConstructorIsDeleted() { + assert((data().DefaultedCopyConstructorIsDeleted || + needsOverloadResolutionForCopyConstructor()) && + "Copy constructor should not be deleted"); + data().DefaultedCopyConstructorIsDeleted = true; + } + + /// \brief Set that we attempted to declare an implicit move /// constructor, but overload resolution failed so we deleted it. void setImplicitMoveConstructorIsDeleted() { assert((data().DefaultedMoveConstructorIsDeleted || @@ -927,6 +988,15 @@ public: data().DefaultedMoveConstructorIsDeleted = true; } + /// \brief Set that we attempted to declare an implicit destructor, + /// but overload resolution failed so we deleted it. + void setImplicitDestructorIsDeleted() { + assert((data().DefaultedDestructorIsDeleted || + needsOverloadResolutionForDestructor()) && + "destructor should not be deleted"); + data().DefaultedDestructorIsDeleted = true; + } + /// \brief Determine whether this class should get an implicit move /// constructor or if any existing special member function inhibits this. bool needsImplicitMoveConstructor() const { @@ -1315,6 +1385,18 @@ public: return data().HasIrrelevantDestructor; } + /// \brief Determine whether this class has at least one trivial, non-deleted + /// copy or move constructor. + bool canPassInRegisters() const { + return data().CanPassInRegisters; + } + + /// \brief Set that we can pass this RecordDecl in registers. + // FIXME: This should be set as part of completeDefinition. + void setCanPassInRegisters(bool CanPass) { + data().CanPassInRegisters = CanPass; + } + /// \brief Determine whether this class has a non-literal or/ volatile type /// non-static data member or base class. bool hasNonLiteralTypeFieldsOrBases() const { @@ -1562,10 +1644,13 @@ public: /// \param Paths used to record the paths from this class to its base class /// subobjects that match the search criteria. /// + /// \param LookupInDependent can be set to true to extend the search to + /// dependent base classes. + /// /// \returns true if there exists any path from this class to a base class /// subobject that matches the search criteria. - bool lookupInBases(BaseMatchesCallback BaseMatches, - CXXBasePaths &Paths) const; + bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, + bool LookupInDependent = false) const; /// \brief Base-class lookup callback that determines whether the given /// base class specifier refers to a specific class declaration. @@ -1607,6 +1692,16 @@ public: CXXBasePath &Path, DeclarationName Name); /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name. + /// + /// This callback can be used with \c lookupInBases() to find members + /// of the given name within a C++ class hierarchy, including dependent + /// classes. + static bool + FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, DeclarationName Name); + + /// \brief Base-class lookup callback that determines whether there exists /// an OpenMP declare reduction member with the given name. /// /// This callback can be used with \c lookupInBases() to find members @@ -1632,6 +1727,14 @@ public: /// \brief Get the indirect primary bases for this class. void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const; + /// Performs an imprecise lookup of a dependent name in this class. + /// + /// This function does not follow strict semantic rules and should be used + /// only when lookup rules can be relaxed, e.g. indexing. + std::vector<const NamedDecl *> + lookupDependentName(const DeclarationName &Name, + llvm::function_ref<bool(const NamedDecl *ND)> Filter); + /// Renders and displays an inheritance diagram /// for this C++ class and all of its base classes (transitively) using /// GraphViz. @@ -1740,6 +1843,10 @@ public: return getLambdaData().MethodTyInfo; } + // \brief Determine whether this type is an Interface Like type for + // __interface inheritence purposes. + bool isInterfaceLike() const; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstCXXRecord && K <= lastCXXRecord; @@ -1774,6 +1881,10 @@ private: if (EndLocation.isValid()) setRangeEnd(EndLocation); IsExplicitSpecified = IsExplicit; + + // IsCopyDeductionCandidate is a union variant member, so ensure it is the + // active member by storing to it. + IsCopyDeductionCandidate = false; } public: @@ -1796,6 +1907,12 @@ public: return getDeclName().getCXXDeductionGuideTemplate(); } + void setIsCopyDeductionCandidate() { + IsCopyDeductionCandidate = true; + } + + bool isCopyDeductionCandidate() const { return IsCopyDeductionCandidate; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXDeductionGuide; } @@ -1864,6 +1981,19 @@ public: return (CD->begin_overridden_methods() != CD->end_overridden_methods()); } + /// If it's possible to devirtualize a call to this method, return the called + /// function. Otherwise, return null. + + /// \param Base The object on which this virtual function is called. + /// \param IsAppleKext True if we are compiling for Apple kext. + CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext); + + const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, + bool IsAppleKext) const { + return const_cast<CXXMethodDecl *>(this)->getDevirtualizedMethod( + Base, IsAppleKext); + } + /// \brief Determine whether this is a usual deallocation function /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded /// delete or delete[] operator with a particular signature. @@ -1923,7 +2053,10 @@ public: /// \brief Returns the type of the \c this pointer. /// - /// Should only be called for instance (i.e., non-static) methods. + /// Should only be called for instance (i.e., non-static) methods. Note + /// that for the call operator of a lambda closure type, this returns the + /// desugared 'this' type (a pointer to the closure type), not the captured + /// 'this' type. QualType getThisType(ASTContext &C) const; unsigned getTypeQualifiers() const { @@ -2443,7 +2576,10 @@ public: class CXXDestructorDecl : public CXXMethodDecl { void anchor() override; + // FIXME: Don't allocate storage for these except in the first declaration + // of a virtual destructor. FunctionDecl *OperatorDelete; + Expr *OperatorDeleteThisArg; CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, @@ -2451,7 +2587,7 @@ class CXXDestructorDecl : public CXXMethodDecl { bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, SC_None, isInline, /*isConstexpr=*/false, SourceLocation()), - OperatorDelete(nullptr) { + OperatorDelete(nullptr), OperatorDeleteThisArg(nullptr) { setImplicit(isImplicitlyDeclared); } @@ -2464,10 +2600,13 @@ public: bool isImplicitlyDeclared); static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); - void setOperatorDelete(FunctionDecl *OD); + void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg); const FunctionDecl *getOperatorDelete() const { return getCanonicalDecl()->OperatorDelete; } + Expr *getOperatorDeleteThisArg() const { + return getCanonicalDecl()->OperatorDeleteThisArg; + } CXXDestructorDecl *getCanonicalDecl() override { return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl()); diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index ff37758c25..eb86526e8e 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -131,7 +131,7 @@ public: } else { DeclsTy &Vec = *getAsVector(); Vec.erase(std::remove_if(Vec.begin(), Vec.end(), - std::mem_fun(&Decl::isFromASTFile)), + [](Decl *D) { return D->isFromASTFile(); }), Vec.end()); // Don't have any external decls any more. Data = DeclsAndHasExternalTy(&Vec, false); diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 6353b26f7b..628d7886aa 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -138,10 +138,9 @@ public: namespace llvm { // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits. template <typename T> - class PointerLikeTypeTraits; + struct PointerLikeTypeTraits; template <> - class PointerLikeTypeTraits<clang::DeclGroupRef> { - public: + struct PointerLikeTypeTraits<clang::DeclGroupRef> { static inline void *getAsVoidPointer(clang::DeclGroupRef P) { return P.getAsOpaquePtr(); } diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index a445042aec..1cd6e004f7 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -381,15 +381,17 @@ public: ArrayRef<SourceLocation> SelLocs = llvm::None); // Iterator access to parameter types. - typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun; - typedef llvm::mapped_iterator<param_const_iterator, deref_fun> - param_type_iterator; + struct GetTypeFn { + QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); } + }; + typedef llvm::mapped_iterator<param_const_iterator, GetTypeFn> + param_type_iterator; param_type_iterator param_type_begin() const { - return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(param_begin(), GetTypeFn()); } param_type_iterator param_type_end() const { - return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(param_end(), GetTypeFn()); } /// createImplicitParams - Used to lazily create the self and cmd @@ -743,6 +745,8 @@ private: Selector GetterName; // getter name of NULL if no getter Selector SetterName; // setter name of NULL if no setter + SourceLocation GetterNameLoc; // location of the getter attribute's value + SourceLocation SetterNameLoc; // location of the setter attribute's value ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method @@ -855,10 +859,18 @@ public: } Selector getGetterName() const { return GetterName; } - void setGetterName(Selector Sel) { GetterName = Sel; } + SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) { + GetterName = Sel; + GetterNameLoc = Loc; + } Selector getSetterName() const { return SetterName; } - void setSetterName(Selector Sel) { SetterName = Sel; } + SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) { + SetterName = Sel; + SetterNameLoc = Loc; + } ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } @@ -1027,10 +1039,9 @@ public: typedef llvm::DenseMap<std::pair<IdentifierInfo*, unsigned/*isClassProperty*/>, ObjCPropertyDecl*> PropertyMap; - - typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*> - ProtocolPropertyMap; - + + typedef llvm::SmallDenseSet<const ObjCProtocolDecl *, 8> ProtocolPropertySet; + typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder; /// This routine collects list of properties to be implemented in the class. @@ -2147,7 +2158,8 @@ public: PropertyDeclOrder &PO) const override; void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property, - ProtocolPropertyMap &PM) const; + ProtocolPropertySet &PS, + PropertyDeclOrder &PO) const; static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCProtocol; } diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h index 30ca79e9d0..2a329c3732 100644 --- a/include/clang/AST/DeclOpenMP.h +++ b/include/clang/AST/DeclOpenMP.h @@ -100,12 +100,22 @@ public: /// /// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer. class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext { +public: + enum InitKind { + CallInit, // Initialized by function call. + DirectInit, // omp_priv(<expr>) + CopyInit // omp_priv = <expr> + }; + private: friend class ASTDeclReader; /// \brief Combiner for declare reduction construct. Expr *Combiner; /// \brief Initializer for declare reduction construct. Expr *Initializer; + /// Kind of initializer - function call or omp_priv<init_expr> initializtion. + InitKind InitializerKind = CallInit; + /// \brief Reference to the previous declare reduction construct in the same /// scope with the same name. Required for proper templates instantiation if /// the declare reduction construct is declared inside compound statement. @@ -117,7 +127,8 @@ private: DeclarationName Name, QualType Ty, OMPDeclareReductionDecl *PrevDeclInScope) : ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), Combiner(nullptr), - Initializer(nullptr), PrevDeclInScope(PrevDeclInScope) {} + Initializer(nullptr), InitializerKind(CallInit), + PrevDeclInScope(PrevDeclInScope) {} void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) { PrevDeclInScope = Prev; @@ -142,8 +153,13 @@ public: /// construct. Expr *getInitializer() { return Initializer; } const Expr *getInitializer() const { return Initializer; } + /// Get initializer kind. + InitKind getInitializerKind() const { return InitializerKind; } /// \brief Set initializer expression for the declare reduction construct. - void setInitializer(Expr *E) { Initializer = E; } + void setInitializer(Expr *E, InitKind IK) { + Initializer = E; + InitializerKind = IK; + } /// \brief Get reference to previous declare reduction construct in the same /// scope with the same name. diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index a7ca03ff9e..bef2339e8e 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SyncScope.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" @@ -274,6 +275,7 @@ public: MLV_LValueCast, // Specialized form of MLV_InvalidExpression. MLV_IncompleteType, MLV_ConstQualified, + MLV_ConstQualifiedField, MLV_ConstAddrSpace, MLV_ArrayType, MLV_NoSetterProperty, @@ -323,6 +325,7 @@ public: CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext CM_NoSetterProperty,// Implicit assignment to ObjC property without setter CM_ConstQualified, + CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, CM_IncompleteType @@ -908,6 +911,10 @@ public: return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + /// The source expression of an opaque value expression is the /// expression which originally generated the value. This is /// provided as a convenience for analyses that don't wish to @@ -1168,6 +1175,10 @@ public: return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + friend TrailingObjects; friend class ASTStmtReader; friend class ASTStmtWriter; @@ -1223,6 +1234,9 @@ public: // Iterators child_range children() { return child_range(&FnName, &FnName + 1); } + const_child_range children() const { + return const_child_range(&FnName, &FnName + 1); + } friend class ASTStmtReader; }; @@ -1316,6 +1330,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; class CharacterLiteral : public Expr { @@ -1366,6 +1383,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; class FloatingLiteral : public Expr, private APFloatStorage { @@ -1430,6 +1450,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; /// ImaginaryLiteral - We support imaginary integer and floating point literals, @@ -1462,6 +1485,9 @@ public: // Iterators child_range children() { return child_range(&Val, &Val+1); } + const_child_range children() const { + return const_child_range(&Val, &Val + 1); + } }; /// StringLiteral - This represents a string literal expression, e.g. "foo" @@ -1629,6 +1655,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This @@ -1670,6 +1699,9 @@ public: // Iterators child_range children() { return child_range(&Val, &Val+1); } + const_child_range children() const { + return const_child_range(&Val, &Val + 1); + } }; /// UnaryOperator - This represents the unary-expression's (except sizeof and @@ -1779,6 +1811,9 @@ public: // Iterators child_range children() { return child_range(&Val, &Val+1); } + const_child_range children() const { + return const_child_range(&Val, &Val + 1); + } }; /// Helper class for OffsetOfExpr. @@ -1982,6 +2017,11 @@ public: Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>()); return child_range(begin, begin + NumExprs); } + const_child_range children() const { + Stmt *const *begin = + reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>()); + return const_child_range(begin, begin + NumExprs); + } friend TrailingObjects; }; @@ -2070,6 +2110,7 @@ public: // Iterators child_range children(); + const_child_range children() const; }; //===----------------------------------------------------------------------===// @@ -2154,6 +2195,9 @@ public: child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } }; /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). @@ -2304,6 +2348,12 @@ public: SourceLocation getLocStart() const LLVM_READONLY; SourceLocation getLocEnd() const LLVM_READONLY; + bool isCallToStdMove() const { + const FunctionDecl* FD = getDirectCallee(); + return getNumArgs() == 1 && FD && FD->isInStdNamespace() && + FD->getIdentifier() && FD->getIdentifier()->isStr("move"); + } + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && T->getStmtClass() <= lastCallExprConstant; @@ -2314,6 +2364,11 @@ public: return child_range(&SubExprs[0], &SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START); } + + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs + + getNumPreArgs() + PREARGS_START); + } }; /// Extra data stored in some MemberExpr objects. @@ -2568,6 +2623,9 @@ public: // Iterators child_range children() { return child_range(&Base, &Base+1); } + const_child_range children() const { + return const_child_range(&Base, &Base + 1); + } friend TrailingObjects; friend class ASTReader; @@ -2640,6 +2698,9 @@ public: // Iterators child_range children() { return child_range(&Init, &Init+1); } + const_child_range children() const { + return const_child_range(&Init, &Init + 1); + } }; /// CastExpr - Base class for type casts, including both implicit @@ -2719,6 +2780,16 @@ public: path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_end() const { return path_buffer() + path_size(); } + const FieldDecl *getTargetUnionField() const { + assert(getCastKind() == CK_ToUnion); + return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType()); + } + + static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, + QualType opType); + static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, + QualType opType); + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCastExprConstant && T->getStmtClass() <= lastCastExprConstant; @@ -2726,6 +2797,7 @@ public: // Iterators child_range children() { return child_range(&Op, &Op+1); } + const_child_range children() const { return const_child_range(&Op, &Op + 1); } }; /// ImplicitCastExpr - Allows us to explicitly represent implicit type @@ -2918,11 +2990,9 @@ public: private: unsigned Opc : 6; - // Records the FP_CONTRACT pragma status at the point that this binary - // operator was parsed. This bit is only meaningful for operations on - // floating point types. For all other types it should default to - // false. - unsigned FPContractable : 1; + // This is only meaningful for operations on floating point types and 0 + // otherwise. + unsigned FPFeatures : 2; SourceLocation OpLoc; enum { LHS, RHS, END_EXPR }; @@ -2931,7 +3001,7 @@ public: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, - SourceLocation opLoc, bool fpContractable) + SourceLocation opLoc, FPOptions FPFeatures) : Expr(BinaryOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), @@ -2939,7 +3009,7 @@ public: rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), - Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) { + Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; assert(!isCompoundAssignmentOp() && @@ -3062,6 +3132,12 @@ public: return isShiftAssignOp(getOpcode()); } + // Return true if a binary operator using the specified opcode and operands + // would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized + // integer to a pointer. + static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, + Expr *LHS, Expr *RHS); + static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && S->getStmtClass() <= lastBinaryOperatorConstant; @@ -3071,19 +3147,26 @@ public: child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. - void setFPContractable(bool FPC) { FPContractable = FPC; } + void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); } + + FPOptions getFPFeatures() const { return FPOptions(FPFeatures); } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. - bool isFPContractable() const { return FPContractable; } + bool isFPContractableWithinStatement() const { + return FPOptions(FPFeatures).allowFPContractWithinStatement(); + } protected: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, - SourceLocation opLoc, bool fpContractable, bool dead2) + SourceLocation opLoc, FPOptions FPFeatures, bool dead2) : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), @@ -3091,7 +3174,7 @@ protected: rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), - Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) { + Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } @@ -3113,8 +3196,8 @@ public: CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, ExprValueKind VK, ExprObjectKind OK, QualType CompLHSType, QualType CompResultType, - SourceLocation OpLoc, bool fpContractable) - : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable, + SourceLocation OpLoc, FPOptions FPFeatures) + : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { @@ -3247,6 +3330,9 @@ public: child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } }; /// BinaryConditionalOperator - The GNU extension to the conditional @@ -3332,6 +3418,9 @@ public: child_range children() { return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); } + const_child_range children() const { + return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS); + } }; inline Expr *AbstractConditionalOperator::getCond() const { @@ -3386,6 +3475,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; /// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). @@ -3428,6 +3520,9 @@ public: // Iterators child_range children() { return child_range(&SubStmt, &SubStmt+1); } + const_child_range children() const { + return const_child_range(&SubStmt, &SubStmt + 1); + } }; /// ShuffleVectorExpr - clang-specific builtin-in function @@ -3496,6 +3591,9 @@ public: child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs); + } }; /// ConvertVectorExpr - Clang builtin function __builtin_convertvector @@ -3550,6 +3648,9 @@ public: // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } + const_child_range children() const { + return const_child_range(&SrcExpr, &SrcExpr + 1); + } }; /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. @@ -3630,6 +3731,9 @@ public: child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } + const_child_range children() const { + return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); + } }; /// GNUNullExpr - Implements the GNU __null extension, which is a name @@ -3666,6 +3770,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; /// Represents a call to the builtin function \c __builtin_va_arg. @@ -3713,6 +3820,9 @@ public: // Iterators child_range children() { return child_range(&Val, &Val+1); } + const_child_range children() const { + return const_child_range(&Val, &Val + 1); + } }; /// @brief Describes an C or C++ initializer list. @@ -3901,6 +4011,10 @@ public: /// initializer)? bool isTransparent() const; + /// Is this the zero initializer {0} in a language which considers it + /// idiomatic? + bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const; + SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } @@ -3910,6 +4024,9 @@ public: InitListExpr *getSemanticForm() const { return isSemanticForm() ? nullptr : AltForm.getPointer(); } + bool isSyntacticForm() const { + return !AltForm.getInt() || !AltForm.getPointer(); + } InitListExpr *getSyntacticForm() const { return isSemanticForm() ? AltForm.getPointer() : nullptr; } @@ -3937,10 +4054,16 @@ public: // Iterators child_range children() { + const_child_range CCR = const_cast<const InitListExpr *>(this)->children(); + return child_range(cast_away_const(CCR.begin()), + cast_away_const(CCR.end())); + } + + const_child_range children() const { // FIXME: This does not include the array filler expression. if (InitExprs.empty()) - return child_range(child_iterator(), child_iterator()); - return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); + return const_child_range(const_child_iterator(), const_child_iterator()); + return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); } typedef InitExprsTy::iterator iterator; @@ -4193,6 +4316,9 @@ public: } Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; } + const Designator *getDesignator(unsigned Idx) const { + return &designators()[Idx]; + } void setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs); @@ -4255,6 +4381,10 @@ public: Stmt **begin = getTrailingObjects<Stmt *>(); return child_range(begin, begin + NumSubExprs); } + const_child_range children() const { + Stmt * const *begin = getTrailingObjects<Stmt *>(); + return const_child_range(begin, begin + NumSubExprs); + } friend TrailingObjects; }; @@ -4288,6 +4418,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; // In cases like: @@ -4333,6 +4466,10 @@ public: child_range children() { return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); } + const_child_range children() const { + return const_child_range(&BaseAndUpdaterExprs[0], + &BaseAndUpdaterExprs[0] + 2); + } }; /// \brief Represents a loop initializing the elements of an array. @@ -4394,6 +4531,9 @@ public: child_range children() { return child_range(SubExprs, SubExprs + 2); } + const_child_range children() const { + return const_child_range(SubExprs, SubExprs + 2); + } friend class ASTReader; friend class ASTStmtReader; @@ -4422,6 +4562,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } friend class ASTReader; friend class ASTStmtReader; @@ -4456,6 +4599,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; class ParenListExpr : public Expr { @@ -4502,6 +4648,9 @@ public: child_range children() { return child_range(&Exprs[0], &Exprs[0]+NumExprs); } + const_child_range children() const { + return const_child_range(&Exprs[0], &Exprs[0] + NumExprs); + } friend class ASTStmtReader; friend class ASTStmtWriter; @@ -4622,7 +4771,9 @@ public: child_range children() { return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs); } - + const_child_range children() const { + return const_child_range(SubExprs, SubExprs + END_EXPR + NumAssocs); + } friend class ASTStmtReader; }; @@ -4691,6 +4842,9 @@ public: // Iterators child_range children() { return child_range(&Base, &Base+1); } + const_child_range children() const { + return const_child_range(&Base, &Base + 1); + } }; /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. @@ -4732,6 +4886,9 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } }; /// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] @@ -4777,6 +4934,9 @@ public: // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } + const_child_range children() const { + return const_child_range(&SrcExpr, &SrcExpr + 1); + } }; /// PseudoObjectExpr - An expression which accesses a pseudo-object @@ -4915,8 +5075,15 @@ public: } child_range children() { - Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer()); - return child_range(cs, cs + getNumSubExprs()); + const_child_range CCR = + const_cast<const PseudoObjectExpr *>(this)->children(); + return child_range(cast_away_const(CCR.begin()), + cast_away_const(CCR.end())); + } + const_child_range children() const { + Stmt *const *cs = const_cast<Stmt *const *>( + reinterpret_cast<const Stmt *const *>(getSubExprsBuffer())); + return const_child_range(cs, cs + getNumSubExprs()); } static bool classof(const Stmt *T) { @@ -4929,9 +5096,11 @@ public: /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the -/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>. -/// All of these instructions take one primary pointer and at least one memory -/// order. +/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>, +/// and corresponding __opencl_atomic_* for OpenCL 2.0. +/// All of these instructions take one primary pointer, at least one memory +/// order. The instructions for which getScopeModel returns non-null value +/// take one synch scope. class AtomicExpr : public Expr { public: enum AtomicOp { @@ -4943,14 +5112,16 @@ public: }; private: + /// \brief Location of sub-expressions. + /// The location of Scope sub-expression is NumSubExprs - 1, which is + /// not fixed, therefore is not defined in enum. enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; - Stmt* SubExprs[END_EXPR]; + Stmt *SubExprs[END_EXPR + 1]; unsigned NumSubExprs; SourceLocation BuiltinLoc, RParenLoc; AtomicOp Op; friend class ASTStmtReader; - public: AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t, AtomicOp op, SourceLocation RP); @@ -4968,8 +5139,12 @@ public: Expr *getOrder() const { return cast<Expr>(SubExprs[ORDER]); } + Expr *getScope() const { + assert(getScopeModel() && "No scope"); + return cast<Expr>(SubExprs[NumSubExprs - 1]); + } Expr *getVal1() const { - if (Op == AO__c11_atomic_init) + if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init) return cast<Expr>(SubExprs[ORDER]); assert(NumSubExprs > VAL1); return cast<Expr>(SubExprs[VAL1]); @@ -4988,6 +5163,7 @@ public: assert(NumSubExprs > WEAK); return cast<Expr>(SubExprs[WEAK]); } + QualType getValueType() const; AtomicOp getOp() const { return Op; } unsigned getNumSubExprs() const { return NumSubExprs; } @@ -5004,10 +5180,17 @@ public: bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__opencl_atomic_compare_exchange_strong || + getOp() == AO__opencl_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || getOp() == AO__atomic_compare_exchange_n; } + bool isOpenCL() const { + return getOp() >= AO__opencl_atomic_init && + getOp() <= AO__opencl_atomic_fetch_max; + } + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -5022,6 +5205,27 @@ public: child_range children() { return child_range(SubExprs, SubExprs+NumSubExprs); } + const_child_range children() const { + return const_child_range(SubExprs, SubExprs + NumSubExprs); + } + + /// \brief Get atomic scope model for the atomic op code. + /// \return empty atomic scope model if the atomic op code does not have + /// scope operand. + static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) { + auto Kind = + (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) + ? AtomicScopeModelKind::OpenCL + : AtomicScopeModelKind::None; + return AtomicScopeModel::create(Kind); + } + + /// \brief Get atomic scope model. + /// \return empty atomic scope model if this atomic expression does not have + /// scope operand. + std::unique_ptr<AtomicScopeModel> getScopeModel() const { + return getScopeModel(getOp()); + } }; /// TypoExpr - Internal placeholder for expressions where typo correction @@ -5040,6 +5244,10 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index f4ff5bb982..a2cf961269 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -54,18 +54,16 @@ class CXXOperatorCallExpr : public CallExpr { OverloadedOperatorKind Operator; SourceRange Range; - // Record the FP_CONTRACT state that applies to this operator call. Only - // meaningful for floating point types. For other types this value can be - // set to false. - unsigned FPContractable : 1; + // Only meaningful for floating point types. + FPOptions FPFeatures; SourceRange getSourceRangeImpl() const LLVM_READONLY; public: CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation operatorloc, bool fpContractable) + SourceLocation operatorloc, FPOptions FPFeatures) : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc), - Operator(Op), FPContractable(fpContractable) { + Operator(Op), FPFeatures(FPFeatures) { Range = getSourceRangeImpl(); } explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : @@ -113,11 +111,15 @@ public: // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. - void setFPContractable(bool FPC) { FPContractable = FPC; } + void setFPFeatures(FPOptions F) { FPFeatures = F; } + + FPOptions getFPFeatures() const { return FPFeatures; } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. - bool isFPContractable() const { return FPContractable; } + bool isFPContractableWithinStatement() const { + return FPFeatures.allowFPContractWithinStatement(); + } friend class ASTStmtReader; friend class ASTStmtWriter; @@ -3054,6 +3056,11 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + /// Determine whether this expression models list-initialization. + /// If so, there will be exactly one subexpression, which will be + /// an InitListExpr. + bool isListInitialization() const { return LParenLoc.isInvalid(); } + /// \brief Retrieve the number of arguments. unsigned arg_size() const { return NumArgs; } diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h new file mode 100644 index 0000000000..81492aec6e --- /dev/null +++ b/include/clang/AST/ExternalASTMerger.h @@ -0,0 +1,176 @@ +//===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the ExternalASTMerger, which vends a combination of ASTs +// from several different ASTContext/FileManager pairs +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H +#define LLVM_CLANG_AST_EXTERNALASTMERGER_H + +#include "clang/AST/ASTImporter.h" +#include "clang/AST/ExternalASTSource.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +/// ExternalASTSource implementation that merges information from several +/// ASTContexts. +/// +/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import +/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts +/// in response to ExternalASTSource API calls. +/// +/// When lookup occurs in the resulting imported DeclContexts, the original +/// DeclContexts need to be queried. Roughly, there are three cases here: +/// +/// - The DeclContext of origin can be found by simple name lookup. In this +/// case, no additional state is required. +/// +/// - The DeclContext of origin is different from what would be found by name +/// lookup. In this case, Origins contains an entry overriding lookup and +/// specifying the correct pair of DeclContext/ASTContext. +/// +/// - The DeclContext of origin was determined by another ExterenalASTMerger. +/// (This is possible when the source ASTContext for one of the Importers has +/// its own ExternalASTMerger). The origin must be properly forwarded in this +/// case. +/// +/// ExternalASTMerger's job is to maintain the data structures necessary to +/// allow this. The data structures themselves can be extracted (read-only) and +/// copied for re-use. +class ExternalASTMerger : public ExternalASTSource { +public: + /// A single origin for a DeclContext. Unlike Decls, DeclContexts do + /// not allow their containing ASTContext to be determined in all cases. + struct DCOrigin { + DeclContext *DC; + ASTContext *AST; + }; + + typedef std::map<const DeclContext *, DCOrigin> OriginMap; + typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector; +private: + /// One importer exists for each source. + ImporterVector Importers; + /// Overrides in case name lookup would return nothing or would return + /// the wrong thing. + OriginMap Origins; + /// The installed log stream. + llvm::raw_ostream *LogStream; + +public: + /// The target for an ExternalASTMerger. + /// + /// ASTImporters require both ASTContext and FileManager to be able to + /// import SourceLocations properly. + struct ImporterTarget { + ASTContext &AST; + FileManager &FM; + }; + /// A source for an ExternalASTMerger. + /// + /// ASTImporters require both ASTContext and FileManager to be able to + /// import SourceLocations properly. Additionally, when import occurs for + /// a DeclContext whose origin has been overridden, then this + /// ExternalASTMerger must be able to determine that. + struct ImporterSource { + ASTContext &AST; + FileManager &FM; + const OriginMap &OM; + }; + +private: + /// The target for this ExtenralASTMerger. + ImporterTarget Target; + +public: + ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef<ImporterSource> Sources); + + /// Add a set of ASTContexts as possible origins. + /// + /// Usually the set will be initialized in the constructor, but long-lived + /// ExternalASTMergers may neeed to import from new sources (for example, + /// newly-parsed source files). + /// + /// Ensures that Importers does not gain duplicate entries as a result. + void AddSources(llvm::ArrayRef<ImporterSource> Sources); + + /// Remove a set of ASTContexts as possible origins. + /// + /// Sometimes an origin goes away (for example, if a source file gets + /// superseded by a newer version). + /// + /// The caller is responsible for ensuring that this doesn't leave + /// DeclContexts that can't be completed. + void RemoveSources(llvm::ArrayRef<ImporterSource> Sources); + + /// Implementation of the ExternalASTSource API. + bool FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) override; + + /// Implementation of the ExternalASTSource API. + void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Result) override; + + /// Implementation of the ExternalASTSource API. + void CompleteType(TagDecl *Tag) override; + + /// Implementation of the ExternalASTSource API. + void CompleteType(ObjCInterfaceDecl *Interface) override; + + /// Returns true if DC can be found in any source AST context. + bool CanComplete(DeclContext *DC); + + /// Records an origin in Origins only if name lookup would find + /// something different or nothing at all. + void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + + /// Regardless of any checks, override the Origin for a DeclContext. + void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + + /// Get a read-only view of the Origins map, for use in constructing + /// an ImporterSource for another ExternalASTMerger. + const OriginMap &GetOrigins() { return Origins; } + + /// Returns true if Importers contains an ASTImporter whose source is + /// OriginContext. + bool HasImporterForOrigin(ASTContext &OriginContext); + + /// Returns a reference to the ASTRImporter from Importers whose origin + /// is OriginContext. This allows manual import of ASTs while preserving the + /// OriginMap correctly. + ASTImporter &ImporterForOrigin(ASTContext &OriginContext); + + /// Sets the current log stream. + void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } +private: + /// Records and origin in Origins. + void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, + ASTImporter &importer); + + /// Performs an action for every DeclContext that is identified as + /// corresponding (either by forced origin or by name lookup) to DC. + template <typename CallbackType> + void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); + +public: + /// Log something if there is a logging callback installed. + llvm::raw_ostream &logs() { return *LogStream; } + + /// True if the log stream is not llvm::nulls(); + bool LoggingEnabled() { return LogStream != &llvm::nulls(); } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 40c54b2e8d..d8dd18ecb8 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -172,7 +172,7 @@ public: enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy }; - virtual ExtKind hasExternalDefinitions(unsigned ID); + virtual ExtKind hasExternalDefinitions(const Decl *D); /// \brief Finds all declarations lexically contained within the given /// DeclContext, after applying an optional filter predicate. diff --git a/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h new file mode 100644 index 0000000000..264f20f19a --- /dev/null +++ b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h @@ -0,0 +1,164 @@ +//===--- LexicallyOrderedRecursiveASTVisitor.h - ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LexicallyOrderedRecursiveASTVisitor interface, which +// recursively traverses the entire AST in a lexical order. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H + +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/SaveAndRestore.h" + +namespace clang { + +/// A RecursiveASTVisitor subclass that guarantees that AST traversal is +/// performed in a lexical order (i.e. the order in which declarations are +/// written in the source). +/// +/// RecursiveASTVisitor doesn't guarantee lexical ordering because there are +/// some declarations, like Objective-C @implementation declarations +/// that might be represented in the AST differently to how they were written +/// in the source. +/// In particular, Objective-C @implementation declarations may contain +/// non-Objective-C declarations, like functions: +/// +/// @implementation MyClass +/// +/// - (void) method { } +/// void normalFunction() { } +/// +/// @end +/// +/// Clang's AST stores these declarations outside of the @implementation +/// declaration, so the example above would be represented using the following +/// AST: +/// |-ObjCImplementationDecl ... MyClass +/// | `-ObjCMethodDecl ... method +/// | ... +/// `-FunctionDecl ... normalFunction +/// ... +/// +/// This class ensures that these declarations are traversed before the +/// corresponding TraverseDecl for the @implementation returns. This ensures +/// that the lexical parent relationship between these declarations and the +/// @implementation is preserved while traversing the AST. Note that the +/// current implementation doesn't mix these declarations with the declarations +/// contained in the @implementation, so the traversal of all of the +/// declarations in the @implementation still doesn't follow the lexical order. +template <typename Derived> +class LexicallyOrderedRecursiveASTVisitor + : public RecursiveASTVisitor<Derived> { + using BaseType = RecursiveASTVisitor<Derived>; + +public: + LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {} + + bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { + // Objective-C @implementation declarations should not trigger early exit + // until the additional decls are traversed as their children are not + // lexically ordered. + bool Result = BaseType::TraverseObjCImplementationDecl(D); + return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; + } + + bool TraverseObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + bool Result = BaseType::TraverseObjCCategoryImplDecl(D); + return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; + } + + bool TraverseDeclContextHelper(DeclContext *DC) { + if (!DC) + return true; + + for (auto I = DC->decls_begin(), E = DC->decls_end(); I != E;) { + Decl *Child = *I; + if (BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Child)) { + ++I; + continue; + } + if (!isa<ObjCImplementationDecl>(Child) && + !isa<ObjCCategoryImplDecl>(Child)) { + if (!BaseType::getDerived().TraverseDecl(Child)) + return false; + ++I; + continue; + } + // Gather declarations that follow the Objective-C implementation + // declarations but are lexically contained in the implementation. + LexicallyNestedDeclarations.clear(); + for (++I; I != E; ++I) { + Decl *Sibling = *I; + if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(), + Child->getLocEnd())) + break; + if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling)) + LexicallyNestedDeclarations.push_back(Sibling); + } + if (!BaseType::getDerived().TraverseDecl(Child)) + return false; + } + return true; + } + + Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } + + SmallVector<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) { + SmallVector<Stmt *, 8> Children(CE->children()); + bool Swap; + // Switch the operator and the first operand for all infix and postfix + // operations. + switch (CE->getOperator()) { + case OO_Arrow: + case OO_Call: + case OO_Subscript: + Swap = true; + break; + case OO_PlusPlus: + case OO_MinusMinus: + // These are postfix unless there is exactly one argument. + Swap = Children.size() != 2; + break; + default: + Swap = CE->isInfixBinaryOp(); + break; + } + if (Swap && Children.size() > 1) + std::swap(Children[0], Children[1]); + return Children; + } + +private: + bool TraverseAdditionalLexicallyNestedDeclarations() { + // FIXME: Ideally the gathered declarations and the declarations in the + // @implementation should be mixed and sorted to get a true lexical order, + // but right now we only care about getting the correct lexical parent, so + // we can traverse the gathered nested declarations after the declarations + // in the decl context. + assert(!BaseType::getDerived().shouldTraversePostOrder() && + "post-order traversal is not supported for lexically ordered " + "recursive ast visitor"); + for (Decl *D : LexicallyNestedDeclarations) { + if (!BaseType::getDerived().TraverseDecl(D)) + return false; + } + return true; + } + + const SourceManager &SM; + llvm::SmallVector<Decl *, 8> LexicallyNestedDeclarations; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h index 583f9d9f1d..3757116e7c 100644 --- a/include/clang/AST/NSAPI.h +++ b/include/clang/AST/NSAPI.h @@ -49,7 +49,7 @@ public: NSStr_initWithString, NSStr_initWithUTF8String }; - static const unsigned NumNSStringMethods = 5; + static const unsigned NumNSStringMethods = 6; IdentifierInfo *getNSClassId(NSClassIdKindKind K) const; @@ -112,7 +112,7 @@ public: NSMutableDict_setObjectForKeyedSubscript, NSMutableDict_setValueForKey }; - static const unsigned NumNSDictionaryMethods = 14; + static const unsigned NumNSDictionaryMethods = 13; /// \brief The Objective-C NSDictionary selectors. Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const; diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index b1ff9bdff5..29862ba416 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -35,7 +35,7 @@ class LangOptions; /// "\::std::vector<int>::". /// /// C++ nested name specifiers are the prefixes to qualified -/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// names. For example, "foo::" in "foo::x" is a nested name /// specifier. Nested name specifiers are made up of a sequence of /// specifiers, each of which can be a namespace, type, identifier /// (for dependent names), decltype specifier, or the global specifier ('::'). diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h index 9af8488fca..e4cc12d358 100644 --- a/include/clang/AST/ODRHash.h +++ b/include/clang/AST/ODRHash.h @@ -25,7 +25,7 @@ namespace clang { class Decl; class IdentifierInfo; -class NestedNameSpecifer; +class NestedNameSpecifier; class Stmt; class TemplateParameterList; diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index f977e63e04..7c24e34251 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -20,6 +20,7 @@ #include "clang/AST/Stmt.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/MapVector.h" namespace clang { @@ -1889,6 +1890,449 @@ public: } }; +/// This represents clause 'task_reduction' in the '#pragma omp taskgroup' +/// directives. +/// +/// \code +/// #pragma omp taskgroup task_reduction(+:a,b) +/// \endcode +/// In this example directive '#pragma omp taskgroup' has clause +/// 'task_reduction' with operator '+' and the variables 'a' and 'b'. +/// +class OMPTaskReductionClause final + : public OMPVarListClause<OMPTaskReductionClause>, + public OMPClauseWithPostUpdate, + private llvm::TrailingObjects<OMPTaskReductionClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// Location of ':'. + SourceLocation ColonLoc; + /// Nested name specifier for C++. + NestedNameSpecifierLoc QualifierLoc; + /// Name of custom operator. + DeclarationNameInfo NameInfo; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param ColonLoc Location of ':'. + /// \param N Number of the variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// + OMPTaskReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + unsigned N, NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : OMPVarListClause<OMPTaskReductionClause>(OMPC_task_reduction, StartLoc, + LParenLoc, EndLoc, N), + OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), + QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPTaskReductionClause(unsigned N) + : OMPVarListClause<OMPTaskReductionClause>( + OMPC_task_reduction, SourceLocation(), SourceLocation(), + SourceLocation(), N), + OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {} + + /// Sets location of ':' symbol in clause. + void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + /// Sets the name info for specified reduction identifier. + void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + /// Sets the nested name specifier. + void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent private copy of the reduction variable. + void setPrivates(ArrayRef<Expr *> Privates); + + /// Get the list of helper privates. + MutableArrayRef<Expr *> getPrivates() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivates() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent LHS expression in the final reduction + /// expression performed by the reduction clause. + void setLHSExprs(ArrayRef<Expr *> LHSExprs); + + /// Get the list of helper LHS expressions. + MutableArrayRef<Expr *> getLHSExprs() { + return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size()); + } + ArrayRef<const Expr *> getLHSExprs() const { + return llvm::makeArrayRef(getPrivates().end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent RHS expression in the final reduction + /// expression performed by the reduction clause. Also, variables in these + /// expressions are used for proper initialization of reduction copies. + void setRHSExprs(ArrayRef<Expr *> RHSExprs); + + /// Get the list of helper destination expressions. + MutableArrayRef<Expr *> getRHSExprs() { + return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getRHSExprs() const { + return llvm::makeArrayRef(getLHSExprs().end(), varlist_size()); + } + + /// Set list of helper reduction expressions, required for proper + /// codegen of the clause. These expressions are binary expressions or + /// operator/custom reduction call that calculates new value from source + /// helper expressions to destination helper expressions. + void setReductionOps(ArrayRef<Expr *> ReductionOps); + + /// Get the list of helper reduction expressions. + MutableArrayRef<Expr *> getReductionOps() { + return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getReductionOps() const { + return llvm::makeArrayRef(getRHSExprs().end(), varlist_size()); + } + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL The variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// \param Privates List of helper expressions for proper generation of + /// private copies. + /// \param LHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// LHSs of the reduction expressions. + /// \param RHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// RHSs of the reduction expressions. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + /// \param ReductionOps List of helper expressions that represents reduction + /// expressions: + /// \code + /// LHSExprs binop RHSExprs; + /// operator binop(LHSExpr, RHSExpr); + /// <CutomReduction>(LHSExpr, RHSExpr); + /// \endcode + /// Required for proper codegen of final reduction operation performed by the + /// reduction clause. + /// \param PreInit Statement that must be executed before entering the OpenMP + /// region with this clause. + /// \param PostUpdate Expression that must be executed after exit from the + /// OpenMP region with this clause. + /// + static OMPTaskReductionClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates, + ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, + ArrayRef<Expr *> ReductionOps, Stmt *PreInit, Expr *PostUpdate); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPTaskReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// Gets location of ':' symbol in clause. + SourceLocation getColonLoc() const { return ColonLoc; } + /// Gets the name info for specified reduction identifier. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + /// Gets the nested name specifier. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + helper_expr_const_range privates() const { + return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_range privates() { + return helper_expr_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_const_range lhs_exprs() const { + return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_range lhs_exprs() { + return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_const_range rhs_exprs() const { + return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_range rhs_exprs() { + return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_const_range reduction_ops() const { + return helper_expr_const_range(getReductionOps().begin(), + getReductionOps().end()); + } + helper_expr_range reduction_ops() { + return helper_expr_range(getReductionOps().begin(), + getReductionOps().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_task_reduction; + } +}; + +/// This represents clause 'in_reduction' in the '#pragma omp task' directives. +/// +/// \code +/// #pragma omp task in_reduction(+:a,b) +/// \endcode +/// In this example directive '#pragma omp task' has clause 'in_reduction' with +/// operator '+' and the variables 'a' and 'b'. +/// +class OMPInReductionClause final + : public OMPVarListClause<OMPInReductionClause>, + public OMPClauseWithPostUpdate, + private llvm::TrailingObjects<OMPInReductionClause, Expr *> { + friend TrailingObjects; + friend OMPVarListClause; + friend class OMPClauseReader; + /// Location of ':'. + SourceLocation ColonLoc; + /// Nested name specifier for C++. + NestedNameSpecifierLoc QualifierLoc; + /// Name of custom operator. + DeclarationNameInfo NameInfo; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param ColonLoc Location of ':'. + /// \param N Number of the variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// + OMPInReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + unsigned N, NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : OMPVarListClause<OMPInReductionClause>(OMPC_in_reduction, StartLoc, + LParenLoc, EndLoc, N), + OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), + QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPInReductionClause(unsigned N) + : OMPVarListClause<OMPInReductionClause>( + OMPC_in_reduction, SourceLocation(), SourceLocation(), + SourceLocation(), N), + OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {} + + /// Sets location of ':' symbol in clause. + void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + /// Sets the name info for specified reduction identifier. + void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + /// Sets the nested name specifier. + void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent private copy of the reduction variable. + void setPrivates(ArrayRef<Expr *> Privates); + + /// Get the list of helper privates. + MutableArrayRef<Expr *> getPrivates() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivates() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent LHS expression in the final reduction + /// expression performed by the reduction clause. + void setLHSExprs(ArrayRef<Expr *> LHSExprs); + + /// Get the list of helper LHS expressions. + MutableArrayRef<Expr *> getLHSExprs() { + return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size()); + } + ArrayRef<const Expr *> getLHSExprs() const { + return llvm::makeArrayRef(getPrivates().end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent RHS expression in the final reduction + /// expression performed by the reduction clause. Also, variables in these + /// expressions are used for proper initialization of reduction copies. + void setRHSExprs(ArrayRef<Expr *> RHSExprs); + + /// Get the list of helper destination expressions. + MutableArrayRef<Expr *> getRHSExprs() { + return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getRHSExprs() const { + return llvm::makeArrayRef(getLHSExprs().end(), varlist_size()); + } + + /// Set list of helper reduction expressions, required for proper + /// codegen of the clause. These expressions are binary expressions or + /// operator/custom reduction call that calculates new value from source + /// helper expressions to destination helper expressions. + void setReductionOps(ArrayRef<Expr *> ReductionOps); + + /// Get the list of helper reduction expressions. + MutableArrayRef<Expr *> getReductionOps() { + return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getReductionOps() const { + return llvm::makeArrayRef(getRHSExprs().end(), varlist_size()); + } + + /// Set list of helper reduction taskgroup descriptors. + void setTaskgroupDescriptors(ArrayRef<Expr *> ReductionOps); + + /// Get the list of helper reduction taskgroup descriptors. + MutableArrayRef<Expr *> getTaskgroupDescriptors() { + return MutableArrayRef<Expr *>(getReductionOps().end(), varlist_size()); + } + ArrayRef<const Expr *> getTaskgroupDescriptors() const { + return llvm::makeArrayRef(getReductionOps().end(), varlist_size()); + } + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL The variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// \param Privates List of helper expressions for proper generation of + /// private copies. + /// \param LHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// LHSs of the reduction expressions. + /// \param RHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// RHSs of the reduction expressions. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + /// \param ReductionOps List of helper expressions that represents reduction + /// expressions: + /// \code + /// LHSExprs binop RHSExprs; + /// operator binop(LHSExpr, RHSExpr); + /// <CutomReduction>(LHSExpr, RHSExpr); + /// \endcode + /// Required for proper codegen of final reduction operation performed by the + /// reduction clause. + /// \param TaskgroupDescriptors List of helper taskgroup descriptors for + /// corresponding items in parent taskgroup task_reduction clause. + /// \param PreInit Statement that must be executed before entering the OpenMP + /// region with this clause. + /// \param PostUpdate Expression that must be executed after exit from the + /// OpenMP region with this clause. + /// + static OMPInReductionClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates, + ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, + ArrayRef<Expr *> ReductionOps, ArrayRef<Expr *> TaskgroupDescriptors, + Stmt *PreInit, Expr *PostUpdate); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPInReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// Gets location of ':' symbol in clause. + SourceLocation getColonLoc() const { return ColonLoc; } + /// Gets the name info for specified reduction identifier. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + /// Gets the nested name specifier. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; + typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; + typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; + typedef llvm::iterator_range<helper_expr_const_iterator> + helper_expr_const_range; + + helper_expr_const_range privates() const { + return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_range privates() { + return helper_expr_range(getPrivates().begin(), getPrivates().end()); + } + helper_expr_const_range lhs_exprs() const { + return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_range lhs_exprs() { + return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); + } + helper_expr_const_range rhs_exprs() const { + return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_range rhs_exprs() { + return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); + } + helper_expr_const_range reduction_ops() const { + return helper_expr_const_range(getReductionOps().begin(), + getReductionOps().end()); + } + helper_expr_range reduction_ops() { + return helper_expr_range(getReductionOps().begin(), + getReductionOps().end()); + } + helper_expr_const_range taskgroup_descriptors() const { + return helper_expr_const_range(getTaskgroupDescriptors().begin(), + getTaskgroupDescriptors().end()); + } + helper_expr_range taskgroup_descriptors() { + return helper_expr_range(getTaskgroupDescriptors().begin(), + getTaskgroupDescriptors().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_in_reduction; + } +}; + /// \brief This represents clause 'linear' in the '#pragma omp ...' /// directives. /// @@ -2697,7 +3141,7 @@ public: /// In this example directive '#pragma omp target' has clause 'device' /// with single expression 'a'. /// -class OMPDeviceClause : public OMPClause { +class OMPDeviceClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; /// \brief Location of '('. SourceLocation LParenLoc; @@ -2717,16 +3161,19 @@ public: /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// - OMPDeviceClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) - : OMPClause(OMPC_device, StartLoc, EndLoc), LParenLoc(LParenLoc), - Device(E) {} + OMPDeviceClause(Expr *E, Stmt *HelperE, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_device, StartLoc, EndLoc), OMPClauseWithPreInit(this), + LParenLoc(LParenLoc), Device(E) { + setPreInitStmt(HelperE); + } /// \brief Build an empty clause. /// OMPDeviceClause() - : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Device(nullptr) {} + : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), + OMPClauseWithPreInit(this), LParenLoc(SourceLocation()), + Device(nullptr) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } /// \brief Returns the location of '('. @@ -3001,7 +3448,7 @@ protected: // Organize the components by declaration and retrieve the original // expression. Original expressions are always the first component of the // mappable component list. - llvm::DenseMap<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>> + llvm::MapVector<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>> ComponentListMap; { auto CI = ComponentLists.begin(); diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 274df220e1..953ecada6c 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -50,7 +50,8 @@ struct PrintingPolicy { UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), - IncludeNewlines(true), MSVCFormatting(false) { } + IncludeNewlines(true), MSVCFormatting(false), + ConstantsAsWritten(false), SuppressImplicitBase(false) { } /// \brief Adjust this printing policy for cases where it's known that /// we're printing C++ code (for instance, if AST dumping reaches a @@ -200,6 +201,27 @@ struct PrintingPolicy { /// prints anonymous namespaces as `anonymous namespace' and does not insert /// spaces after template arguments. bool MSVCFormatting : 1; + + /// \brief Whether we should print the constant expressions as written in the + /// sources. + /// + /// This flag determines whether constants expressions like + /// + /// \code + /// 0x10 + /// 2.5e3 + /// \endcode + /// + /// will be printed as written or as follows: + /// + /// \code + /// 0x10 + /// 2.5e3 + /// \endcode + bool ConstantsAsWritten : 1; + + /// \brief When true, don't print the implicit 'self' or 'this' expressions. + bool SuppressImplicitBase : 1; }; } // end namespace clang diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 1b5850a05b..7fb5221b7d 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -83,7 +83,7 @@ namespace clang { return false; \ } while (false) -/// \brief A class that does preordor or postorder +/// \brief A class that does preorder or postorder /// depth-first traversal on the entire Clang AST and visits each node. /// /// This class performs three distinct tasks: @@ -267,6 +267,12 @@ public: bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + /// \brief Recursively visit a base specifier. This can be overridden by a + /// subclass. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base); + /// \brief Recursively visit a constructor initializer. This /// automatically dispatches to another visitor for the initializer /// expression, but not for the name of the initializer, so may @@ -309,6 +315,8 @@ public: // ---- Methods on Stmts ---- + Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } + private: template<typename T, typename U> struct has_same_member_pointer_type : std::false_type {}; @@ -491,6 +499,8 @@ public: bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } #include "clang/AST/DeclNodes.inc" + bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child); + private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); @@ -593,6 +603,16 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) { #define STMT(CLASS, PARENT) \ case Stmt::CLASS##Class: \ TRY_TO(WalkUpFrom##CLASS(static_cast<CLASS *>(S))); break; +#define INITLISTEXPR(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + { \ + auto ILE = static_cast<CLASS *>(S); \ + if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \ + TRY_TO(WalkUpFrom##CLASS(Syn)); \ + if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \ + TRY_TO(WalkUpFrom##CLASS(Sem)); \ + break; \ + } #include "clang/AST/StmtNodes.inc" } @@ -968,6 +988,11 @@ DEF_TRAVERSE_TYPE(DependentSizedArrayType, { TRY_TO(TraverseStmt(T->getSizeExpr())); }) +DEF_TRAVERSE_TYPE(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(T->getAddrSpaceExpr())); + TRY_TO(TraverseType(T->getPointeeType())); +}) + DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { if (T->getSizeExpr()) TRY_TO(TraverseStmt(T->getSizeExpr())); @@ -1021,8 +1046,12 @@ DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { DEF_TRAVERSE_TYPE(RecordType, {}) DEF_TRAVERSE_TYPE(EnumType, {}) DEF_TRAVERSE_TYPE(TemplateTypeParmType, {}) -DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {}) -DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { + TRY_TO(TraverseType(T->getReplacementType())); +}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { + TRY_TO(TraverseTemplateArgument(T->getArgumentPack())); +}) DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); @@ -1174,6 +1203,11 @@ DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { return TraverseArrayTypeLocHelper(TL); }) +DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getAddrSpaceExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getPointeeType())); +}) + // FIXME: order? why not size expr first? // FIXME: base VectorTypeLoc is unfinished DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { @@ -1249,8 +1283,12 @@ DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { DEF_TRAVERSE_TYPELOC(RecordType, {}) DEF_TRAVERSE_TYPELOC(EnumType, {}) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) -DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {}) -DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { + TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType())); +}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { + TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack())); +}) // FIXME: use the loc for the template name? DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { @@ -1321,14 +1359,20 @@ DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) // than those. template <typename Derived> +bool RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext( + const Decl *Child) { + // BlockDecls and CapturedDecls are traversed through BlockExprs and + // CapturedStmts respectively. + return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child); +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) { if (!DC) return true; for (auto *Child : DC->decls()) { - // BlockDecls and CapturedDecls are traversed through BlockExprs and - // CapturedStmts respectively. - if (!isa<BlockDecl>(Child) && !isa<CapturedDecl>(Child)) + if (!canIgnoreChildDeclWhileTraversingDeclContext(Child)) TRY_TO(TraverseDecl(Child)); } @@ -1656,8 +1700,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( // template declarations. #define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \ DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \ - TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \ + TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ \ /* By default, we do not traverse the instantiations of \ class templates since they do not appear in the user code. The \ @@ -1751,12 +1795,19 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseCXXBaseSpecifier( + const CXXBaseSpecifier &Base) { + TRY_TO(TraverseTypeLoc(Base.getTypeSourceInfo()->getTypeLoc())); + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(CXXRecordDecl *D) { if (!TraverseRecordHelper(D)) return false; if (D->isCompleteDefinition()) { for (const auto &I : D->bases()) { - TRY_TO(TraverseTypeLoc(I.getTypeSourceInfo()->getTypeLoc())); + TRY_TO(TraverseCXXBaseSpecifier(I)); } // We don't traverse the friends or the conversions, as they are // already in decls_begin()/decls_end(). @@ -1781,6 +1832,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); }) if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \ \ + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \ if (!getDerived().shouldVisitTemplateInstantiations() && \ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \ /* Returning from here skips traversing the \ @@ -2038,7 +2090,7 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { TRY_TO(WalkUpFrom##STMT(S)); \ { CODE; } \ if (ShouldVisitChildren) { \ - for (Stmt *SubStmt : S->children()) { \ + for (Stmt * SubStmt : getDerived().getStmtChildren(S)) { \ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \ } \ } \ @@ -2212,13 +2264,15 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr( // the syntactic and the semantic form. // // There is no guarantee about which form \p S takes when this method is called. -DEF_TRAVERSE_STMT(InitListExpr, { +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseInitListExpr( + InitListExpr *S, DataRecursionQueue *Queue) { TRY_TO(TraverseSynOrSemInitListExpr( S->isSemanticForm() ? S->getSyntacticForm() : S, Queue)); TRY_TO(TraverseSynOrSemInitListExpr( S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); - ShouldVisitChildren = false; -}) + return true; +} // GenericSelectionExpr is a special case because the types and expressions // are interleaved. We also need to watch out for null types (default @@ -2326,7 +2380,7 @@ DEF_TRAVERSE_STMT(LambdaExpr, { } TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); + FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); if (S->hasExplicitParameters() && S->hasExplicitResultType()) { // Visit the whole type. @@ -2996,6 +3050,52 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPTaskReductionClause( + OMPTaskReductionClause *C) { + TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); + TRY_TO(VisitOMPClauseList(C)); + TRY_TO(VisitOMPClauseWithPostUpdate(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPInReductionClause( + OMPInReductionClause *C) { + TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); + TRY_TO(VisitOMPClauseList(C)); + TRY_TO(VisitOMPClauseWithPostUpdate(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->taskgroup_descriptors()) + TRY_TO(TraverseStmt(E)); + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) { TRY_TO(VisitOMPClauseList(C)); return true; @@ -3009,6 +3109,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) { + TRY_TO(VisitOMPClauseWithPreInit(C)); TRY_TO(TraverseStmt(C->getDevice())); return true; } diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index cd5f186a20..89a9d3c4cc 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -21,6 +21,60 @@ namespace clang { class ASTContext; +// Some notes on redeclarables: +// +// - Every redeclarable is on a circular linked list. +// +// - Every decl has a pointer to the first element of the chain _and_ a +// DeclLink that may point to one of 3 possible states: +// - the "previous" (temporal) element in the chain +// - the "latest" (temporal) element in the chain +// - the an "uninitialized-latest" value (when newly-constructed) +// +// - The first element is also often called the canonical element. Every +// element has a pointer to it so that "getCanonical" can be fast. +// +// - Most links in the chain point to previous, except the link out of +// the first; it points to latest. +// +// - Elements are called "first", "previous", "latest" or +// "most-recent" when referring to temporal order: order of addition +// to the chain. +// +// - To make matters confusing, the DeclLink type uses the term "next" +// for its pointer-storage internally (thus functions like +// NextIsPrevious). It's easiest to just ignore the implementation of +// DeclLink when making sense of the redeclaration chain. +// +// - There's also a "definition" link for several types of +// redeclarable, where only one definition should exist at any given +// time (and the defn pointer is stored in the decl's "data" which +// is copied to every element on the chain when it's changed). +// +// Here is some ASCII art: +// +// "first" "latest" +// "canonical" "most recent" +// +------------+ first +--------------+ +// | | <--------------------------- | | +// | | | | +// | | | | +// | | +--------------+ | | +// | | first | | | | +// | | <---- | | | | +// | | | | | | +// | @class A | link | @interface A | link | @class A | +// | seen first | <---- | seen second | <---- | seen third | +// | | | | | | +// +------------+ +--------------+ +--------------+ +// | data | defn | data | defn | data | +// | | ----> | | <---- | | +// +------------+ +--------------+ +--------------+ +// | | ^ ^ +// | |defn | | +// | link +-----+ | +// +-->-------------------------------------------+ + /// \brief Provides common interface for the Decls that can be redeclared. template<typename decl_type> class Redeclarable { diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index c210bd1cec..795f4d6e71 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -389,8 +389,8 @@ public: /// back to its original source language syntax. void dumpPretty(const ASTContext &Context) const; void printPretty(raw_ostream &OS, PrinterHelper *Helper, - const PrintingPolicy &Policy, - unsigned Indentation = 0) const; + const PrintingPolicy &Policy, unsigned Indentation = 0, + const ASTContext *Context = nullptr) const; /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only /// works on systems with GraphViz (Mac OS X) or dot+gv installed. diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index ac440a9f0c..77f81838e5 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -308,12 +308,16 @@ class CoroutineBodyStmt final OnFallthrough, ///< Handler for control flow falling off the body. Allocate, ///< Coroutine frame memory allocation. Deallocate, ///< Coroutine frame memory deallocation. - ReturnValue, ///< Return value for thunk function. + ReturnValue, ///< Return value for thunk function: p.get_return_object(). + ResultDecl, ///< Declaration holding the result of get_return_object. + ReturnStmt, ///< Return statement for the thunk function. + ReturnStmtOnAllocFailure, ///< Return statement if allocation failed. FirstParamMove ///< First offset for move construction of parameter copies. }; unsigned NumParams; friend class ASTStmtReader; + friend class ASTReader; friend TrailingObjects; Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); } @@ -331,7 +335,10 @@ public: Stmt *OnFallthrough = nullptr; Expr *Allocate = nullptr; Expr *Deallocate = nullptr; - Stmt *ReturnValue = nullptr; + Expr *ReturnValue = nullptr; + Stmt *ResultDecl = nullptr; + Stmt *ReturnStmt = nullptr; + Stmt *ReturnStmtOnAllocFailure = nullptr; ArrayRef<Stmt *> ParamMoves; }; @@ -341,6 +348,12 @@ private: public: static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args); + static CoroutineBodyStmt *Create(const ASTContext &C, EmptyShell, + unsigned NumParams); + + bool hasDependentPromiseType() const { + return getPromiseDecl()->getType()->isDependentType(); + } /// \brief Retrieve the body of the coroutine as written. This will be either /// a CompoundStmt or a TryStmt. @@ -375,9 +388,13 @@ public: Expr *getDeallocate() const { return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]); } - Expr *getReturnValueInit() const { - return cast_or_null<Expr>(getStoredStmts()[SubStmt::ReturnValue]); + return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]); + } + Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; } + Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; } + Stmt *getReturnStmtOnAllocFailure() const { + return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure]; } ArrayRef<Stmt const *> getParamMoves() const { return {getStoredStmts() + SubStmt::FirstParamMove, NumParams}; @@ -430,6 +447,8 @@ public: SubStmts[SubStmt::PromiseCall] = PromiseCall; } + CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {} + SourceLocation getKeywordLoc() const { return CoreturnLoc; } /// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr diff --git a/include/clang/AST/StmtDataCollectors.td b/include/clang/AST/StmtDataCollectors.td new file mode 100644 index 0000000000..bf5f8c2170 --- /dev/null +++ b/include/clang/AST/StmtDataCollectors.td @@ -0,0 +1,242 @@ +class Stmt { + code Code = [{ + addData(S->getStmtClass()); + // This ensures that non-macro-generated code isn't identical to + // macro-generated code. + addData(data_collection::getMacroStack(S->getLocStart(), Context)); + addData(data_collection::getMacroStack(S->getLocEnd(), Context)); + }]; +} + +class Expr { + code Code = [{ + addData(S->getType()); + }]; +} + +//--- Builtin functionality ----------------------------------------------// +class ArrayTypeTraitExpr { + code Code = [{ + addData(S->getTrait()); + }]; +} +class ExpressionTraitExpr { + code Code = [{ + addData(S->getTrait()); + }]; +} +class PredefinedExpr { + code Code = [{ + addData(S->getIdentType()); + }]; +} +class TypeTraitExpr { + code Code = [{ + addData(S->getTrait()); + for (unsigned i = 0; i < S->getNumArgs(); ++i) + addData(S->getArg(i)->getType()); + }]; +} + +//--- Calls --------------------------------------------------------------// +class CallExpr { + code Code = [{ + // Function pointers don't have a callee and we just skip hashing it. + if (const FunctionDecl *D = S->getDirectCallee()) { + // If the function is a template specialization, we also need to handle + // the template arguments as they are not included in the qualified name. + if (auto Args = D->getTemplateSpecializationArgs()) { + std::string ArgString; + + // Print all template arguments into ArgString + llvm::raw_string_ostream OS(ArgString); + for (unsigned i = 0; i < Args->size(); ++i) { + Args->get(i).print(Context.getLangOpts(), OS); + // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. + OS << '\n'; + } + OS.flush(); + + addData(ArgString); + } + addData(D->getQualifiedNameAsString()); + } + }]; +} + +//--- Value references ---------------------------------------------------// +class DeclRefExpr { + code Code = [{ + addData(S->getDecl()->getQualifiedNameAsString()); + }]; +} +class MemberExpr { + code Code = [{ + addData(S->getMemberDecl()->getName()); + }]; +} + +//--- Literals -----------------------------------------------------------// +class IntegerLiteral { + code Code = [{ + addData(llvm::hash_value(S->getValue())); + }]; +} +class FloatingLiteral { + code Code = [{ + addData(llvm::hash_value(S->getValue())); + }]; +} +class StringLiteral { + code Code = [{ + addData(S->getString()); +}]; +} +class CXXBoolLiteralExpr { + code Code = [{ + addData(S->getValue()); + }]; +} +class CharacterLiteral { + code Code = [{ + addData(S->getValue()); + }]; +} + +//--- Exceptions ---------------------------------------------------------// +class CXXCatchStmt { + code Code = [{ + addData(S->getCaughtType()); + }]; +} + +//--- C++ OOP Stmts ------------------------------------------------------// +class CXXDeleteExpr { + code Code = [{ + addData(S->isArrayFormAsWritten()); addData(S->isGlobalDelete()); + }]; +} + +//--- Casts --------------------------------------------------------------// +class ObjCBridgedCastExpr { + code Code = [{ + addData(S->getBridgeKind()); + }]; +} + +//--- Miscellaneous Exprs ------------------------------------------------// +class BinaryOperator { + code Code = [{ + addData(S->getOpcode()); + }]; +} +class UnaryOperator { + code Code = [{ + addData(S->getOpcode()); + }]; +} + +//--- Control flow -------------------------------------------------------// +class GotoStmt { + code Code = [{ + addData(S->getLabel()->getName()); + }]; +} +class IndirectGotoStmt { + code Code = [{ + if (S->getConstantTarget()) + addData(S->getConstantTarget()->getName()); + }]; +} +class LabelStmt { + code Code = [{ + addData(S->getDecl()->getName()); + }]; +} +class MSDependentExistsStmt { + code Code = [{ + addData(S->isIfExists()); + }]; +} +class AddrLabelExpr { + code Code = [{ + addData(S->getLabel()->getName()); + }]; +} + +//--- Objective-C --------------------------------------------------------// +class ObjCIndirectCopyRestoreExpr { + code Code = [{ + addData(S->shouldCopy()); + }]; +} +class ObjCPropertyRefExpr { + code Code = [{ + addData(S->isSuperReceiver()); addData(S->isImplicitProperty()); + }]; +} +class ObjCAtCatchStmt { + code Code = [{ + addData(S->hasEllipsis()); + }]; +} + +//--- Miscellaneous Stmts ------------------------------------------------// +class CXXFoldExpr { + code Code = [{ + addData(S->isRightFold()); addData(S->getOperator()); + }]; +} +class GenericSelectionExpr { + code Code = [{ + for (unsigned i = 0; i < S->getNumAssocs(); ++i) { + addData(S->getAssocType(i)); + } + }]; +} +class LambdaExpr { + code Code = [{ + for (const LambdaCapture &C : S->captures()) { + addData(C.isPackExpansion()); + addData(C.getCaptureKind()); + if (C.capturesVariable()) + addData(C.getCapturedVar()->getType()); + } + addData(S->isGenericLambda()); + addData(S->isMutable()); + }]; +} +class DeclStmt { + code Code = [{ + auto numDecls = std::distance(S->decl_begin(), S->decl_end()); + addData(static_cast<unsigned>(numDecls)); + for (const Decl *D : S->decls()) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + addData(VD->getType()); + } + } + }]; +} +class AsmStmt { + code Code = [{ + addData(S->isSimple()); + addData(S->isVolatile()); + addData(S->generateAsmString(Context)); + for (unsigned i = 0; i < S->getNumInputs(); ++i) { + addData(S->getInputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumOutputs(); ++i) { + addData(S->getOutputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumClobbers(); ++i) { + addData(S->getClobber(i)); + } + }]; +} +class AttributedStmt { + code Code = [{ + for (const Attr *A : S->getAttrs()) { + addData(std::string(A->getSpelling())); + } + }]; +} diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index 81f8ad4344..5d3bce8d83 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -118,6 +118,8 @@ public: REFERENCE operator->() const { return operator*(); } }; +struct ConstStmtIterator; + struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} @@ -128,6 +130,13 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { StmtIterator(const VariableArrayType *t) : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} + +private: + StmtIterator(const StmtIteratorBase &RHS) + : StmtIteratorImpl<StmtIterator, Stmt *&>(RHS) {} + + inline friend StmtIterator + cast_away_const(const ConstStmtIterator &RHS); }; struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, @@ -137,8 +146,15 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, ConstStmtIterator(const StmtIterator& RHS) : StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} + + ConstStmtIterator(Stmt * const *S) + : StmtIteratorImpl<ConstStmtIterator, const Stmt *>( + const_cast<Stmt **>(S)) {} }; +inline StmtIterator cast_away_const(const ConstStmtIterator &RHS) { + return RHS; +} } // end namespace clang #endif diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index 13af142ca3..5ad118ca40 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -318,8 +318,9 @@ class OMPLoopDirective : public OMPExecutableDirective { /// \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 10 are specific to the worksharing ones. + /// The first 9 children are necessary for all the loop directives, + /// the next 8 are specific to the worksharing ones, and the next 11 are + /// used for combined constructs containing two pragmas associated to loops. /// After the fixed children, three arrays of length CollapsedNum are /// allocated: loop counters, their updates and final values. /// PrevLowerBound and PrevUpperBound are used to communicate blocking @@ -344,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective { // specify the offset to the end (and start of the following counters/ // updates/finals arrays). DefaultEnd = 9, - // The following 12 exprs are used by worksharing and distribute loops only. + // The following 8 exprs are used by worksharing and distribute loops only. IsLastIterVariableOffset = 9, LowerBoundVariableOffset = 10, UpperBoundVariableOffset = 11, @@ -353,13 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective { NextLowerBoundOffset = 14, NextUpperBoundOffset = 15, NumIterationsOffset = 16, + // Offset to the end for worksharing loop directives. + WorksharingEnd = 17, PrevLowerBoundVariableOffset = 17, PrevUpperBoundVariableOffset = 18, DistIncOffset = 19, PrevEnsureUpperBoundOffset = 20, + CombinedLowerBoundVariableOffset = 21, + CombinedUpperBoundVariableOffset = 22, + CombinedEnsureUpperBoundOffset = 23, + CombinedInitOffset = 24, + CombinedConditionOffset = 25, + CombinedNextLowerBoundOffset = 26, + CombinedNextUpperBoundOffset = 27, // Offset to the end (and start of the following counters/updates/finals - // arrays) for worksharing loop directives. - WorksharingEnd = 21, + // arrays) for combined distribute loop directives. + CombinedDistributeEnd = 28, }; /// \brief Get the counters storage. @@ -423,11 +433,12 @@ protected: /// \brief Offset to the start of children expression arrays. static unsigned getArraysOffset(OpenMPDirectiveKind Kind) { - return (isOpenMPWorksharingDirective(Kind) || - isOpenMPTaskLoopDirective(Kind) || - isOpenMPDistributeDirective(Kind)) - ? WorksharingEnd - : DefaultEnd; + if (isOpenMPLoopBoundSharingDirective(Kind)) + return CombinedDistributeEnd; + if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) || + isOpenMPDistributeDirective(Kind)) + return WorksharingEnd; + return DefaultEnd; } /// \brief Children number. @@ -515,33 +526,60 @@ protected: *std::next(child_begin(), NumIterationsOffset) = NI; } void setPrevLowerBoundVariable(Expr *PrevLB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB; } void setPrevUpperBoundVariable(Expr *PrevUB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB; } void setDistInc(Expr *DistInc) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), DistIncOffset) = DistInc; } void setPrevEnsureUpperBound(Expr *PrevEUB) { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); *std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB; } + void setCombinedLowerBoundVariable(Expr *CombLB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB; + } + void setCombinedUpperBoundVariable(Expr *CombUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB; + } + void setCombinedEnsureUpperBound(Expr *CombEUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB; + } + void setCombinedInit(Expr *CombInit) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedInitOffset) = CombInit; + } + void setCombinedCond(Expr *CombCond) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedConditionOffset) = CombCond; + } + void setCombinedNextLowerBound(Expr *CombNLB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB; + } + void setCombinedNextUpperBound(Expr *CombNUB) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + *std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB; + } void setCounters(ArrayRef<Expr *> A); void setPrivateCounters(ArrayRef<Expr *> A); void setInits(ArrayRef<Expr *> A); @@ -549,6 +587,33 @@ protected: void setFinals(ArrayRef<Expr *> A); public: + /// The expressions built to support OpenMP loops in combined/composite + /// pragmas (e.g. pragma omp distribute parallel for) + struct DistCombinedHelperExprs { + /// DistributeLowerBound - used when composing 'omp distribute' with + /// 'omp for' in a same construct. + Expr *LB; + /// DistributeUpperBound - used when composing 'omp distribute' with + /// 'omp for' in a same construct. + Expr *UB; + /// DistributeEnsureUpperBound - used when composing 'omp distribute' + /// with 'omp for' in a same construct, EUB depends on DistUB + Expr *EUB; + /// Distribute loop iteration variable init used when composing 'omp + /// distribute' + /// with 'omp for' in a same construct + Expr *Init; + /// Distribute Loop condition used when composing 'omp distribute' + /// with 'omp for' in a same construct + Expr *Cond; + /// Update of LowerBound for statically sheduled omp loops for + /// outer loop in combined constructs (e.g. 'distribute parallel for') + Expr *NLB; + /// Update of UpperBound for statically sheduled omp loops for + /// outer loop in combined constructs (e.g. 'distribute parallel for') + Expr *NUB; + }; + /// \brief The expressions built for the OpenMP loop CodeGen for the /// whole collapsed loop nest. struct HelperExprs { @@ -611,6 +676,9 @@ public: /// Init statement for all captured expressions. Stmt *PreInits; + /// Expressions used when combining OpenMP loop pragmas + DistCombinedHelperExprs DistCombinedFields; + /// \brief Check if all the expressions are built (does not check the /// worksharing ones). bool builtAll() { @@ -654,6 +722,13 @@ public: Finals[i] = nullptr; } PreInits = nullptr; + DistCombinedFields.LB = nullptr; + DistCombinedFields.UB = nullptr; + DistCombinedFields.EUB = nullptr; + DistCombinedFields.Init = nullptr; + DistCombinedFields.Cond = nullptr; + DistCombinedFields.NLB = nullptr; + DistCombinedFields.NUB = nullptr; } }; @@ -757,37 +832,71 @@ public: *std::next(child_begin(), NumIterationsOffset))); } Expr *getPrevLowerBoundVariable() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevLowerBoundVariableOffset))); } Expr *getPrevUpperBoundVariable() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevUpperBoundVariableOffset))); } Expr *getDistInc() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), DistIncOffset))); } Expr *getPrevEnsureUpperBound() const { - assert((isOpenMPWorksharingDirective(getDirectiveKind()) || - isOpenMPTaskLoopDirective(getDirectiveKind()) || - isOpenMPDistributeDirective(getDirectiveKind())) && - "expected worksharing loop directive"); + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), PrevEnsureUpperBoundOffset))); } + Expr *getCombinedLowerBoundVariable() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedLowerBoundVariableOffset))); + } + Expr *getCombinedUpperBoundVariable() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedUpperBoundVariableOffset))); + } + Expr *getCombinedEnsureUpperBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedEnsureUpperBoundOffset))); + } + Expr *getCombinedInit() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedInitOffset))); + } + Expr *getCombinedCond() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedConditionOffset))); + } + Expr *getCombinedNextLowerBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedNextLowerBoundOffset))); + } + Expr *getCombinedNextUpperBound() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedNextUpperBoundOffset))); + } const Stmt *getBody() const { // This relies on the loop form is already checked by Sema. Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); @@ -1786,7 +1895,7 @@ public: } }; -/// \brief This represents '#pragma omp taskgroup' directive. +/// This represents '#pragma omp taskgroup' directive. /// /// \code /// #pragma omp taskgroup @@ -1794,39 +1903,61 @@ public: /// class OMPTaskgroupDirective : public OMPExecutableDirective { friend class ASTStmtReader; - /// \brief Build directive with the given start and end location. + /// 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. /// - OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc) + OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, - StartLoc, EndLoc, 0, 1) {} + StartLoc, EndLoc, NumClauses, 2) {} - /// \brief Build an empty directive. + /// Build an empty directive. + /// \param NumClauses Number of clauses. /// - explicit OMPTaskgroupDirective() + explicit OMPTaskgroupDirective(unsigned NumClauses) : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, - SourceLocation(), SourceLocation(), 0, 1) {} + SourceLocation(), SourceLocation(), NumClauses, + 2) {} + + /// Sets the task_reduction return variable. + void setReductionRef(Expr *RR) { + *std::next(child_begin(), 1) = RR; + } public: - /// \brief Creates directive. + /// Creates directive. /// /// \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 ReductionRef Reference to the task_reduction return variable. /// - static OMPTaskgroupDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - Stmt *AssociatedStmt); + static OMPTaskgroupDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + Expr *ReductionRef); - /// \brief Creates an empty directive. + /// Creates an empty directive. /// /// \param C AST context. + /// \param NumClauses Number of clauses. /// - static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell); + static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + + /// Returns reference to the task_reduction return variable. + const Expr *getReductionRef() const { + return static_cast<const Expr *>(*std::next(child_begin(), 1)); + } + Expr *getReductionRef() { + return static_cast<Expr *>(*std::next(child_begin(), 1)); + } static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTaskgroupDirectiveClass; diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index df4a2d8bc3..470788e8bb 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -29,15 +29,17 @@ template <typename T> struct make_const_ptr { typedef const T *type; }; /// StmtVisitorBase - This class implements a simple visitor for Stmt /// subclasses. Since Expr derives from Stmt, this also includes support for /// visiting Exprs. -template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void, + class... ParamTys> class StmtVisitorBase { public: #define PTR(CLASS) typename Ptr<CLASS>::type #define DISPATCH(NAME, CLASS) \ - return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S)) + return static_cast<ImplClass*>(this)->Visit ## NAME( \ + static_cast<PTR(CLASS)>(S), std::forward<ParamTys>(P)...) - RetTy Visit(PTR(Stmt) S) { + RetTy Visit(PTR(Stmt) S, ParamTys... P) { // If we have a binary expr, dispatch to the subcode of the binop. A smart // optimizer (e.g. LLVM) will fold this comparison into the switch stmt @@ -111,13 +113,13 @@ public: // If the implementation chooses not to implement a certain visit method, fall // back on VisitExpr or whatever else is the superclass. #define STMT(CLASS, PARENT) \ - RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); } + RetTy Visit ## CLASS(PTR(CLASS) S, ParamTys... P) { DISPATCH(PARENT, PARENT); } #include "clang/AST/StmtNodes.inc" // If the implementation doesn't implement binary operator methods, fall back // on VisitBinaryOperator. #define BINOP_FALLBACK(NAME) \ - RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \ + RetTy VisitBin ## NAME(PTR(BinaryOperator) S, ParamTys... P) { \ DISPATCH(BinaryOperator, BinaryOperator); \ } BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) @@ -137,7 +139,7 @@ public: // If the implementation doesn't implement compound assignment operator // methods, fall back on VisitCompoundAssignOperator. #define CAO_FALLBACK(NAME) \ - RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \ + RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S, ParamTys... P) { \ DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \ } CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) @@ -149,7 +151,7 @@ public: // If the implementation doesn't implement unary operator methods, fall back // on VisitUnaryOperator. #define UNARYOP_FALLBACK(NAME) \ - RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \ + RetTy VisitUnary ## NAME(PTR(UnaryOperator) S, ParamTys... P) { \ DISPATCH(UnaryOperator, UnaryOperator); \ } UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) @@ -163,7 +165,7 @@ public: #undef UNARYOP_FALLBACK // Base case, ignore it. :) - RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); } + RetTy VisitStmt(PTR(Stmt) Node, ParamTys... P) { return RetTy(); } #undef PTR #undef DISPATCH @@ -174,18 +176,18 @@ public: /// /// This class does not preserve constness of Stmt pointers (see also /// ConstStmtVisitor). -template<typename ImplClass, typename RetTy=void> +template<typename ImplClass, typename RetTy=void, typename... ParamTys> class StmtVisitor - : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {}; + : public StmtVisitorBase<make_ptr, ImplClass, RetTy, ParamTys...> {}; /// ConstStmtVisitor - This class implements a simple visitor for Stmt /// subclasses. Since Expr derives from Stmt, this also includes support for /// visiting Exprs. /// /// This class preserves constness of Stmt pointers (see also StmtVisitor). -template<typename ImplClass, typename RetTy=void> +template<typename ImplClass, typename RetTy=void, typename... ParamTys> class ConstStmtVisitor - : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {}; + : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy, ParamTys...> {}; /// \brief This class implements a simple visitor for OMPClause /// subclasses. diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index bf4d008ee8..45a610e638 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -262,6 +262,11 @@ public: TemplateName getUnderlying() const; + /// Get the template name to substitute when this template name is used as a + /// template template argument. This refers to the most recent declaration of + /// the template, including any default template arguments. + TemplateName getNameToSubstitute() const; + /// \brief Determines whether this is a dependent template name. bool isDependent() const; @@ -515,8 +520,7 @@ namespace llvm { /// \brief The clang::TemplateName class is effectively a pointer. template<> -class PointerLikeTypeTraits<clang::TemplateName> { -public: +struct PointerLikeTypeTraits<clang::TemplateName> { static inline void *getAsVoidPointer(clang::TemplateName TN) { return TN.getAsVoidPointer(); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9c1d110067..e1956473ac 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -48,10 +48,9 @@ namespace clang { namespace llvm { template <typename T> - class PointerLikeTypeTraits; + struct PointerLikeTypeTraits; template<> - class PointerLikeTypeTraits< ::clang::Type*> { - public: + struct PointerLikeTypeTraits< ::clang::Type*> { static inline void *getAsVoidPointer(::clang::Type *P) { return P; } static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); @@ -59,8 +58,7 @@ namespace llvm { enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template<> - class PointerLikeTypeTraits< ::clang::ExtQuals*> { - public: + struct PointerLikeTypeTraits< ::clang::ExtQuals*> { static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { return static_cast< ::clang::ExtQuals*>(P); @@ -164,8 +162,6 @@ public: FastMask = (1 << FastWidth) - 1 }; - Qualifiers() : Mask(0) {} - /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { @@ -332,15 +328,34 @@ public: } bool hasAddressSpace() const { return Mask & AddressSpaceMask; } - unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } - void setAddressSpace(unsigned space) { - assert(space <= MaxAddressSpace); + LangAS getAddressSpace() const { + return static_cast<LangAS>(Mask >> AddressSpaceShift); + } + bool hasTargetSpecificAddressSpace() const { + return isTargetAddressSpace(getAddressSpace()); + } + /// Get the address space attribute value to be printed by diagnostics. + unsigned getAddressSpaceAttributePrintValue() const { + auto Addr = getAddressSpace(); + // This function is not supposed to be used with language specific + // address spaces. If that happens, the diagnostic message should consider + // printing the QualType instead of the address space value. + assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); + if (Addr != LangAS::Default) + return toTargetAddressSpace(Addr); + // TODO: The diagnostic messages where Addr may be 0 should be fixed + // since it cannot differentiate the situation where 0 denotes the default + // address space or user specified __attribute__((address_space(0))). + return 0; + } + void setAddressSpace(LangAS space) { + assert((unsigned)space <= MaxAddressSpace); Mask = (Mask & ~AddressSpaceMask) | (((uint32_t) space) << AddressSpaceShift); } - void removeAddressSpace() { setAddressSpace(0); } - void addAddressSpace(unsigned space) { - assert(space); + void removeAddressSpace() { setAddressSpace(LangAS::Default); } + void addAddressSpace(LangAS space) { + assert(space != LangAS::Default); setAddressSpace(space); } @@ -524,7 +539,7 @@ private: // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| // |C R V|U|GCAttr|Lifetime|AddressSpace| - uint32_t Mask; + uint32_t Mask = 0; static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; @@ -619,7 +634,7 @@ class QualType { friend class QualifierCollector; public: - QualType() {} + QualType() = default; QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} @@ -755,6 +770,10 @@ public: /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; + /// Return true if this has unique object representations according to (C++17 + /// [meta.unary.prop]p9) + bool hasUniqueObjectRepresentations(const ASTContext &Context) const; + // Don't promise in the API that anything besides 'const' can be // easily added. @@ -992,7 +1011,7 @@ public: } /// Return the address space of this type. - inline unsigned getAddressSpace() const; + inline LangAS getAddressSpace() const; /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; @@ -1020,6 +1039,9 @@ public: return getQualifiers().hasStrongOrWeakObjCLifetime(); } + // true when Type is objc's weak and weak is enabled but ARC isn't. + bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; + enum DestructionKind { DK_none, DK_cxx_destructor, @@ -1096,6 +1118,8 @@ public: QualType getAtomicUnqualifiedType() const; private: + bool unionHasUniqueObjectRepresentations(const ASTContext& Context) const; + bool structHasUniqueObjectRepresentations(const ASTContext& Context) const; // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the // caller. @@ -1123,8 +1147,7 @@ template<> struct simplify_type< ::clang::QualType> { // Teach SmallPtrSet that QualType is "basically a pointer". template<> -class PointerLikeTypeTraits<clang::QualType> { -public: +struct PointerLikeTypeTraits<clang::QualType> { static inline void *getAsVoidPointer(clang::QualType P) { return P.getAsOpaquePtr(); } @@ -1215,7 +1238,7 @@ public: } bool hasAddressSpace() const { return Quals.hasAddressSpace(); } - unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + LangAS getAddressSpace() const { return Quals.getAddressSpace(); } const Type *getBaseType() const { return BaseType; } @@ -1379,7 +1402,7 @@ protected: /// Extra information which affects how the function is called, like /// regparm and the calling convention. - unsigned ExtInfo : 10; + unsigned ExtInfo : 11; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. @@ -1688,6 +1711,7 @@ public: bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. + bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type @@ -1732,6 +1756,7 @@ public: bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++11 std::nullptr_t bool isAlignValT() const; // C++17 std::align_val_t + bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ @@ -1991,10 +2016,11 @@ public: Optional<NullabilityKind> getNullability(const ASTContext &context) const; /// Determine whether the given type can have a nullability - /// specifier applied to it, i.e., if it is any kind of pointer type - /// or a dependent type that could instantiate to any kind of - /// pointer type. - bool canHaveNullability() const; + /// specifier applied to it, i.e., if it is any kind of pointer type. + /// + /// \param ResultIfUnknown The value to return if we don't yet know whether + /// this type can have nullability because it is dependent. + bool canHaveNullability(bool ResultIfUnknown = true) const; /// Retrieve the set of substitutions required when accessing a member /// of the Objective-C receiver type that is declared in the given context. @@ -2076,7 +2102,7 @@ public: : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), /*InstantiationDependent=*/(K == Dependent), /*VariablyModified=*/false, - /*Unexpanded paramter pack=*/false) { + /*Unexpanded parameter pack=*/false) { BuiltinTypeBits.Kind = K; } @@ -2724,6 +2750,49 @@ public: unsigned TypeQuals, Expr *E); }; +/// Represents an extended address space qualifier where the input address space +/// value is dependent. Non-dependent address spaces are not represented with a +/// special Type subclass; they are stored on an ExtQuals node as part of a QualType. +/// +/// For example: +/// \code +/// template<typename T, int AddrSpace> +/// class AddressSpace { +/// typedef T __attribute__((address_space(AddrSpace))) type; +/// } +/// \endcode +class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { + const ASTContext &Context; + Expr *AddrSpaceExpr; + QualType PointeeType; + SourceLocation loc; + + DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, + QualType can, Expr *AddrSpaceExpr, + SourceLocation loc); + + friend class ASTContext; + +public: + Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } + QualType getPointeeType() const { return PointeeType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentAddressSpace; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType PointeeType, Expr *AddrSpaceExpr); +}; + /// Represents an extended vector type where either the type or size is /// dependent. /// @@ -2924,19 +2993,23 @@ class FunctionType : public Type { // * AST read and write // * Codegen class ExtInfo { - // Feel free to rearrange or add bits, but if you go over 10, + // Feel free to rearrange or add bits, but if you go over 11, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|produces|regparm| - // |0 .. 4| 5 | 6 | 7 .. 9| + // | CC |noreturn|produces|nocallersavedregs|regparm| + // |0 .. 4| 5 | 6 | 7 |8 .. 10| // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; - enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), - RegParmOffset = 7 }; // Assumed to be the last field + enum { NoCallerSavedRegsMask = 0x80 }; + enum { + RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | + NoCallerSavedRegsMask), + RegParmOffset = 8 + }; // Assumed to be the last field uint16_t Bits; @@ -2947,13 +3020,13 @@ class FunctionType : public Type { public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, - bool producesResult) { - assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); - Bits = ((unsigned) cc) | - (noReturn ? NoReturnMask : 0) | - (producesResult ? ProducesResultMask : 0) | - (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult, bool noCallerSavedRegs) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); } // Constructor with all defaults. Use when for example creating a @@ -2966,6 +3039,7 @@ class FunctionType : public Type { bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = Bits >> RegParmOffset; @@ -2999,6 +3073,13 @@ class FunctionType : public Type { return ExtInfo(Bits & ~ProducesResultMask); } + ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { + if (noCallerSavedRegs) + return ExtInfo(Bits | NoCallerSavedRegsMask); + else + return ExtInfo(Bits & ~NoCallerSavedRegsMask); + } + ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | @@ -3118,6 +3199,7 @@ public: ABIMask = 0x0F, IsConsumed = 0x10, HasPassObjSize = 0x20, + IsNoEscape = 0x40, }; unsigned char Data; @@ -3158,6 +3240,19 @@ public: return Copy; } + bool isNoEscape() const { + return Data & IsNoEscape; + } + + ExtParameterInfo withIsNoEscape(bool NoEscape) const { + ExtParameterInfo Copy = *this; + if (NoEscape) + Copy.Data |= IsNoEscape; + else + Copy.Data &= ~IsNoEscape; + return Copy; + } + unsigned char getOpaqueValue() const { return Data; } static ExtParameterInfo getFromOpaqueValue(unsigned char data) { ExtParameterInfo result; @@ -3760,10 +3855,9 @@ public: return reinterpret_cast<RecordDecl*>(TagType::getDecl()); } - // FIXME: This predicate is a helper to QualType/Type. It needs to - // recursively check all fields for const-ness. If any field is declared - // const, it needs to return false. - bool hasConstFields() const { return false; } + /// Recursively check all fields in the record for const-ness. If any field + /// is declared const, return true. Otherwise, return false. + bool hasConstFields() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -3845,6 +3939,7 @@ public: attr_sptr, attr_uptr, attr_nonnull, + attr_ns_returns_retained, attr_nullable, attr_null_unspecified, attr_objc_kindof, @@ -5567,7 +5662,7 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { } /// Return the address space of this type. -inline unsigned QualType::getAddressSpace() const { +inline LangAS QualType::getAddressSpace() const { return getQualifiers().getAddressSpace(); } @@ -5746,6 +5841,9 @@ inline bool Type::isVectorType() const { inline bool Type::isExtVectorType() const { return isa<ExtVectorType>(CanonicalType); } +inline bool Type::isDependentAddressSpaceType() const { + return isa<DependentAddressSpaceType>(CanonicalType); +} inline bool Type::isObjCObjectPointerType() const { return isa<ObjCObjectPointerType>(CanonicalType); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 525f848a9f..283c421425 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1544,7 +1544,11 @@ class DependentSizedArrayTypeLoc : public InheritingConcreteTypeLoc<ArrayTypeLoc, DependentSizedArrayTypeLoc, DependentSizedArrayType> { - +public: + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + ArrayTypeLoc::initializeLocal(Context, Loc); + setSizeExpr(getTypePtr()->getSizeExpr()); + } }; class VariableArrayTypeLoc : @@ -1660,6 +1664,76 @@ private: } }; +struct DependentAddressSpaceLocInfo { + Expr *ExprOperand; + SourceRange OperandParens; + SourceLocation AttrLoc; +}; + +class DependentAddressSpaceTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, + DependentAddressSpaceTypeLoc, + DependentAddressSpaceType, + DependentAddressSpaceLocInfo> { + + public: + + /// The location of the attribute name, i.e. + /// int * __attribute__((address_space(11))) + /// ^~~~~~~~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// int * __attribute__((address_space(11))) + /// ^~ + Expr *getAttrExprOperand() const { + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + getLocalData()->ExprOperand = e; + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// int * __attribute__((address_space(11))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + SourceRange range(getAttrNameLoc()); + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + /// Returns the type before the address space attribute application + /// area. + /// int * __attribute__((address_space(11))) * + /// ^ ^ + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } + + TypeLoc getPointeeTypeLoc() const { + return this->getInnerTypeLoc(); + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(getTypePtr()->getAddrSpaceExpr()); + } +}; + //===----------------------------------------------------------------------===// // // All of these need proper implementations. diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 9d1d09e2cc..66697fa0d0 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -23,7 +23,7 @@ // NON_CANONICAL_TYPE(Class, Base) - A type that can show up // anywhere in the AST but will never be a part of a canonical // type. Clients that only need to deal with canonical types -// (ignoring, e.g., typedefs and other type alises used for +// (ignoring, e.g., typedefs and other type aliases used for // pretty-printing) can ignore these types. // // DEPENDENT_TYPE(Class, Base) - A type that will only show up @@ -73,6 +73,7 @@ TYPE(IncompleteArray, ArrayType) TYPE(VariableArray, ArrayType) DEPENDENT_TYPE(DependentSizedArray, ArrayType) DEPENDENT_TYPE(DependentSizedExtVector, Type) +DEPENDENT_TYPE(DependentAddressSpace, Type) TYPE(Vector, Type) TYPE(ExtVector, VectorType) ABSTRACT_TYPE(Function, Type) diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h index 392e544d90..fa64fae882 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -26,7 +26,7 @@ namespace clang { /// \brief Function object that provides a total ordering on QualType values. -struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> { +struct QualTypeOrdering { bool operator()(QualType T1, QualType T2) const { return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr()); } diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index 5cbcf51dd6..b0b71e4735 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -154,6 +154,28 @@ public: bool isRTTIKind() const { return isRTTIKind(getKind()); } + GlobalDecl getGlobalDecl() const { + assert(isUsedFunctionPointerKind() && + "GlobalDecl can be created only from virtual function"); + + auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl()); + switch (getKind()) { + case CK_FunctionPointer: + return GlobalDecl(getFunctionDecl()); + case CK_CompleteDtorPointer: + return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete); + case CK_DeletingDtorPointer: + return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting); + case CK_VCallOffset: + case CK_VBaseOffset: + case CK_OffsetToTop: + case CK_RTTI: + case CK_UnusedFunctionPointer: + llvm_unreachable("Only function pointers kinds"); + } + llvm_unreachable("Should already return"); + } + private: static bool isFunctionPointerKind(Kind ComponentKind) { return isUsedFunctionPointerKind(ComponentKind) || diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 6c1c8e4428..d1a582508a 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -1,4 +1,4 @@ -//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===// +//===- ASTMatchers.h - Structural query framework ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,7 +25,7 @@ // // For example, when we're interested in child classes of a certain class, we // would write: -// cxxRecordDecl(hasName("MyClass"), hasChild(id("child", recordDecl()))) +// cxxRecordDecl(hasName("MyClass"), has(id("child", recordDecl()))) // When the match is found via the MatchFinder, a user provided callback will // be called with a BoundNodes instance that contains a mapping from the // strings that we provided for the id(...) calls to the nodes that were @@ -46,13 +46,48 @@ #define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" +#include <cassert> +#include <cstddef> #include <iterator> +#include <limits> +#include <string> +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { @@ -78,7 +113,7 @@ public: /// \brief Type of mapping from binding identifiers to bound nodes. This type /// is an associative container with a key type of \c std::string and a value /// type of \c clang::ast_type_traits::DynTypedNode - typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap; + using IDToNodeMap = internal::BoundNodesMap::IDToNodeMap; /// \brief Retrieve mapping from binding identifiers to bound nodes. const IDToNodeMap &getMap() const { @@ -86,13 +121,13 @@ public: } private: + friend class internal::BoundNodesTreeBuilder; + /// \brief Create BoundNodes from a pre-filled map of bindings. BoundNodes(internal::BoundNodesMap &MyBoundNodes) : MyBoundNodes(MyBoundNodes) {} internal::BoundNodesMap MyBoundNodes; - - friend class internal::BoundNodesTreeBuilder; }; /// \brief If the provided matcher matches a node, binds the node to \c ID. @@ -107,13 +142,13 @@ internal::Matcher<T> id(StringRef ID, /// \brief Types of matchers for the top-level classes in the AST class /// hierarchy. /// @{ -typedef internal::Matcher<Decl> DeclarationMatcher; -typedef internal::Matcher<Stmt> StatementMatcher; -typedef internal::Matcher<QualType> TypeMatcher; -typedef internal::Matcher<TypeLoc> TypeLocMatcher; -typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher; -typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher; -typedef internal::Matcher<CXXCtorInitializer> CXXCtorInitializerMatcher; +using DeclarationMatcher = internal::Matcher<Decl>; +using StatementMatcher = internal::Matcher<Stmt>; +using TypeMatcher = internal::Matcher<QualType>; +using TypeLocMatcher = internal::Matcher<TypeLoc>; +using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>; +using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>; +using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>; /// @} /// \brief Matches any node. @@ -180,6 +215,16 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> /// matches "using Y = int", but not "typedef int X" const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl; +/// \brief Matches type alias template declarations. +/// +/// typeAliasTemplateDecl() matches +/// \code +/// template <typename T> +/// using Y = X<T>; +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl> + typeAliasTemplateDecl; + /// \brief Matches AST nodes that were expanded within the main-file. /// /// Example matches X but not Y @@ -572,6 +617,23 @@ AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>, InnerMatcher.matches(*Initializer, Finder, Builder)); } +/// \brief Matches the specialized template of a specialization declaration. +/// +/// Given +/// \code +/// tempalate<typename T> class A {}; +/// typedef A<int> B; +/// \endcode +/// classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl())) +/// matches 'B' with classTemplateDecl() matching the class template +/// declaration of 'A'. +AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate, + internal::Matcher<ClassTemplateDecl>, InnerMatcher) { + const ClassTemplateDecl* Decl = Node.getSpecializedTemplate(); + return (Decl != nullptr && + InnerMatcher.matches(*Decl, Finder, Builder)); +} + /// \brief Matches a declaration that has been implicitly added /// by the compiler (eg. implicit default/copy constructors). AST_MATCHER(Decl, isImplicit) { @@ -1118,6 +1180,91 @@ const internal::VariadicDynCastAllOfMatcher< Decl, ObjCInterfaceDecl> objcInterfaceDecl; +/// \brief Matches Objective-C implementation declarations. +/// +/// Example matches Foo +/// \code +/// @implementation Foo +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCImplementationDecl> objcImplementationDecl; + +/// \brief Matches Objective-C protocol declarations. +/// +/// Example matches FooDelegate +/// \code +/// @protocol FooDelegate +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCProtocolDecl> objcProtocolDecl; + +/// \brief Matches Objective-C category declarations. +/// +/// Example matches Foo (Additions) +/// \code +/// @interface Foo (Additions) +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCCategoryDecl> objcCategoryDecl; + +/// \brief Matches Objective-C category definitions. +/// +/// Example matches Foo (Additions) +/// \code +/// @implementation Foo (Additions) +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCCategoryImplDecl> objcCategoryImplDecl; + +/// \brief Matches Objective-C method declarations. +/// +/// Example matches both declaration and definition of -[Foo method] +/// \code +/// @interface Foo +/// - (void)method; +/// @end +/// +/// @implementation Foo +/// - (void)method {} +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCMethodDecl> objcMethodDecl; + +/// \brief Matches Objective-C instance variable declarations. +/// +/// Example matches _enabled +/// \code +/// @implementation Foo { +/// BOOL _enabled; +/// } +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCIvarDecl> objcIvarDecl; + +/// \brief Matches Objective-C property declarations. +/// +/// Example matches enabled +/// \code +/// @interface Foo +/// @property BOOL enabled; +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCPropertyDecl> objcPropertyDecl; + /// \brief Matches expressions that introduce cleanups to be run at the end /// of the sub-expression's evaluation. /// @@ -1150,6 +1297,20 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm, InnerMatcher.matches(*SyntForm, Finder, Builder)); } +/// \brief Matches C++ initializer list expressions. +/// +/// Given +/// \code +/// std::vector<int> a({ 1, 2, 3 }); +/// std::vector<int> b = { 4, 5 }; +/// int c[] = { 6, 7 }; +/// std::pair<int, int> d = { 8, 9 }; +/// \endcode +/// cxxStdInitializerListExpr() +/// matches "{ 1, 2, 3 }" and "{ 4, 5 }" +const internal::VariadicDynCastAllOfMatcher<Stmt, + CXXStdInitializerListExpr> cxxStdInitializerListExpr; + /// \brief Matches implicit initializers of init list expressions. /// /// Given @@ -1333,7 +1494,7 @@ const internal::VariadicDynCastAllOfMatcher< /// /// Example: Given /// \code -/// struct T {void func()}; +/// struct T {void func();}; /// T f(); /// void g(T); /// \endcode @@ -2060,23 +2221,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// \c b. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { - internal::DynTypedMatcher::VO_EachOf -}; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + eachOf = {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::DynTypedMatcher::VO_AnyOf -}; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + anyOf = {internal::DynTypedMatcher::VO_AnyOf}; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { - internal::DynTypedMatcher::VO_AllOf -}; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + allOf = {internal::DynTypedMatcher::VO_AllOf}; /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) /// @@ -2462,8 +2623,21 @@ const internal::VariadicOperatorMatcherFunc<1, 1> unless = { /// - for CXXConstructExpr, the declaration of the constructor /// - for CXXNewExpr, the declaration of the operator new /// -/// Also usable as Matcher<T> for any T supporting the getDecl() member -/// function. e.g. various subtypes of clang::Type and various expressions. +/// For type nodes, hasDeclaration will generally match the declaration of the +/// sugared type. Given +/// \code +/// class X {}; +/// typedef X Y; +/// Y y; +/// \endcode +/// in varDecl(hasType(hasDeclaration(decl()))) the decl will match the +/// typedefDecl. A common use case is to match the underlying, desugared type. +/// This can be achieved by using the hasUnqualifiedDesugaredType matcher: +/// \code +/// varDecl(hasType(hasUnqualifiedDesugaredType( +/// recordType(hasDeclaration(decl()))))) +/// \endcode +/// In this matcher, the decl will match the CXXRecordDecl of class X. /// /// Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, /// Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -2522,7 +2696,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>, /// \brief Matches on the receiver of an ObjectiveC Message expression. /// /// Example -/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *"))); +/// matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *"))); /// matches the [webView ...] message invocation. /// \code /// NSString *webViewJavaScript = ... @@ -2756,7 +2930,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, /// class A {}; /// using B = A; /// \endcode -/// The matcher type(hasUniqualifeidDesugaredType(recordType())) matches +/// The matcher type(hasUnqualifeidDesugaredType(recordType())) matches /// both B and A. AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>, InnerMatcher) { @@ -3150,7 +3324,7 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, /// with forField matching foo_ AST_MATCHER_P(CXXCtorInitializer, forField, internal::Matcher<FieldDecl>, InnerMatcher) { - const FieldDecl *NodeAsDecl = Node.getMember(); + const FieldDecl *NodeAsDecl = Node.getAnyMember(); return (NodeAsDecl != nullptr && InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); } @@ -3405,16 +3579,21 @@ AST_MATCHER_P(FunctionDecl, returns, return InnerMatcher.matches(Node.getReturnType(), Finder, Builder); } -/// \brief Matches extern "C" function declarations. +/// \brief Matches extern "C" function or variable declarations. /// /// Given: /// \code /// extern "C" void f() {} /// extern "C" { void g() {} } /// void h() {} +/// extern "C" int x = 1; +/// extern "C" int y = 2; +/// int z = 3; /// \endcode /// functionDecl(isExternC()) -/// matches the declaration of f and g, but not the declaration h +/// matches the declaration of f and g, but not the declaration of h. +/// varDecl(isExternC()) +/// matches the declaration of x and y, but not the declaration of z. AST_POLYMORPHIC_MATCHER(isExternC, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl)) { return Node.isExternC(); @@ -3719,14 +3898,30 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) { return Node.size() == N; } -/// \brief Matches literals that are equal to the given value. +/// \brief Matches literals that are equal to the given value of type ValueT. /// -/// Example matches true (matcher = cxxBoolLiteral(equals(true))) +/// Given /// \code -/// true +/// f('\0', false, 3.14, 42); /// \endcode +/// characterLiteral(equals(0)) +/// matches '\0' +/// cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0)) +/// match false +/// floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2)) +/// match 3.14 +/// integerLiteral(equals(42)) +/// matches 42 +/// +/// Note that you cannot directly match a negative numeric literal because the +/// minus sign is not part of the literal: It is a unary operator whose operand +/// is the positive numeric literal. Instead, you must use a unaryOperator() +/// matcher to match the minus sign: /// -/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>, +/// unaryOperator(hasOperatorName("-"), +/// hasUnaryOperand(integerLiteral(equals(13)))) +/// +/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>, /// Matcher<FloatingLiteral>, Matcher<IntegerLiteral> template <typename ValueT> internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT> @@ -3736,6 +3931,34 @@ equals(const ValueT &Value) { ValueT>(Value); } +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals, + AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral, + CXXBoolLiteralExpr, + IntegerLiteral), + bool, Value, 0) { + return internal::ValueEqualsMatcher<NodeType, ParamT>(Value) + .matchesNode(Node); +} + +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals, + AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral, + CXXBoolLiteralExpr, + IntegerLiteral), + unsigned, Value, 1) { + return internal::ValueEqualsMatcher<NodeType, ParamT>(Value) + .matchesNode(Node); +} + +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals, + AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral, + CXXBoolLiteralExpr, + FloatingLiteral, + IntegerLiteral), + double, Value, 2) { + return internal::ValueEqualsMatcher<NodeType, ParamT>(Value) + .matchesNode(Node); +} + /// \brief Matches the operator Name of operator expressions (binary or /// unary). /// @@ -3816,7 +4039,6 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand, /// \code /// int a = b ?: 1; /// \endcode - AST_POLYMORPHIC_MATCHER_P(hasSourceExpression, AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr, OpaqueValueExpr), @@ -4952,6 +5174,21 @@ AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType); /// and \c s. AST_TYPE_MATCHER(RecordType, recordType); +/// \brief Matches tag types (record and enum types). +/// +/// Given +/// \code +/// enum E {}; +/// class C {}; +/// +/// E e; +/// C c; +/// \endcode +/// +/// \c tagType() matches the type of the variable declarations of both \c e +/// and \c c. +AST_TYPE_MATCHER(TagType, tagType); + /// \brief Matches types specified with an elaborated type keyword or with a /// qualified name. /// @@ -5474,7 +5711,6 @@ AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>, return false; } - /// \brief Matches CUDA kernel call expression. /// /// Example matches, @@ -5485,7 +5721,6 @@ const internal::VariadicDynCastAllOfMatcher< Stmt, CUDAKernelCallExpr> cudaKernelCallExpr; - /// \brief Matches expressions that resolve to a null pointer constant, such as /// GNU's __null, C++11's nullptr, or C's NULL macro. /// @@ -5569,7 +5804,7 @@ AST_MATCHER(NamedDecl, hasExternalFormalLinkage) { return Node.hasExternalFormalLinkage(); } -} // end namespace ast_matchers -} // end namespace clang +} // namespace ast_matchers +} // namespace clang -#endif +#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index bc75e807ce..203575e689 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1,4 +1,4 @@ -//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===// +//===- ASTMatchersInternal.h - Structural query framework -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -38,23 +38,42 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ManagedStatic.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> #include <map> #include <string> +#include <tuple> +#include <type_traits> +#include <utility> #include <vector> namespace clang { + +class ASTContext; + namespace ast_matchers { class BoundNodes; @@ -158,7 +177,7 @@ public: /// Note that we're using std::map here, as for memoization: /// - we need a comparison operator /// - we need an assignment operator - typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap; + using IDToNodeMap = std::map<std::string, ast_type_traits::DynTypedNode>; const IDToNodeMap &getMap() const { return NodeMap; @@ -188,7 +207,7 @@ public: /// BoundNodesTree. class Visitor { public: - virtual ~Visitor() {} + virtual ~Visitor() = default; /// \brief Called multiple times during a single call to VisitMatches(...). /// @@ -248,7 +267,7 @@ class ASTMatchFinder; class DynMatcherInterface : public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> { public: - virtual ~DynMatcherInterface() {} + virtual ~DynMatcherInterface() = default; /// \brief Returns true if \p DynNode can be matched. /// @@ -317,26 +336,29 @@ public: /// \brief Takes ownership of the provided implementation pointer. template <typename T> DynTypedMatcher(MatcherInterface<T> *Implementation) - : AllowBind(false), - SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), + : SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), RestrictKind(SupportedKind), Implementation(Implementation) {} /// \brief Construct from a variadic function. enum VariadicOperator { /// \brief Matches nodes for which all provided matchers match. VO_AllOf, + /// \brief Matches nodes for which at least one of the provided matchers /// matches. VO_AnyOf, + /// \brief Matches nodes for which at least one of the provided matchers /// matches, but doesn't stop at the first match. VO_EachOf, + /// \brief Matches nodes that do not match the provided matcher. /// /// Uses the variadic matcher interface, but fails if /// InnerMatchers.size() != 1. VO_UnaryNot }; + static DynTypedMatcher constructVariadic(VariadicOperator Op, ast_type_traits::ASTNodeKind SupportedKind, @@ -382,7 +404,7 @@ public: /// include both in the ID to make it unique. /// /// \c MatcherIDType supports operator< and provides strict weak ordering. - typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType; + using MatcherIDType = std::pair<ast_type_traits::ASTNodeKind, uint64_t>; MatcherIDType getID() const { /// FIXME: Document the requirements this imposes on matcher /// implementations (no new() implementation_ during a Matches()). @@ -428,13 +450,12 @@ private: DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind, ast_type_traits::ASTNodeKind RestrictKind, IntrusiveRefCntPtr<DynMatcherInterface> Implementation) - : AllowBind(false), - SupportedKind(SupportedKind), - RestrictKind(RestrictKind), + : SupportedKind(SupportedKind), RestrictKind(RestrictKind), Implementation(std::move(Implementation)) {} - bool AllowBind; + bool AllowBind = false; ast_type_traits::ASTNodeKind SupportedKind; + /// \brief A potentially stricter node kind. /// /// It allows to perform implicit and dynamic cast of matchers without @@ -545,6 +566,7 @@ public: private: // For Matcher<T> <=> Matcher<U> conversions. template <typename U> friend class Matcher; + // For DynTypedMatcher::unconditionalConvertTo<T>. friend class DynTypedMatcher; @@ -618,8 +640,8 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, // Metafunction to determine if type T has a member called getDecl. template <typename Ty> class has_getDecl { - typedef char yes[1]; - typedef char no[2]; + using yes = char[1]; + using no = char[2]; template <typename Inner> static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr); @@ -728,48 +750,94 @@ public: } private: - /// \brief If getDecl exists as a member of U, returns whether the inner - /// matcher matches Node.getDecl(). - template <typename U> - bool matchesSpecialized( - const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, - typename std::enable_if<has_getDecl<U>::value, int>::type = 0) const { - return matchesDecl(Node.getDecl(), Finder, Builder); - } - - /// \brief Extracts the TagDecl of a QualType and returns whether the inner - /// matcher matches on it. + /// \brief Forwards to matching on the underlying type of the QualType. bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { if (Node.isNull()) return false; - if (auto *TD = Node->getAsTagDecl()) - return matchesDecl(TD, Finder, Builder); - else if (auto *TT = Node->getAs<TypedefType>()) - return matchesDecl(TT->getDecl(), Finder, Builder); - // Do not use getAs<TemplateTypeParmType> instead of the direct dyn_cast. - // Calling getAs will return the canonical type, but that type does not - // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is - // available, and using dyn_cast ensures that. - else if (auto *TTP = dyn_cast<TemplateTypeParmType>(Node.getTypePtr())) - return matchesDecl(TTP->getDecl(), Finder, Builder); - else if (auto *OCIT = Node->getAs<ObjCInterfaceType>()) - return matchesDecl(OCIT->getDecl(), Finder, Builder); - else if (auto *UUT = Node->getAs<UnresolvedUsingType>()) - return matchesDecl(UUT->getDecl(), Finder, Builder); - else if (auto *ICNT = Node->getAs<InjectedClassNameType>()) - return matchesDecl(ICNT->getDecl(), Finder, Builder); + return matchesSpecialized(*Node, Finder, Builder); + } + + /// \brief Finds the best declaration for a type and returns whether the inner + /// matcher matches on it. + bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + // DeducedType does not have declarations of its own, so
+ // match the deduced type instead. + const Type *EffectiveType = &Node; + if (const auto *S = dyn_cast<DeducedType>(&Node)) { + EffectiveType = S->getDeducedType().getTypePtrOrNull(); + if (!EffectiveType) + return false; + } + + // First, for any types that have a declaration, extract the declaration and + // match on it. + if (const auto *S = dyn_cast<TagType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) { + return matchesDecl(S->getInterface(), Finder, Builder); + } + + // A SubstTemplateTypeParmType exists solely to mark a type substitution + // on the instantiated template. As users usually want to match the + // template parameter on the uninitialized template, we can always desugar + // one level without loss of expressivness. + // For example, given: + // template<typename T> struct X { T t; } class A {}; X<A> a; + // The following matcher will match, which otherwise would not: + // fieldDecl(hasType(pointerType())). + if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) { + return matchesSpecialized(S->getReplacementType(), Finder, Builder); + } + + // For template specialization types, we want to match the template + // declaration, as long as the type is still dependent, and otherwise the + // declaration of the instantiated tag type. + if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) { + if (!S->isTypeAlias() && S->isSugared()) { + // If the template is non-dependent, we want to match the instantiated + // tag type. + // For example, given: + // template<typename T> struct X {}; X<int> a; + // The following matcher will match, which otherwise would not: + // templateSpecializationType(hasDeclaration(cxxRecordDecl())). + return matchesSpecialized(*S->desugar(), Finder, Builder); + } + // If the template is dependent or an alias, match the template + // declaration. + return matchesDecl(S->getTemplateName().getAsTemplateDecl(), Finder, + Builder); + } + + // FIXME: We desugar elaborated types. This makes the assumption that users + // do never want to match on whether a type is elaborated - there are + // arguments for both sides; for now, continue desugaring. + if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) { + return matchesSpecialized(S->desugar(), Finder, Builder); + } return false; } - /// \brief Gets the TemplateDecl from a TemplateSpecializationType - /// and returns whether the inner matches on it. - bool matchesSpecialized(const TemplateSpecializationType &Node, - ASTMatchFinder *Finder, + /// \brief Extracts the Decl the DeclRefExpr references and returns whether + /// the inner matcher matches on it. + bool matchesSpecialized(const DeclRefExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return matchesDecl(Node.getTemplateName().getAsTemplateDecl(), - Finder, Builder); + return matchesDecl(Node.getDecl(), Finder, Builder); } /// \brief Extracts the Decl of the callee of a CallExpr and returns whether @@ -811,6 +879,13 @@ private: return matchesDecl(Node.getLabel(), Finder, Builder); } + /// \brief Extracts the declaration of a LabelStmt and returns whether the + /// inner matcher matches on it. + bool matchesSpecialized(const LabelStmt &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getDecl(), Finder, Builder); + } + /// \brief Returns whether the inner matcher \c Node. Returns false if \c Node /// is \c NULL. bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder, @@ -863,6 +938,7 @@ public: enum TraversalKind { /// Will traverse any child nodes. TK_AsIs, + /// Will not traverse implicit casts and parentheses. TK_IgnoreImplicitCastsAndParentheses }; @@ -871,6 +947,7 @@ public: enum BindKind { /// Stop at the first match and only bind the first match. BK_First, + /// Create results for all combinations of bindings that match. BK_All }; @@ -879,11 +956,12 @@ public: enum AncestorMatchMode { /// All ancestors. AMM_All, + /// Direct parent only. AMM_ParentOnly }; - virtual ~ASTMatchFinder() {} + virtual ~ASTMatchFinder() = default; /// \brief Returns true if the given class is directly or indirectly derived /// from a base type matching \c base. @@ -906,7 +984,7 @@ public: std::is_base_of<TypeLoc, T>::value || std::is_base_of<QualType, T>::value, "unsupported type for recursive matching"); - return matchesChildOf(ast_type_traits::DynTypedNode::create(Node), + return matchesChildOf(ast_type_traits::DynTypedNode::create(Node), Matcher, Builder, Traverse, Bind); } @@ -969,17 +1047,17 @@ template <typename... Ts> struct TypeList {}; // Empty sentinel type list. template <typename T1, typename... Ts> struct TypeList<T1, Ts...> { /// \brief The first type on the list. - typedef T1 head; + using head = T1; /// \brief A sublist with the tail. ie everything but the head. /// /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the /// end of the list. - typedef TypeList<Ts...> tail; + using tail = TypeList<Ts...>; }; /// \brief The empty type list. -typedef TypeList<> EmptyTypeList; +using EmptyTypeList = TypeList<>; /// \brief Helper meta-function to determine if some type \c T is present or /// a parent type in the list. @@ -997,8 +1075,9 @@ struct TypeListContainsSuperOf<EmptyTypeList, T> { /// \brief A "type list" that contains all types. /// /// Useful for matchers like \c anything and \c unless. -typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, - QualType, Type, TypeLoc, CXXCtorInitializer> AllNodeBaseTypes; +using AllNodeBaseTypes = + TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, QualType, + Type, TypeLoc, CXXCtorInitializer>; /// \brief Helper meta-function to extract the argument out of a function of /// type void(Arg). @@ -1006,20 +1085,22 @@ typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, /// See AST_POLYMORPHIC_SUPPORTED_TYPES for details. template <class T> struct ExtractFunctionArgMeta; template <class T> struct ExtractFunctionArgMeta<void(T)> { - typedef T type; + using type = T; }; /// \brief Default type lists for ArgumentAdaptingMatcher matchers. -typedef AllNodeBaseTypes AdaptativeDefaultFromTypes; -typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, - TypeLoc, QualType> AdaptativeDefaultToTypes; +using AdaptativeDefaultFromTypes = AllNodeBaseTypes; +using AdaptativeDefaultToTypes = + TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, TypeLoc, + QualType>; /// \brief All types that are supported by HasDeclarationMatcher above. -typedef TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType, - InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr, - QualType, RecordType, TagType, TemplateSpecializationType, - TemplateTypeParmType, TypedefType, UnresolvedUsingType> - HasDeclarationSupportedTypes; +using HasDeclarationSupportedTypes = + TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType, + ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr, + MemberExpr, QualType, RecordType, TagType, + TemplateSpecializationType, TemplateTypeParmType, TypedefType, + UnresolvedUsingType>; /// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by /// "adapting" a \c To into a \c T. @@ -1043,7 +1124,7 @@ struct ArgumentAdaptingMatcherFunc { explicit Adaptor(const Matcher<T> &InnerMatcher) : InnerMatcher(InnerMatcher) {} - typedef ToTypes ReturnTypes; + using ReturnTypes = ToTypes; template <typename To> operator Matcher<To>() const { return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); @@ -1080,7 +1161,8 @@ template <template <typename T> class MatcherT, typename ReturnTypesF = void(AllNodeBaseTypes)> class PolymorphicMatcherWithParam0 { public: - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; + template <typename T> operator Matcher<T>() const { static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value, @@ -1097,7 +1179,7 @@ public: explicit PolymorphicMatcherWithParam1(const P1 &Param1) : Param1(Param1) {} - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; template <typename T> operator Matcher<T>() const { @@ -1118,7 +1200,7 @@ public: PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2) : Param1(Param1), Param2(Param2) {} - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; template <typename T> operator Matcher<T>() const { @@ -1137,8 +1219,8 @@ private: /// This is useful when a matcher syntactically requires a child matcher, /// but the context doesn't care. See for example: anything(). class TrueMatcher { - public: - typedef AllNodeBaseTypes ReturnTypes; +public: + using ReturnTypes = AllNodeBaseTypes; template <typename T> operator Matcher<T>() const { @@ -1184,7 +1266,6 @@ public: /// ChildT must be an AST base type. template <typename T, typename ChildT> class HasMatcher : public WrapperMatcherInterface<T> { - public: explicit HasMatcher(const Matcher<ChildT> &ChildMatcher) : HasMatcher::WrapperMatcherInterface(ChildMatcher) {} @@ -1278,7 +1359,7 @@ template<typename T> BindableMatcher<T> makeAllOfComposite( ArrayRef<const Matcher<T> *> InnerMatchers) { // For the size() == 0 case, we return a "true" matcher. - if (InnerMatchers.size() == 0) { + if (InnerMatchers.empty()) { return BindableMatcher<T>(TrueMatcher()); } // For the size() == 1 case, we simply return that one matcher. @@ -1287,7 +1368,8 @@ BindableMatcher<T> makeAllOfComposite( return BindableMatcher<T>(*InnerMatchers[0]); } - typedef llvm::pointee_iterator<const Matcher<T> *const *> PI; + using PI = llvm::pointee_iterator<const Matcher<T> *const *>; + std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()), PI(InnerMatchers.end())); return BindableMatcher<T>( @@ -1580,12 +1662,13 @@ template <typename InnerTBase, typename ReturnTypesF> class TypeTraversePolymorphicMatcher { private: - typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, - ReturnTypesF> Self; + using Self = TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, + ReturnTypesF>; + static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers); public: - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; explicit TypeTraversePolymorphicMatcher( ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) @@ -1612,6 +1695,7 @@ private: template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher { struct Wrapper { Wrapper() : M(Func()) {} + Matcher M; }; @@ -1657,6 +1741,7 @@ struct NotEqualsBoundNodePredicate { bool operator()(const internal::BoundNodesMap &Nodes) const { return Nodes.getNode(ID) != Node; } + std::string ID; ast_type_traits::DynTypedNode Node; }; @@ -1712,9 +1797,10 @@ CompoundStmtMatcher<StmtExpr>::get(const StmtExpr &Node) { return Node.getSubStmt(); } +} // namespace internal + +} // namespace ast_matchers -} // end namespace internal -} // end namespace ast_matchers -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h index 2c76ddaa07..908fa0db62 100644 --- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -76,7 +76,7 @@ public: ET_ParserInvalidToken = 106, ET_ParserMalformedBindExpr = 107, ET_ParserTrailingCode = 108, - ET_ParserUnsignedError = 109, + ET_ParserNumberError = 109, ET_ParserOverloadedType = 110 }; diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h index 76926f09db..e8fcf0a9d6 100644 --- a/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -1,4 +1,4 @@ -//===--- Parser.h - Matcher expression parser -----*- C++ -*-===// +//===- Parser.h - Matcher expression parser ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,7 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Simple matcher expression parser. /// @@ -19,8 +19,10 @@ /// \code /// Grammar for the expressions supported: /// <Expression> := <Literal> | <NamedValue> | <MatcherExpression> -/// <Literal> := <StringLiteral> | <Unsigned> +/// <Literal> := <StringLiteral> | <Boolean> | <Double> | <Unsigned> /// <StringLiteral> := "quoted string" +/// <Boolean> := true | false +/// <Double> := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+ /// <Unsigned> := [0-9]+ /// <NamedValue> := <Identifier> /// <MatcherExpression> := <Identifier>(<ArgumentList>) | @@ -28,24 +30,28 @@ /// <Identifier> := [a-zA-Z]+ /// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> /// \endcode -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H #define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H -#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/Dynamic/Registry.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" -#include "clang/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { namespace dynamic { +class Diagnostics; + /// \brief Matcher expression parser. class Parser { public: @@ -122,8 +128,8 @@ public: /// \brief Sema implementation that uses the matcher registry to process the /// tokens. class RegistrySema : public Parser::Sema { - public: - ~RegistrySema() override; + public: + ~RegistrySema() override; llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) override; @@ -141,7 +147,7 @@ public: getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; }; - typedef llvm::StringMap<VariantValue> NamedValueMap; + using NamedValueMap = llvm::StringMap<VariantValue>; /// \brief Parse a matcher expression. /// @@ -245,13 +251,14 @@ private: const NamedValueMap *const NamedValues; Diagnostics *const Error; - typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy; + using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>; + ContextStackTy ContextStack; std::vector<MatcherCompletion> Completions; }; -} // namespace dynamic -} // namespace ast_matchers -} // namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h index 7bba95dbff..277491250d 100644 --- a/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -1,4 +1,4 @@ -//===--- Registry.h - Matcher registry --------------------------*- C++ -*-===// +//===- Registry.h - Matcher registry ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,12 +6,12 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Registry of all known matchers. /// /// The registry provides a generic interface to construct any matcher by name. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H @@ -34,9 +34,9 @@ namespace internal { class MatcherDescriptor; -} // end namespace internal +} // namespace internal -typedef const internal::MatcherDescriptor *MatcherCtor; +using MatcherCtor = const internal::MatcherDescriptor *; struct MatcherCompletion { MatcherCompletion() = default; @@ -129,8 +129,8 @@ public: Diagnostics *Error); }; -} // end namespace dynamic -} // end namespace ast_matchers -} // end namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang #endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index 2c80b51373..f9efe0f16f 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -35,6 +35,8 @@ class ArgKind { public: enum Kind { AK_Matcher, + AK_Boolean, + AK_Double, AK_Unsigned, AK_String }; @@ -56,7 +58,7 @@ class ArgKind { /// \param To the requested destination type. /// /// \param Specificity value corresponding to the "specificity" of the - /// convertion. + /// conversion. bool isConvertibleTo(ArgKind To, unsigned *Specificity) const; bool operator<(const ArgKind &Other) const { @@ -182,7 +184,7 @@ public: /// \param Kind the requested destination type. /// /// \param Specificity value corresponding to the "specificity" of the - /// convertion. + /// conversion. bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity) const { if (Value) @@ -241,6 +243,8 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { /// copy/assignment. /// /// Supported types: +/// - \c bool +// - \c double /// - \c unsigned /// - \c llvm::StringRef /// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>) @@ -253,14 +257,29 @@ public: VariantValue &operator=(const VariantValue &Other); /// \brief Specific constructors for each supported type. + VariantValue(bool Boolean); + VariantValue(double Double); VariantValue(unsigned Unsigned); VariantValue(StringRef String); VariantValue(const VariantMatcher &Matchers); + /// \brief Constructs an \c unsigned value (disambiguation from bool). + VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {} + /// \brief Returns true iff this is not an empty value. explicit operator bool() const { return hasValue(); } bool hasValue() const { return Type != VT_Nothing; } + /// \brief Boolean value functions. + bool isBoolean() const; + bool getBoolean() const; + void setBoolean(bool Boolean); + + /// \brief Double value functions. + bool isDouble() const; + double getDouble() const; + void setDouble(double Double); + /// \brief Unsigned value functions. bool isUnsigned() const; unsigned getUnsigned() const; @@ -281,7 +300,7 @@ public: /// \param Kind the requested destination type. /// /// \param Specificity value corresponding to the "specificity" of the - /// convertion. + /// conversion. bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const; /// \brief Determines if the contained value can be converted to any kind @@ -290,7 +309,7 @@ public: /// \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 + /// conversion. It is the maximum specificity of all the possible /// conversions. bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const; @@ -303,6 +322,8 @@ private: /// \brief All supported value types. enum ValueType { VT_Nothing, + VT_Boolean, + VT_Double, VT_Unsigned, VT_String, VT_Matcher @@ -311,6 +332,8 @@ private: /// \brief All supported value types. union AllValues { unsigned Unsigned; + double Double; + bool Boolean; std::string *String; VariantMatcher *Matcher; }; diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h index c0fc02724f..5ba42b475c 100644 --- a/include/clang/Analysis/Analyses/Consumed.h +++ b/include/clang/Analysis/Analyses/Consumed.h @@ -19,7 +19,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceLocation.h" namespace clang { diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h index 1229f8a8ef..6cb161ab37 100644 --- a/include/clang/Analysis/Analyses/Dominators.h +++ b/include/clang/Analysis/Analyses/Dominators.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H #define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/Support/GenericDomTree.h" @@ -38,15 +38,15 @@ typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode; class DominatorTree : public ManagedAnalysis { virtual void anchor(); public: - llvm::DominatorTreeBase<CFGBlock>* DT; + llvm::DomTreeBase<CFGBlock>* DT; DominatorTree() { - DT = new llvm::DominatorTreeBase<CFGBlock>(false); + DT = new llvm::DomTreeBase<CFGBlock>(); } ~DominatorTree() override { delete DT; } - llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; } + llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; } /// \brief This method returns the root CFGBlock of the dominators tree. /// diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 8db4b0a58f..6a1222386b 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H #include "clang/AST/Decl.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "llvm/ADT/ImmutableSet.h" namespace clang { diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h index a1c6504275..c0a9352837 100644 --- a/include/clang/Analysis/Analyses/PostOrderCFGView.h +++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -21,7 +21,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/BitVector.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" namespace clang { diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index 22694a7a22..7e403b1f40 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -19,7 +19,7 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringRef.h" diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 8c1d1da554..414645b723 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -25,7 +25,7 @@ #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/OperatorKinds.h" #include <memory> #include <ostream> diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index be8a7105d7..17351622fb 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -909,15 +909,10 @@ class Project : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } - Project(SExpr *R, StringRef SName) - : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr) - { } Project(SExpr *R, const clang::ValueDecl *Cvd) - : SExpr(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd) - { } - Project(const Project &P, SExpr *R) - : SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl) - { } + : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) { + assert(Cvd && "ValueDecl must not be null"); + } SExpr *record() { return Rec; } const SExpr *record() const { return Rec; } @@ -931,10 +926,14 @@ public: } StringRef slotName() const { - if (Cvdecl) + if (Cvdecl->getDeclName().isIdentifier()) return Cvdecl->getName(); - else - return SlotName; + if (!SlotName) { + SlotName = ""; + llvm::raw_string_ostream OS(*SlotName); + Cvdecl->printName(OS); + } + return *SlotName; } template <class V> @@ -953,7 +952,7 @@ public: private: SExpr* Rec; - StringRef SlotName; + mutable llvm::Optional<std::string> SlotName; const clang::ValueDecl *Cvdecl; }; diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisDeclContext.h index f6a47d646d..03ff4a9516 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisDeclContext.h @@ -1,4 +1,4 @@ -//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// +//=== AnalysisDeclContext.h - Analysis context for Path Sens analysis --*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -12,10 +12,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H -#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H #include "clang/AST/Decl.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CodeInjector.h" #include "llvm/ADT/DenseMap.h" @@ -416,22 +417,25 @@ class AnalysisDeclContextManager { /// Pointer to an interface that can provide function bodies for /// declarations from external source. std::unique_ptr<CodeInjector> Injector; - + + /// A factory for creating and caching implementations for common + /// methods during the analysis. + BodyFarm FunctionBodyFarm; + /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. bool SynthesizeBodies; public: - AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, bool addImplicitDtors = false, bool addInitializers = false, bool addTemporaryDtors = false, + bool addLifetime = false, bool addLoopExit = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, - CodeInjector* injector = nullptr); - - ~AnalysisDeclContextManager(); + CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); @@ -470,6 +474,9 @@ public: return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); } + /// Get a reference to {@code BodyFarm} instance. + BodyFarm &getBodyFarm(); + /// Discard all previously created AnalysisDeclContexts. void clear(); diff --git a/include/clang/Analysis/BodyFarm.h b/include/clang/Analysis/BodyFarm.h new file mode 100644 index 0000000000..ff0859bc66 --- /dev/null +++ b/include/clang/Analysis/BodyFarm.h @@ -0,0 +1,54 @@ +//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// BodyFarm is a factory for creating faux implementations for functions/methods +// for analysis purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H +#define LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H + +#include "clang/AST/DeclBase.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + +class ASTContext; +class FunctionDecl; +class ObjCMethodDecl; +class ObjCPropertyDecl; +class Stmt; +class CodeInjector; + +class BodyFarm { +public: + BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {} + + /// Factory method for creating bodies for ordinary functions. + Stmt *getBody(const FunctionDecl *D); + + /// Factory method for creating bodies for Objective-C properties. + Stmt *getBody(const ObjCMethodDecl *D); + + /// Remove copy constructor to avoid accidental copying. + BodyFarm(const BodyFarm &other) = delete; + +private: + typedef llvm::DenseMap<const Decl *, Optional<Stmt *>> BodyMap; + + ASTContext &C; + BodyMap Bodies; + CodeInjector *Injector; +}; +} // namespace clang + +#endif diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index d23ed77ded..8cdd782671 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -58,6 +58,8 @@ public: Statement, Initializer, NewAllocator, + LifetimeEnds, + LoopExit, // dtor kind AutomaticObjectDtor, DeleteDtor, @@ -167,6 +169,51 @@ private: } }; +/// Represents the point where a loop ends. +/// This element is is only produced when building the CFG for the static +/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag. +/// +/// Note: a loop exit element can be reached even when the loop body was never +/// entered. +class CFGLoopExit : public CFGElement { +public: + explicit CFGLoopExit(const Stmt *stmt) + : CFGElement(LoopExit, stmt) {} + + const Stmt *getLoopStmt() const { + return static_cast<Stmt *>(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGLoopExit() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == LoopExit; + } +}; + +/// Represents the point where the lifetime of an automatic object ends +class CFGLifetimeEnds : public CFGElement { +public: + explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt) + : CFGElement(LifetimeEnds, var, stmt) {} + + const VarDecl *getVarDecl() const { + return static_cast<VarDecl *>(Data1.getPointer()); + } + + const Stmt *getTriggerStmt() const { + return static_cast<Stmt *>(Data2.getPointer()); + } + +private: + friend class CFGElement; + CFGLifetimeEnds() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == LifetimeEnds; + } +}; + /// CFGImplicitDtor - Represents C++ object destructor implicitly generated /// by compiler on various occasions. class CFGImplicitDtor : public CFGElement { @@ -701,6 +748,14 @@ public: Elements.push_back(CFGAutomaticObjDtor(VD, S), C); } + void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) { + Elements.push_back(CFGLifetimeEnds(VD, S), C); + } + + void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) { + Elements.push_back(CFGLoopExit(LoopStmt), C); + } + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { Elements.push_back(CFGDeleteDtor(RD, DE), C); } @@ -717,6 +772,19 @@ public: *I = CFGAutomaticObjDtor(VD, S); return ++I; } + + // Scope leaving must be performed in reversed order. So insertion is in two + // steps. First we prepare space for some number of elements, then we insert + // the elements beginning at the last position in prepared space. + iterator beginLifetimeEndsInsert(iterator I, size_t Cnt, + BumpVectorContext &C) { + return iterator( + Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C)); + } + iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) { + *I = CFGLifetimeEnds(VD, S); + return ++I; + } }; /// \brief CFGCallback defines methods that should be called when a logical @@ -753,6 +821,8 @@ public: bool AddEHEdges; bool AddInitializers; bool AddImplicitDtors; + bool AddLifetime; + bool AddLoopExit; bool AddTemporaryDtors; bool AddStaticInitBranches; bool AddCXXNewAllocator; @@ -774,8 +844,10 @@ public: BuildOptions() : forcedBlkExprs(nullptr), Observer(nullptr), - PruneTriviallyFalseEdges(true), AddEHEdges(false), + PruneTriviallyFalseEdges(true), + AddEHEdges(false), AddInitializers(false), AddImplicitDtors(false), + AddLifetime(false), AddLoopExit(false), AddTemporaryDtors(false), AddStaticInitBranches(false), AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} }; diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h index 51cad7a96d..051b923665 100644 --- a/include/clang/Analysis/CloneDetection.h +++ b/include/clang/Analysis/CloneDetection.h @@ -7,18 +7,16 @@ // //===----------------------------------------------------------------------===// /// -/// /file -/// This file defines classes for searching and anlyzing source code clones. +/// \file +/// This file defines classes for searching and analyzing source code clones. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_CLONEDETECTION_H #define LLVM_CLANG_AST_CLONEDETECTION_H -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/ADT/StringMap.h" - +#include "clang/AST/StmtVisitor.h" +#include "llvm/Support/Regex.h" #include <vector> namespace clang { @@ -29,7 +27,7 @@ class VarDecl; class ASTContext; class CompoundStmt; -/// \brief Identifies a list of statements. +/// Identifies a list of statements. /// /// Can either identify a single arbitrary Stmt object, a continuous sequence of /// child statements inside a CompoundStmt or no statements at all. @@ -39,8 +37,8 @@ class StmtSequence { /// Stmt, then S is a pointer to this Stmt. const Stmt *S; - /// The related ASTContext for S. - ASTContext *Context; + /// The declaration that contains the statements. + const Decl *D; /// If EndIndex is non-zero, then S is a CompoundStmt and this StmtSequence /// instance is representing the CompoundStmt children inside the array @@ -49,7 +47,7 @@ class StmtSequence { unsigned EndIndex; public: - /// \brief Constructs a StmtSequence holding multiple statements. + /// Constructs a StmtSequence holding multiple statements. /// /// The resulting StmtSequence identifies a continuous sequence of statements /// in the body of the given CompoundStmt. Which statements of the body should @@ -57,20 +55,20 @@ public: /// that describe a non-empty sub-array in the body of the given CompoundStmt. /// /// \param Stmt A CompoundStmt that contains all statements in its body. - /// \param Context The ASTContext for the given CompoundStmt. + /// \param D The Decl containing this Stmt. /// \param StartIndex The inclusive start index in the children array of /// \p Stmt /// \param EndIndex The exclusive end index in the children array of \p Stmt. - StmtSequence(const CompoundStmt *Stmt, ASTContext &Context, - unsigned StartIndex, unsigned EndIndex); + StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex, + unsigned EndIndex); - /// \brief Constructs a StmtSequence holding a single statement. + /// Constructs a StmtSequence holding a single statement. /// /// \param Stmt An arbitrary Stmt. - /// \param Context The ASTContext for the given Stmt. - StmtSequence(const Stmt *Stmt, ASTContext &Context); + /// \param D The Decl containing this Stmt. + StmtSequence(const Stmt *Stmt, const Decl *D); - /// \brief Constructs an empty StmtSequence. + /// Constructs an empty StmtSequence. StmtSequence(); typedef const Stmt *const *iterator; @@ -110,9 +108,12 @@ public: bool empty() const { return size() == 0; } /// Returns the related ASTContext for the stored Stmts. - ASTContext &getASTContext() const { - assert(Context); - return *Context; + ASTContext &getASTContext() const; + + /// Returns the declaration that contains the stored Stmts. + const Decl *getContainingDecl() const { + assert(D); + return D; } /// Returns true if this objects holds a list of statements. @@ -150,106 +151,244 @@ public: bool contains(const StmtSequence &Other) const; }; -/// \brief Searches for clones in source code. +/// Searches for similar subtrees in the AST. +/// +/// First, this class needs several declarations with statement bodies which +/// can be passed via analyzeCodeBody. Afterwards all statements can be +/// searched for clones by calling findClones with a given list of constraints +/// that should specify the wanted properties of the clones. /// -/// First, this class needs a translation unit which is passed via -/// \p analyzeTranslationUnit . It will then generate and store search data -/// for all statements inside the given translation unit. -/// Afterwards the generated data can be used to find code clones by calling -/// \p findClones . +/// The result of findClones can be further constrained with the constrainClones +/// method. /// /// This class only searches for clones in exectuable source code /// (e.g. function bodies). Other clones (e.g. cloned comments or declarations) /// are not supported. class CloneDetector { + public: - typedef unsigned DataPiece; - - /// Holds the data about a StmtSequence that is needed during the search for - /// code clones. - struct CloneSignature { - /// \brief The hash code of the StmtSequence. - /// - /// The initial clone groups that are formed during the search for clones - /// consist only of Sequences that share the same hash code. This makes this - /// value the central part of this heuristic that is needed to find clones - /// in a performant way. For this to work, the type of this variable - /// always needs to be small and fast to compare. - /// - /// Also, StmtSequences that are clones of each others have to share - /// the same hash code. StmtSequences that are not clones of each other - /// shouldn't share the same hash code, but if they do, it will only - /// degrade the performance of the hash search but doesn't influence - /// the correctness of the result. - size_t Hash; - - /// \brief The complexity of the StmtSequence. - /// - /// This value gives an approximation on how many direct or indirect child - /// statements are contained in the related StmtSequence. In general, the - /// greater this value, the greater the amount of statements. However, this - /// is only an approximation and the actual amount of statements can be - /// higher or lower than this value. Statements that are generated by the - /// compiler (e.g. macro expansions) for example barely influence the - /// complexity value. - /// - /// The main purpose of this value is to filter clones that are too small - /// and therefore probably not interesting enough for the user. - unsigned Complexity; - - /// \brief Creates an empty CloneSignature without any data. - CloneSignature() : Complexity(1) {} - - CloneSignature(llvm::hash_code Hash, unsigned Complexity) - : Hash(Hash), Complexity(Complexity) {} - }; + /// A collection of StmtSequences that share an arbitrary property. + typedef llvm::SmallVector<StmtSequence, 8> CloneGroup; - /// Holds group of StmtSequences that are clones of each other and the - /// complexity value (see CloneSignature::Complexity) that all stored - /// StmtSequences have in common. - struct CloneGroup { - std::vector<StmtSequence> Sequences; - CloneSignature Signature; + /// Generates and stores search data for all statements in the body of + /// the given Decl. + void analyzeCodeBody(const Decl *D); - CloneGroup() {} + /// Constrains the given list of clone groups with the given constraint. + /// + /// The constraint is expected to have a method with the signature + /// `void constrain(std::vector<CloneDetector::CloneGroup> &Sequences)` + /// as this is the interface that the CloneDetector uses for applying the + /// constraint. The constraint is supposed to directly modify the passed list + /// so that all clones in the list fulfill the specific property this + /// constraint ensures. + template <typename T> + static void constrainClones(std::vector<CloneGroup> &CloneGroups, T C) { + C.constrain(CloneGroups); + } - CloneGroup(const StmtSequence &Seq, CloneSignature Signature) - : Signature(Signature) { - Sequences.push_back(Seq); - } + /// Constrains the given list of clone groups with the given list of + /// constraints. + /// + /// The constraints are applied in sequence in the order in which they are + /// passed to this function. + template <typename T1, typename... Ts> + static void constrainClones(std::vector<CloneGroup> &CloneGroups, T1 C, + Ts... ConstraintList) { + constrainClones(CloneGroups, C); + constrainClones(CloneGroups, ConstraintList...); + } - /// \brief Returns false if and only if this group should be skipped when - /// searching for clones. - bool isValid() const { - // A clone group with only one member makes no sense, so we skip them. - return Sequences.size() > 1; + /// Searches for clones in all previously passed statements. + /// \param Result Output parameter to which all created clone groups are + /// added. + /// \param ConstraintList The constraints that should be applied to the + // result. + template <typename... Ts> + void findClones(std::vector<CloneGroup> &Result, Ts... ConstraintList) { + // The initial assumption is that there is only one clone group and every + // statement is a clone of the others. This clone group will then be + // split up with the help of the constraints. + CloneGroup AllClones; + AllClones.reserve(Sequences.size()); + for (const auto &C : Sequences) { + AllClones.push_back(C); } + + Result.push_back(AllClones); + + constrainClones(Result, ConstraintList...); + } + +private: + CloneGroup Sequences; +}; + +/// This class is a utility class that contains utility functions for building +/// custom constraints. +class CloneConstraint { +public: + /// Removes all groups by using a filter function. + /// \param CloneGroups The list of CloneGroups that is supposed to be + /// filtered. + /// \param Filter The filter function that should return true for all groups + /// that should be removed from the list. + static void filterGroups( + std::vector<CloneDetector::CloneGroup> &CloneGroups, + llvm::function_ref<bool(const CloneDetector::CloneGroup &)> Filter) { + CloneGroups.erase( + std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter), + CloneGroups.end()); + } + + /// Splits the given CloneGroups until the given Compare function returns true + /// for all clones in a single group. + /// \param CloneGroups A list of CloneGroups that should be modified. + /// \param Compare The comparison function that all clones are supposed to + /// pass. Should return true if and only if two clones belong + /// to the same CloneGroup. + static void splitCloneGroups( + std::vector<CloneDetector::CloneGroup> &CloneGroups, + llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)> + Compare); +}; + +/// This constraint moves clones into clone groups of type II via hashing. +/// +/// Clones with different hash values are moved into separate clone groups. +/// Collisions are possible, and this constraint does nothing to address this +/// them. Add the slower RecursiveCloneTypeIIVerifyConstraint later in the +/// constraint chain, not necessarily immediately, to eliminate hash collisions +/// through a more detailed analysis. +class RecursiveCloneTypeIIHashConstraint { +public: + void constrain(std::vector<CloneDetector::CloneGroup> &Sequences); +}; + +/// This constraint moves clones into clone groups of type II by comparing them. +/// +/// Clones that aren't type II clones are moved into separate clone groups. +/// In contrast to the RecursiveCloneTypeIIHashConstraint, all clones in a clone +/// group are guaranteed to be be type II clones of each other, but it is too +/// slow to efficiently handle large amounts of clones. +class RecursiveCloneTypeIIVerifyConstraint { +public: + void constrain(std::vector<CloneDetector::CloneGroup> &Sequences); +}; + +/// Ensures that every clone has at least the given complexity. +/// +/// Complexity is here defined as the total amount of children of a statement. +/// This constraint assumes the first statement in the group is representative +/// for all other statements in the group in terms of complexity. +class MinComplexityConstraint { + unsigned MinComplexity; + +public: + MinComplexityConstraint(unsigned MinComplexity) + : MinComplexity(MinComplexity) {} + + /// Calculates the complexity of the given StmtSequence. + /// \param Limit The limit of complexity we probe for. After reaching + /// this limit during calculation, this method is exiting + /// early to improve performance and returns this limit. + size_t calculateStmtComplexity(const StmtSequence &Seq, std::size_t Limit, + const std::string &ParentMacroStack = ""); + + void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) { + CloneConstraint::filterGroups( + CloneGroups, [this](const CloneDetector::CloneGroup &A) { + if (!A.empty()) + return calculateStmtComplexity(A.front(), MinComplexity) < + MinComplexity; + else + return false; + }); + } +}; + +/// Ensures that all clone groups contain at least the given amount of clones. +class MinGroupSizeConstraint { + unsigned MinGroupSize; + +public: + MinGroupSizeConstraint(unsigned MinGroupSize = 2) + : MinGroupSize(MinGroupSize) {} + + void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) { + CloneConstraint::filterGroups(CloneGroups, + [this](const CloneDetector::CloneGroup &A) { + return A.size() < MinGroupSize; + }); + } +}; + +/// Ensures that no clone group fully contains another clone group. +struct OnlyLargestCloneConstraint { + void constrain(std::vector<CloneDetector::CloneGroup> &Result); +}; + +struct FilenamePatternConstraint { + StringRef IgnoredFilesPattern; + std::shared_ptr<llvm::Regex> IgnoredFilesRegex; + + FilenamePatternConstraint(StringRef IgnoredFilesPattern) + : IgnoredFilesPattern(IgnoredFilesPattern) { + IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" + + IgnoredFilesPattern.str() + "$)"); + } + + bool isAutoGenerated(const CloneDetector::CloneGroup &Group); + + void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) { + CloneConstraint::filterGroups( + CloneGroups, [this](const CloneDetector::CloneGroup &Group) { + return isAutoGenerated(Group); + }); + } +}; + +/// Analyzes the pattern of the referenced variables in a statement. +class VariablePattern { + + /// Describes an occurence of a variable reference in a statement. + struct VariableOccurence { + /// The index of the associated VarDecl in the Variables vector. + size_t KindID; + /// The statement in the code where the variable was referenced. + const Stmt *Mention; + + VariableOccurence(size_t KindID, const Stmt *Mention) + : KindID(KindID), Mention(Mention) {} }; - /// \brief Generates and stores search data for all statements in the body of - /// the given Decl. - void analyzeCodeBody(const Decl *D); + /// All occurences of referenced variables in the order of appearance. + std::vector<VariableOccurence> Occurences; + /// List of referenced variables in the order of appearance. + /// Every item in this list is unique. + std::vector<const VarDecl *> Variables; - /// \brief Stores the CloneSignature to allow future querying. - void add(const StmtSequence &S, const CloneSignature &Signature); + /// Adds a new variable referenced to this pattern. + /// \param VarDecl The declaration of the variable that is referenced. + /// \param Mention The SourceRange where this variable is referenced. + void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention); - /// \brief Searches the provided statements for clones. - /// - /// \param Result Output parameter that is filled with a list of found - /// clone groups. Each group contains multiple StmtSequences - /// that were identified to be clones of each other. - /// \param MinGroupComplexity Only return clones which have at least this - /// complexity value. - /// \param CheckPatterns Returns only clone groups in which the referenced - /// variables follow the same pattern. - void findClones(std::vector<CloneGroup> &Result, unsigned MinGroupComplexity, - bool CheckPatterns = true); - - /// \brief Describes two clones that reference their variables in a different - /// pattern which could indicate a programming error. + /// Adds each referenced variable from the given statement. + void addVariables(const Stmt *S); + +public: + /// Creates an VariablePattern object with information about the given + /// StmtSequence. + VariablePattern(const StmtSequence &Sequence) { + for (const Stmt *S : Sequence) + addVariables(S); + } + + /// Describes two clones that reference their variables in a different pattern + /// which could indicate a programming error. struct SuspiciousClonePair { - /// \brief Utility class holding the relevant information about a single - /// clone in this pair. + /// Utility class holding the relevant information about a single + /// clone in this pair. struct SuspiciousCloneInfo { /// The variable which referencing in this clone was against the pattern. const VarDecl *Variable; @@ -270,17 +409,37 @@ public: SuspiciousCloneInfo SecondCloneInfo; }; - /// \brief Searches the provided statements for pairs of clones that don't - /// follow the same pattern when referencing variables. - /// \param Result Output parameter that will contain the clone pairs. - /// \param MinGroupComplexity Only clone pairs in which the clones have at - /// least this complexity value. - void findSuspiciousClones(std::vector<SuspiciousClonePair> &Result, - unsigned MinGroupComplexity); + /// Counts the differences between this pattern and the given one. + /// \param Other The given VariablePattern to compare with. + /// \param FirstMismatch Output parameter that will be filled with information + /// about the first difference between the two patterns. This parameter + /// can be a nullptr, in which case it will be ignored. + /// \return Returns the number of differences between the pattern this object + /// is following and the given VariablePattern. + /// + /// For example, the following statements all have the same pattern and this + /// function would return zero: + /// + /// if (a < b) return a; return b; + /// if (x < y) return x; return y; + /// if (u2 < u1) return u2; return u1; + /// + /// But the following statement has a different pattern (note the changed + /// variables in the return statements) and would have two differences when + /// compared with one of the statements above. + /// + /// if (a < b) return b; return a; + /// + /// This function should only be called if the related statements of the given + /// pattern and the statements of this objects are clones of each other. + unsigned countPatternDifferences( + const VariablePattern &Other, + VariablePattern::SuspiciousClonePair *FirstMismatch = nullptr); +}; -private: - /// Stores all encountered StmtSequences alongside their CloneSignature. - std::vector<std::pair<CloneSignature, StmtSequence>> Sequences; +/// Ensures that all clones reference variables in the same pattern. +struct MatchingVariablePatternConstraint { + void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups); }; } // end namespace clang diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index be5adfb294..2d59dec48a 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H #define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -83,6 +83,7 @@ public: PostImplicitCallKind, MinImplicitCallKind = PreImplicitCallKind, MaxImplicitCallKind = PostImplicitCallKind, + LoopExitKind, EpsilonKind}; private: @@ -654,6 +655,29 @@ private: } }; +/// Represents a point when we exit a loop. +/// When this ProgramPoint is encountered we can be sure that the symbolic +/// execution of the corresponding LoopStmt is finished on the given path. +/// Note: It is possible to encounter a LoopExit element when we haven't even +/// encountered the loop itself. At the current state not all loop exits will +/// result in a LoopExit program point. +class LoopExit : public ProgramPoint { +public: + LoopExit(const Stmt *LoopStmt, const LocationContext *LC) + : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {} + + const Stmt *getLoopStmt() const { + return static_cast<const Stmt *>(getData1()); + } + +private: + friend class ProgramPoint; + LoopExit() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == LoopExitKind; + } +}; + /// This is a meta program point, which should be skipped by all the diagnostic /// reasoning etc. class EpsilonPoint : public ProgramPoint { diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h index 63df61bedb..6b0090813e 100644 --- a/include/clang/Basic/AddressSpaces.h +++ b/include/clang/Basic/AddressSpaces.h @@ -16,36 +16,59 @@ #ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H #define LLVM_CLANG_BASIC_ADDRESSSPACES_H -namespace clang { +#include <assert.h> -namespace LangAS { +namespace clang { -/// \brief Defines the set of possible language-specific address spaces. +/// \brief Defines the address space values used by the address space qualifier +/// of QualType. /// -/// This uses a high starting offset so as not to conflict with any address -/// space used by a target. -enum ID { - Offset = 0x7FFF00, +enum class LangAS : unsigned { + // The default value 0 is the value used in QualType for the the situation + // where there is no address space qualifier. + Default = 0, - opencl_global = Offset, + // OpenCL specific address spaces. + // In OpenCL each l-value must have certain non-default address space, each + // r-value must have no address space (i.e. the default address space). The + // pointee of a pointer must have non-default address space. + opencl_global, opencl_local, opencl_constant, + opencl_private, opencl_generic, + // CUDA specific address spaces. cuda_device, cuda_constant, cuda_shared, - Last, - Count = Last-Offset + // This denotes the count of language-specific address spaces and also + // the offset added to the target-specific address spaces, which are usually + // specified by address space attributes __attribute__(address_space(n))). + FirstTargetAddressSpace }; /// The type of a lookup table which maps from language-specific address spaces /// to target-specific ones. -typedef unsigned Map[Count]; +typedef unsigned LangASMap[(unsigned)LangAS::FirstTargetAddressSpace]; +/// \return whether \p AS is a target-specific address space rather than a +/// clang AST address space +inline bool isTargetAddressSpace(LangAS AS) { + return (unsigned)AS >= (unsigned)LangAS::FirstTargetAddressSpace; } +inline unsigned toTargetAddressSpace(LangAS AS) { + assert(isTargetAddressSpace(AS)); + return (unsigned)AS - (unsigned)LangAS::FirstTargetAddressSpace; } +inline LangAS getLangASFromTargetAS(unsigned TargetAS) { + return static_cast<LangAS>((TargetAS) + + (unsigned)LangAS::FirstTargetAddressSpace); +} + +} // namespace clang + #endif diff --git a/include/clang/Basic/AlignedAllocation.h b/include/clang/Basic/AlignedAllocation.h new file mode 100644 index 0000000000..b3496949f3 --- /dev/null +++ b/include/clang/Basic/AlignedAllocation.h @@ -0,0 +1,44 @@ +//===--- AlignedAllocation.h - Aligned Allocation ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a function that returns the minimum OS versions supporting +/// C++17's aligned allocation functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H +#define LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H + +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +inline VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { + switch (OS) { + default: + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.13. + return VersionTuple(10U, 13U); + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0. + return VersionTuple(11U); + case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0. + return VersionTuple(4U); + } + + llvm_unreachable("Unexpected OS"); +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h index 18a2b8a318..1c83e2d0f8 100644 --- a/include/clang/Basic/AllDiagnostics.h +++ b/include/clang/Basic/AllDiagnostics.h @@ -18,17 +18,19 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CommentDiagnostic.h" #include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/CrossTU/CrossTUDiagnostic.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Serialization/SerializationDiagnostic.h" +#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" namespace clang { template <size_t SizeOfStr, typename FieldType> class StringSizerHelper { - char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1]; + static_assert(SizeOfStr <= FieldType(~0U), "Field too small!"); public: enum { Size = SizeOfStr }; }; diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 5960cca1e7..0090b99526 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -149,6 +149,9 @@ class ExprArgument<string name, bit opt = 0> : Argument<name, opt>; class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name, opt, fake>; +class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name, + opt, + fake>; class TypeArgument<string name, bit opt = 0> : Argument<name, opt>; class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>; class VariadicUnsignedArgument<string name> : Argument<name, 1>; @@ -207,18 +210,26 @@ class CXX11<string namespace, string name, int version = 1> string Namespace = namespace; int Version = version; } +class C2x<string namespace, string name> : Spelling<name, "C2x"> { + string Namespace = namespace; +} + class Keyword<string name> : Spelling<name, "Keyword">; class Pragma<string namespace, string name> : Spelling<name, "Pragma"> { string Namespace = namespace; } -// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also -// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible +// The GCC spelling implies GNU<name> and CXX11<"gnu", name> and also sets +// KnownToGCC to 1. This spelling should be used for any GCC-compatible // attributes. class GCC<string name> : Spelling<name, "GCC"> { let KnownToGCC = 1; } +// The Clang spelling implies GNU<name> and CXX11<"clang", name>. This spelling +// should be used for any Clang-specific attributes. +class Clang<string name> : Spelling<name, "Clang">; + class Accessor<string name, list<Spelling> spellings> { string Name = name; list<Spelling> Spellings = spellings; @@ -248,6 +259,8 @@ def COnly : LangOpt<"CPlusPlus", 1>; def CPlusPlus : LangOpt<"CPlusPlus">; def OpenCL : LangOpt<"OpenCL">; def RenderScript : LangOpt<"RenderScript">; +def ObjC : LangOpt<"ObjC1">; +def BlocksSupported : LangOpt<"Blocks">; // Defines targets for target-specific attributes. The list of strings should // specify architectures for which the target applies, based off the ArchType @@ -259,17 +272,124 @@ class TargetArch<list<string> arches> { } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; def TargetAVR : TargetArch<["avr"]>; -def TargetMips : TargetArch<["mips", "mipsel"]>; +def TargetMips32 : TargetArch<["mips", "mipsel"]>; +def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; def TargetX86 : TargetArch<["x86"]>; def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; -def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> { +def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let OSes = ["Win32"]; } -def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> { +def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let CXXABIs = ["Microsoft"]; } +// Attribute subject match rules that are used for #pragma clang attribute. +// +// A instance of AttrSubjectMatcherRule represents an individual match rule. +// An individual match rule can correspond to a number of different attribute +// subjects, e.g. "record" matching rule corresponds to the Record and +// CXXRecord attribute subjects. +// +// Match rules are used in the subject list of the #pragma clang attribute. +// Match rules can have sub-match rules that are instances of +// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number +// of different attribute subjects, and it can have a negated spelling as well. +// For example, "variable(unless(is_parameter))" matching rule corresponds to +// the NonParmVar attribute subject. +class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects, + bit negated = 0> { + string Name = name; + list<AttrSubject> Subjects = subjects; + bit Negated = negated; + // Lists language options, one of which is required to be true for the + // attribute to be applicable. If empty, the language options are taken + // from the parent matcher rule. + list<LangOpt> LangOpts = []; +} +class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects, + list<AttrSubjectMatcherSubRule> subrules = []> { + string Name = name; + list<AttrSubject> Subjects = subjects; + list<AttrSubjectMatcherSubRule> Constraints = subrules; + // Lists language options, one of which is required to be true for the + // attribute to be applicable. If empty, no language options are required. + list<LangOpt> LangOpts = []; +} + +// function(is_member) +def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> { + let LangOpts = [CPlusPlus]; +} +def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [ + SubRuleForCXXMethod +]>; +// hasType is abstract, it should be used with one of the sub-rules. +def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [ + AttrSubjectMatcherSubRule<"functionType", [FunctionLike]> + + // FIXME: There's a matcher ambiguity with objc methods and blocks since + // functionType excludes them but functionProtoType includes them. + // AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]> +]>; +def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias", + [TypedefName]>; +def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record, + CXXRecord], [ + // unless(is_union) + AttrSubjectMatcherSubRule<"is_union", [Struct], 1> +]>; +def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>; +def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant", + [EnumConstant]>; +def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [ + AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>, + AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>, + AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>, + // unless(is_parameter) + AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1> +]>; +def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>; +def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace", + [Namespace]> { + let LangOpts = [CPlusPlus]; +} +def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface", + [ObjCInterface]> { + let LangOpts = [ObjC]; +} +def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol", + [ObjCProtocol]> { + let LangOpts = [ObjC]; +} +def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category", + [ObjCCategory]> { + let LangOpts = [ObjC]; +} +def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method", + [ObjCMethod], [ + AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]> +]> { + let LangOpts = [ObjC]; +} +def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property", + [ObjCProperty]> { + let LangOpts = [ObjC]; +} +def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> { + let LangOpts = [BlocksSupported]; +} + +// Aggregate attribute subject match rules are abstract match rules that can't +// be used directly in #pragma clang attribute. Instead, users have to use +// subject match rules that correspond to attribute subjects that derive from +// the specified subject. +class AttrSubjectMatcherAggregateRule<AttrSubject subject> { + AttrSubject Subject = subject; +} + +def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>; + class Attr { // The various ways in which an attribute can be spelled in source list<Spelling> Spellings; @@ -302,6 +422,17 @@ class Attr { // Set to true if this attribute can be duplicated on a subject when merging // attributes. By default, attributes are not merged. bit DuplicatesAllowedWhileMerging = 0; + // Set to true if this attribute meaningful when applied to or inherited + // in a class template definition. + bit MeaningfulToClassTemplateDefinition = 0; + // Set to true if this attribute can be used with '#pragma clang attribute'. + // By default, when this value is false, an attribute is supported by the + // '#pragma clang attribute' only when: + // - It has documentation. + // - It has a subject list whose subjects can be represented using subject + // match rules. + // - It has GNU/CXX11 spelling and doesn't require delayed parsing. + bit ForcePragmaAttributeSupport = 0; // Lists language options, one of which is required to be true for the // attribute to be applicable. If empty, no language options are required. list<LangOpt> LangOpts = []; @@ -373,6 +504,7 @@ def AbiTag : Attr { let Args = [VariadicStringArgument<"Tags">]; let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag, "ExpectedStructClassVariableFunctionOrInlineNamespace">; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [AbiTagsDocs]; } @@ -435,23 +567,19 @@ def AlwaysInline : InheritableAttr { } def XRayInstrument : InheritableAttr { - let Spellings = [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">, - GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]; + let Spellings = [Clang<"xray_always_instrument">, + Clang<"xray_never_instrument">]; let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod">; let Accessors = [Accessor<"alwaysXRayInstrument", - [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">]>, + [Clang<"xray_always_instrument">]>, Accessor<"neverXRayInstrument", - [GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]>]; + [Clang<"xray_never_instrument">]>]; let Documentation = [XRayDocs]; } def XRayLogArgs : InheritableAttr { - let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">]; + let Spellings = [Clang<"xray_log_args">]; let Subjects = SubjectList< [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod" >; @@ -474,13 +602,16 @@ def AnalyzerNoReturn : InheritableAttr { def Annotate : InheritableParamAttr { let Spellings = [GNU<"annotate">]; let Args = [StringArgument<"Annotation">]; + // Ensure that the annotate attribute can be used with + // '#pragma clang attribute' even though it has no subject list. + let ForcePragmaAttributeSupport = 1; let Documentation = [Undocumented]; } def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { // NOTE: If you add any additional spellings, MSP430Interrupt's, // MipsInterrupt's and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Args = [EnumArgument<"Interrupt", "InterruptType", ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"], @@ -491,14 +622,14 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { } def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> { - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; let ParseKind = "Interrupt"; let Documentation = [AVRInterruptDocs]; } def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> { - let Spellings = [GNU<"signal">]; + let Spellings = [GCC<"signal">]; let Subjects = SubjectList<[Function]>; let Documentation = [AVRSignalDocs]; } @@ -529,21 +660,44 @@ def Availability : InheritableAttr { .Case("tvos_app_extension", "tvOS (App Extension)") .Case("watchos_app_extension", "watchOS (App Extension)") .Default(llvm::StringRef()); +} +static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) { + return llvm::StringSwitch<llvm::StringRef>(Platform) + .Case("ios", "iOS") + .Case("macos", "macOS") + .Case("tvos", "tvOS") + .Case("watchos", "watchOS") + .Case("ios_app_extension", "iOSApplicationExtension") + .Case("macos_app_extension", "macOSApplicationExtension") + .Case("tvos_app_extension", "tvOSApplicationExtension") + .Case("watchos_app_extension", "watchOSApplicationExtension") + .Default(Platform); +} +static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { + return llvm::StringSwitch<llvm::StringRef>(Platform) + .Case("iOS", "ios") + .Case("macOS", "macos") + .Case("tvOS", "tvos") + .Case("watchOS", "watchos") + .Case("iOSApplicationExtension", "ios_app_extension") + .Case("macOSApplicationExtension", "macos_app_extension") + .Case("tvOSApplicationExtension", "tvos_app_extension") + .Case("watchOSApplicationExtension", "watchos_app_extension") + .Default(Platform); } }]; let HasCustomParsing = 1; let DuplicatesAllowedWhileMerging = 1; -// let Subjects = SubjectList<[Named]>; + let Subjects = SubjectList<[Named]>; let Documentation = [AvailabilityDocs]; } def ExternalSourceSymbol : InheritableAttr { - let Spellings = [GNU<"external_source_symbol">, - CXX11<"clang", "external_source_symbol">]; + let Spellings = [Clang<"external_source_symbol">]; let Args = [StringArgument<"language", 1>, StringArgument<"definedIn", 1>, BoolArgument<"generatedDeclaration", 1>]; let HasCustomParsing = 1; -// let Subjects = SubjectList<[Named]>; + let Subjects = SubjectList<[Named]>; let Documentation = [ExternalSourceSymbolDocs]; } @@ -741,6 +895,13 @@ def OpenCLUnrollHint : InheritableAttr { let Documentation = [OpenCLUnrollHintDocs]; } +def OpenCLIntelReqdSubGroupSize: InheritableAttr { + let Spellings = [GNU<"intel_reqd_sub_group_size">]; + let Args = [UnsignedArgument<"SubGroupSize">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [OpenCLIntelReqdSubGroupSizeDocs]; +} + // This attribute is both a type attribute, and a declaration attribute (for // parameter variables). def OpenCLAccess : Attr { @@ -800,11 +961,12 @@ def RenderScriptKernel : Attr { def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, - CXX11<"","deprecated", 201309>]; + CXX11<"","deprecated", 201309>, C2x<"", "deprecated">]; let Args = [StringArgument<"Message", 1>, // An optional string argument that enables us to provide a // Fix-It. StringArgument<"Replacement", 1>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [DeprecatedDocs]; } @@ -846,7 +1008,7 @@ def ExtVectorType : Attr { } def FallThrough : StmtAttr { - let Spellings = [CXX11<"", "fallthrough", 201603>, + let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">, CXX11<"clang", "fallthrough">]; // let Subjects = [NullStmt]; let Documentation = [FallthroughDocs]; @@ -881,7 +1043,14 @@ def FlagEnum : InheritableAttr { let Spellings = [GNU<"flag_enum">]; let Subjects = SubjectList<[Enum]>; let Documentation = [FlagEnumDocs]; - let LangOpts = [COnly]; +} + +def EnumExtensibility : InheritableAttr { + let Spellings = [Clang<"enum_extensibility">]; + let Subjects = SubjectList<[Enum]>; + let Args = [EnumArgument<"Extensibility", "Kind", + ["closed", "open"], ["Closed", "Open"]>]; + let Documentation = [EnumExtensibilityDocs]; } def Flatten : InheritableAttr { @@ -987,23 +1156,23 @@ def MSABI : InheritableAttr { def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> { // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's // and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Args = [UnsignedArgument<"Number">]; let ParseKind = "Interrupt"; let HasCustomParsing = 1; let Documentation = [Undocumented]; } -def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { +def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"mips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } -def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> { +def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> { // NOTE: If you add any additional spellings, ARMInterrupt's, // MSP430Interrupt's and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; let Args = [EnumArgument<"Interrupt", "InterruptType", ["vector=sw0", "vector=sw1", "vector=hw0", @@ -1016,6 +1185,24 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> { let Documentation = [MipsInterruptDocs]; } +def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> { + let Spellings = [GCC<"micromips">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [MicroMipsDocs]; +} + +def MipsLongCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> { + let Spellings = [GCC<"long_call">, GCC<"far">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MipsLongCallStyleDocs]; +} + +def MipsShortCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> { + let Spellings = [GCC<"short_call">, GCC<"near">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MipsShortCallStyleDocs]; +} + def Mode : Attr { let Spellings = [GCC<"mode">]; let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag, @@ -1049,8 +1236,7 @@ def ReturnsTwice : InheritableAttr { } def DisableTailCalls : InheritableAttr { - let Spellings = [GNU<"disable_tail_calls">, - CXX11<"clang", "disable_tail_calls">]; + let Spellings = [Clang<"disable_tail_calls">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [DisableTailCallsDocs]; } @@ -1075,13 +1261,13 @@ def NoDebug : InheritableAttr { } def NoDuplicate : InheritableAttr { - let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; + let Spellings = [Clang<"noduplicate">]; let Subjects = SubjectList<[Function]>; let Documentation = [NoDuplicateDocs]; } def Convergent : InheritableAttr { - let Spellings = [GNU<"convergent">, CXX11<"clang", "convergent">]; + let Spellings = [Clang<"convergent">]; let Subjects = SubjectList<[Function]>; let Documentation = [ConvergentDocs]; } @@ -1092,12 +1278,18 @@ def NoInline : InheritableAttr { let Documentation = [Undocumented]; } -def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { +def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"nomips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } +def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> { + let Spellings = [GCC<"nomicromips">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [MicroMipsDocs]; +} + // This is not a TargetSpecificAttr so that is silently accepted and // ignored on other targets as encouraged by the OpenCL spec. // @@ -1205,6 +1397,12 @@ def ObjCKindOf : TypeAttr { let Documentation = [Undocumented]; } +def NoEscape : Attr { + let Spellings = [Clang<"noescape">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [NoEscapeDocs]; +} + def AssumeAligned : InheritableAttr { let Spellings = [GCC<"assume_aligned">]; let Subjects = SubjectList<[ObjCMethod, Function]>; @@ -1212,6 +1410,14 @@ def AssumeAligned : InheritableAttr { let Documentation = [AssumeAlignedDocs]; } +def AllocAlign : InheritableAttr { + let Spellings = [GCC<"alloc_align">]; + let Subjects = SubjectList<[HasFunctionProto], WarnDiag, + "ExpectedFunctionWithProtoType">; + let Args = [IntArgument<"ParamIndex">]; + let Documentation = [AllocAlignDocs]; +} + def NoReturn : InheritableAttr { let Spellings = [GCC<"noreturn">, Declspec<"noreturn">]; // FIXME: Does GCC allow this on the function instead? @@ -1225,14 +1431,15 @@ def NoInstrumentFunction : InheritableAttr { } def NotTailCalled : InheritableAttr { - let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">]; + let Spellings = [Clang<"not_tail_called">]; let Subjects = SubjectList<[Function]>; let Documentation = [NotTailCalledDocs]; } def NoThrow : InheritableAttr { let Spellings = [GCC<"nothrow">, Declspec<"nothrow">]; - let Documentation = [Undocumented]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoThrowDocs]; } def NvWeak : IgnoredAttr { @@ -1386,7 +1593,7 @@ def ObjCBoxable : Attr { } def OptimizeNone : InheritableAttr { - let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; + let Spellings = [Clang<"optnone">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [OptnoneDocs]; } @@ -1464,8 +1671,7 @@ def ReqdWorkGroupSize : InheritableAttr { } def RequireConstantInit : InheritableAttr { - let Spellings = [GNU<"require_constant_initialization">, - CXX11<"clang", "require_constant_initialization">]; + let Spellings = [Clang<"require_constant_initialization">]; let Subjects = SubjectList<[GlobalVar], ErrorDiag, "ExpectedStaticOrTLSVar">; let Documentation = [RequireConstantInitDocs]; @@ -1482,7 +1688,7 @@ def WorkGroupSizeHint : InheritableAttr { } def InitPriority : InheritableAttr { - let Spellings = [GNU<"init_priority">]; + let Spellings = [GCC<"init_priority">]; let Args = [UnsignedArgument<"Priority">]; let Subjects = SubjectList<[Var], ErrorDiag>; let Documentation = [Undocumented]; @@ -1497,6 +1703,42 @@ def Section : InheritableAttr { let Documentation = [SectionDocs]; } +def PragmaClangBSSSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangDataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangRodataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangTextSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + def Sentinel : InheritableAttr { let Spellings = [GCC<"sentinel">]; let Args = [DefaultIntArgument<"Sentinel", 0>, @@ -1512,26 +1754,32 @@ def StdCall : InheritableAttr { } def SwiftCall : InheritableAttr { - let Spellings = [GCC<"swiftcall">]; + let Spellings = [GNU<"swiftcall">]; // let Subjects = SubjectList<[Function]>; let Documentation = [SwiftCallDocs]; } def SwiftContext : ParameterABIAttr { - let Spellings = [GCC<"swift_context">]; + let Spellings = [GNU<"swift_context">]; let Documentation = [SwiftContextDocs]; } def SwiftErrorResult : ParameterABIAttr { - let Spellings = [GCC<"swift_error_result">]; + let Spellings = [GNU<"swift_error_result">]; let Documentation = [SwiftErrorResultDocs]; } def SwiftIndirectResult : ParameterABIAttr { - let Spellings = [GCC<"swift_indirect_result">]; + let Spellings = [GNU<"swift_indirect_result">]; let Documentation = [SwiftIndirectResultDocs]; } +def Suppress : StmtAttr { + let Spellings = [CXX11<"gsl", "suppress">]; + let Args = [VariadicStringArgument<"DiagnosticIdentifiers">]; + let Documentation = [SuppressDocs]; +} + def SysVABI : InheritableAttr { let Spellings = [GCC<"sysv_abi">]; // let Subjects = [Function, ObjCMethod]; @@ -1574,11 +1822,18 @@ def Target : InheritableAttr { let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [TargetDocs]; let AdditionalMembers = [{ - typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr; + struct ParsedTargetAttr { + std::vector<std::string> Features; + StringRef Architecture; + bool DuplicateArchitecture = false; + }; ParsedTargetAttr parse() const { + return parse(getFeaturesStr()); + } + static ParsedTargetAttr parse(StringRef Features) { ParsedTargetAttr Ret; SmallVector<StringRef, 1> AttrFeatures; - getFeaturesStr().split(AttrFeatures, ","); + Features.split(AttrFeatures, ","); // Grab the various features and prepend a "+" to turn on the feature to // the backend and add them to our existing set of features. @@ -1595,12 +1850,15 @@ def Target : InheritableAttr { continue; // While we're here iterating check for a different target cpu. - if (Feature.startswith("arch=")) - Ret.second = Feature.split("=").second.trim(); - else if (Feature.startswith("no-")) - Ret.first.push_back("-" + Feature.split("-").second.str()); + if (Feature.startswith("arch=")) { + if (!Ret.Architecture.empty()) + Ret.DuplicateArchitecture = true; + else + Ret.Architecture = Feature.split("=").second.trim(); + } else if (Feature.startswith("no-")) + Ret.Features.push_back("-" + Feature.split("-").second.str()); else - Ret.first.push_back("+" + Feature.str()); + Ret.Features.push_back("+" + Feature.str()); } return Ret; } @@ -1630,14 +1888,14 @@ def Unavailable : InheritableAttr { def DiagnoseIf : InheritableAttr { let Spellings = [GNU<"diagnose_if">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>; let Args = [ExprArgument<"Cond">, StringArgument<"Message">, EnumArgument<"DiagnosticType", "DiagnosticType", ["error", "warning"], ["DT_Error", "DT_Warning"]>, BoolArgument<"ArgDependent", 0, /*fake*/ 1>, - FunctionArgument<"Parent", 0, /*fake*/ 1>]; + NamedArgument<"Parent", 0, /*fake*/ 1>]; let DuplicatesAllowedWhileMerging = 1; let LateParsed = 1; let AdditionalMembers = [{ @@ -1674,7 +1932,8 @@ def ObjCRequiresPropertyDefs : InheritableAttr { } def Unused : InheritableAttr { - let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">]; + let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, + C2x<"", "maybe_unused">]; let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label, Field, ObjCMethod, FunctionLike], WarnDiag, "ExpectedForMaybeUnused">; @@ -1715,12 +1974,13 @@ def Visibility : InheritableAttr { let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [Undocumented]; } def TypeVisibility : InheritableAttr { let Clone = 0; - let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">]; + let Spellings = [Clang<"type_visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; @@ -1735,16 +1995,16 @@ def VecReturn : InheritableAttr { } def WarnUnused : InheritableAttr { - let Spellings = [GNU<"warn_unused">]; + let Spellings = [GCC<"warn_unused">]; let Subjects = SubjectList<[Record]>; let Documentation = [Undocumented]; } def WarnUnusedResult : InheritableAttr { - let Spellings = [CXX11<"", "nodiscard", 201603>, + let Spellings = [CXX11<"", "nodiscard", 201603>, C2x<"", "nodiscard">, CXX11<"clang", "warn_unused_result">, GCC<"warn_unused_result">]; - let Subjects = SubjectList<[ObjCMethod, Enum, CXXRecord, FunctionLike], + let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike], WarnDiag, "ExpectedFunctionMethodEnumOrClass">; let Documentation = [WarnUnusedResultsDocs]; } @@ -1777,23 +2037,29 @@ def LTOVisibilityPublic : InheritableAttr { def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { // NOTE: If you add any additional spellings, ARMInterrupt's, // MSP430Interrupt's and MipsInterrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[HasFunctionProto]>; let ParseKind = "Interrupt"; let HasCustomParsing = 1; - let Documentation = [AnyX86InterruptDocs]; + let Documentation = [Undocumented]; +} + +def AnyX86NoCallerSavedRegisters : InheritableAttr, + TargetSpecificAttr<TargetAnyX86> { + let Spellings = [GCC<"no_caller_saved_registers">]; + let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } -def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> { - let Spellings = [GNU<"force_align_arg_pointer">]; +def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { + let Spellings = [GCC<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific // code silently allows anything function-like (such as typedefs or function // pointers), but does not apply the attribute to them. - let Documentation = [Undocumented]; + let Documentation = [X86ForceAlignArgPointerDocs]; } def NoSanitize : InheritableAttr { - let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">]; + let Spellings = [Clang<"no_sanitize">]; let Args = [VariadicStringArgument<"Sanitizers">]; let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag, "ExpectedFunctionMethodOrGlobalVar">; @@ -1855,15 +2121,12 @@ def ScopedLockable : InheritableAttr { } def Capability : InheritableAttr { - let Spellings = [GNU<"capability">, CXX11<"clang", "capability">, - GNU<"shared_capability">, - CXX11<"clang", "shared_capability">]; + let Spellings = [Clang<"capability">, Clang<"shared_capability">]; let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, "ExpectedStructOrUnionOrTypedef">; let Args = [StringArgument<"Name">]; let Accessors = [Accessor<"isShared", - [GNU<"shared_capability">, - CXX11<"clang","shared_capability">]>]; + [Clang<"shared_capability">]>]; let Documentation = [Undocumented]; let AdditionalMembers = [{ bool isMutex() const { return getName().equals_lower("mutex"); } @@ -1872,27 +2135,22 @@ def Capability : InheritableAttr { } def AssertCapability : InheritableAttr { - let Spellings = [GNU<"assert_capability">, - CXX11<"clang", "assert_capability">, - GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]; + let Spellings = [Clang<"assert_capability">, + Clang<"assert_shared_capability">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Args = [ExprArgument<"Expr">]; + let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]>]; + [Clang<"assert_shared_capability">]>]; let Documentation = [AssertCapabilityDocs]; } def AcquireCapability : InheritableAttr { - let Spellings = [GNU<"acquire_capability">, - CXX11<"clang", "acquire_capability">, - GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + let Spellings = [Clang<"acquire_capability">, + Clang<"acquire_shared_capability">, GNU<"exclusive_lock_function">, GNU<"shared_lock_function">]; let Subjects = SubjectList<[Function]>; @@ -1902,17 +2160,14 @@ def AcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + [Clang<"acquire_shared_capability">, GNU<"shared_lock_function">]>]; let Documentation = [AcquireCapabilityDocs]; } def TryAcquireCapability : InheritableAttr { - let Spellings = [GNU<"try_acquire_capability">, - CXX11<"clang", "try_acquire_capability">, - GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]; + let Spellings = [Clang<"try_acquire_capability">, + Clang<"try_acquire_shared_capability">]; let Subjects = SubjectList<[Function], ErrorDiag>; let LateParsed = 1; @@ -1921,18 +2176,14 @@ def TryAcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]>]; + [Clang<"try_acquire_shared_capability">]>]; let Documentation = [TryAcquireCapabilityDocs]; } def ReleaseCapability : InheritableAttr { - let Spellings = [GNU<"release_capability">, - CXX11<"clang", "release_capability">, - GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">, - GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, + let Spellings = [Clang<"release_capability">, + Clang<"release_shared_capability">, + Clang<"release_generic_capability">, GNU<"unlock_function">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; @@ -1941,21 +2192,17 @@ def ReleaseCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">]>, + [Clang<"release_shared_capability">]>, Accessor<"isGeneric", - [GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, + [Clang<"release_generic_capability">, GNU<"unlock_function">]>]; let Documentation = [ReleaseCapabilityDocs]; } def RequiresCapability : InheritableAttr { - let Spellings = [GNU<"requires_capability">, - CXX11<"clang", "requires_capability">, + let Spellings = [Clang<"requires_capability">, GNU<"exclusive_locks_required">, - GNU<"requires_shared_capability">, - CXX11<"clang", "requires_shared_capability">, + Clang<"requires_shared_capability">, GNU<"shared_locks_required">]; let Args = [VariadicExprArgument<"Args">]; let LateParsed = 1; @@ -1963,9 +2210,8 @@ def RequiresCapability : InheritableAttr { let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; let Subjects = SubjectList<[Function]>; - let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">, - GNU<"shared_locks_required">, - CXX11<"clang","requires_shared_capability">]>]; + let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability">, + GNU<"shared_locks_required">]>]; let Documentation = [Undocumented]; } @@ -2215,9 +2461,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> { } def SelectAny : InheritableAttr { - let Spellings = [Declspec<"selectany">]; - let LangOpts = [MicrosoftExt]; - let Documentation = [Undocumented]; + let Spellings = [Declspec<"selectany">, GCC<"selectany">]; + let Documentation = [SelectAnyDocs]; } def Thread : Attr { @@ -2429,6 +2674,14 @@ def OMPCaptureNoInit : InheritableAttr { let Documentation = [Undocumented]; } +def OMPCaptureKind : Attr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Args = [UnsignedArgument<"CaptureKind">]; + let Documentation = [Undocumented]; +} + def OMPDeclareSimdDecl : Attr { let Spellings = [Pragma<"omp", "declare simd">]; let Subjects = SubjectList<[Function]>; @@ -2515,7 +2768,7 @@ def OMPDeclareTargetDecl : Attr { } def InternalLinkage : InheritableAttr { - let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; + let Spellings = [Clang<"internal_linkage">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; let Documentation = [InternalLinkageDocs]; } diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index df299e07c6..ecff329c4c 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -7,6 +7,24 @@ // //===---------------------------------------------------------------------===// +// To test that the documentation builds cleanly, you must run clang-tblgen to +// convert the .td file into a .rst file, and then run sphinx to convert the +// .rst file into an HTML file. After completing testing, you should revert the +// generated .rst file so that the modified version does not get checked in to +// version control. +// +// To run clang-tblgen to generate the .rst file: +// clang-tblgen -gen-attr-docs -I <root>/llvm/tools/clang/include +// <root>/llvm/tools/clang/include/clang/Basic/Attr.td -o +// <root>/llvm/tools/clang/docs/AttributeReference.rst +// +// To run sphinx to generate the .html files (note that sphinx-build must be +// available on the PATH): +// Windows (from within the clang\docs directory): +// make.bat html +// Non-Windows (from within the clang\docs directory): +// make -f Makefile.sphinx html + def GlobalDocumentation { code Intro =[{.. ------------------------------------------------------------------- @@ -112,6 +130,50 @@ members, and static locals. }]; } +def NoEscapeDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +``noescape`` placed on a function parameter of a pointer type is used to inform +the compiler that the pointer cannot escape: that is, no reference to the object +the pointer points to that is derived from the parameter value will survive +after the function returns. Users are responsible for making sure parameters +annotated with ``noescape`` do not actuallly escape. + +For example: + +.. code-block:: c + + int *gp; + + void nonescapingFunc(__attribute__((noescape)) int *p) { + *p += 100; // OK. + } + + void escapingFunc(__attribute__((noescape)) int *p) { + gp = p; // Not OK. + } + +Additionally, when the parameter is a `block pointer +<https://clang.llvm.org/docs/BlockLanguageSpec.html>`, the same restriction +applies to copies of the block. For example: + +.. code-block:: c + + typedef void (^BlockTy)(); + BlockTy g0, g1; + + void nonescapingFunc(__attribute__((noescape)) BlockTy block) { + block(); // OK. + } + + void escapingFunc(__attribute__((noescape)) BlockTy block) { + g0 = block; // Not OK. + g1 = Block_copy(block); // Not OK either. + } + + }]; +} + def CarriesDependencyDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -244,6 +306,36 @@ An example of how to use ``alloc_size`` }]; } +def AllocAlignDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((alloc_align(<alignment>))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) is at least as aligned as the value of the indicated parameter. The +parameter is given by its index in the list of formal parameters; the first +parameter has index 1 unless the function is a C++ non-static member function, +in which case the first parameter has index 2 to account for the implicit ``this`` +parameter. + +.. code-block:: c++ + + // The returned pointer has the alignment specified by the first parameter. + void *a(size_t align) __attribute__((alloc_align(1))); + + // The returned pointer has the alignment specified by the second parameter. + void *b(void *v, size_t align) __attribute__((alloc_align(2))); + + // The returned pointer has the alignment specified by the second visible + // parameter, however it must be adjusted for the implicit 'this' parameter. + void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3))); + +Note that this attribute merely informs the compiler that a function always +returns a sufficiently aligned pointer. It does not cause the compiler to +emit code to enforce that alignment. The behavior is undefined if the returned +poitner is not sufficiently aligned. + }]; +} + def EnableIfDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -575,20 +667,27 @@ semantics: for ``T`` and ``U`` to be incompatible. The declaration of ``overloadable`` functions is restricted to function -declarations and definitions. Most importantly, if any function with a given -name is given the ``overloadable`` attribute, then all function declarations -and definitions with that name (and in that scope) must have the -``overloadable`` attribute. This rule even applies to redeclarations of -functions whose original declaration had the ``overloadable`` attribute, e.g., +declarations and definitions. If a function is marked with the ``overloadable`` +attribute, then all declarations and definitions of functions with that name, +except for at most one (see the note below about unmarked overloads), must have +the ``overloadable`` attribute. In addition, redeclarations of a function with +the ``overloadable`` attribute must have the ``overloadable`` attribute, and +redeclarations of a function without the ``overloadable`` attribute must *not* +have the ``overloadable`` attribute. e.g., .. code-block:: c int f(int) __attribute__((overloadable)); float f(float); // error: declaration of "f" must have the "overloadable" attribute + int f(int); // error: redeclaration of "f" must have the "overloadable" attribute int g(int) __attribute__((overloadable)); int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute + int h(int); + int h(int) __attribute__((overloadable)); // error: declaration of "h" must not + // have the "overloadable" attribute + Functions marked ``overloadable`` must have prototypes. Therefore, the following code is ill-formed: @@ -621,7 +720,28 @@ caveats to this use of name mangling: linkage specification, it's name *will* be mangled in the same way as it would in C. -Query for this feature with ``__has_extension(attribute_overloadable)``. +For the purpose of backwards compatibility, at most one function with the same +name as other ``overloadable`` functions may omit the ``overloadable`` +attribute. In this case, the function without the ``overloadable`` attribute +will not have its name mangled. + +For example: + +.. code-block:: c + + // Notes with mangled names assume Itanium mangling. + int f(int); + int f(double) __attribute__((overloadable)); + void foo() { + f(5); // Emits a call to f (not _Z1fi, as it would with an overload that + // was marked with overloadable). + f(1.0); // Emits a call to _Z1fd. + } + +Support for unmarked overloads is not present in some versions of clang. You may +query for it using ``__has_extension(overloadable_unmarked)``. + +Query for this attribute with ``__has_attribute(overloadable)``. }]; } @@ -852,13 +972,13 @@ the function declaration for a hypothetical function ``f``: void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7))); -The availability attribute states that ``f`` was introduced in Mac OS X 10.4, -deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information +The availability attribute states that ``f`` was introduced in macOS 10.4, +deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information is used by Clang to determine when it is safe to use ``f``: for example, if -Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()`` -succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call +Clang is instructed to compile code for macOS 10.5, a call to ``f()`` +succeeds. If Clang is instructed to compile code for macOS 10.6, the call succeeds but Clang emits a warning specifying that the function is deprecated. -Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call +Finally, if Clang is instructed to compile code for macOS 10.7, the call fails because ``f()`` is no longer available. The availability attribute is a comma-separated list starting with the @@ -903,7 +1023,7 @@ are: command-line arguments. ``macos`` - Apple's Mac OS X operating system. The minimum deployment target is + Apple's macOS operating system. The minimum deployment target is specified by the ``-mmacosx-version-min=*version*`` command-line argument. ``macosx`` is supported for backward-compatibility reasons, but it is deprecated. @@ -957,6 +1077,19 @@ When one method overrides another, the overriding method can be more widely avai - (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later - (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4 @end + +Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from +``<os/availability.h>`` can simplify the spelling: + +.. code-block:: objc + + @interface A + - (id)method API_AVAILABLE(macos(10.11))); + - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0)); + @end + +Also see the documentation for `@available +<http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available>`_ }]; } @@ -1160,6 +1293,7 @@ Here is an example: def ARMInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (ARM)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on ARM targets. This attribute may be attached to a function definition and @@ -1201,6 +1335,7 @@ The semantics are as follows: def MipsInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (MIPS)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on MIPS targets. This attribute may be attached to a function definition and instructs @@ -1239,8 +1374,65 @@ The semantics are as follows: }]; } +def MicroMipsDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + }]; +} + +def MipsLongCallStyleDocs : Documentation { + let Category = DocCatFunction; + let Heading = "long_call (gnu::long_call, gnu::far)"; + let Content = [{ +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +and ``__attribute__((near))`` attributes on MIPS targets. These attributes may +only be added to function declarations and change the code generated +by the compiler when directly calling the function. The ``near`` attribute +allows calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB +segment as the caller. The ``long_call`` and ``far`` attributes are synonyms +and require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + }]; +} + +def MipsShortCallStyleDocs : Documentation { + let Category = DocCatFunction; + let Heading = "short_call (gnu::short_call, gnu::near)"; + let Content = [{ +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +``__attribute__((short__call))``, and ``__attribute__((near))`` attributes +on MIPS targets. These attributes may only be added to function declarations +and change the code generated by the compiler when directly calling +the function. The ``short_call`` and ``near`` attributes are synonyms and +allow calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB segment +as the caller. The ``long_call`` and ``far`` attributes are synonyms and +require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + }]; +} + def AVRInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (AVR)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt))`` attribute on AVR targets. This attribute may be attached to a function definition and instructs @@ -1963,6 +2155,55 @@ manipulating bits of the enumerator when issuing warnings. }]; } +def EnumExtensibilityDocs : Documentation { + let Category = DocCatType; + let Content = [{ +Attribute ``enum_extensibility`` is used to distinguish between enum definitions +that are extensible and those that are not. The attribute can take either +``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the +enum type takes a value that corresponds to one of the enumerators listed in the +enum definition or, when the enum is annotated with ``flag_enum``, a value that +can be constructed using values corresponding to the enumerators. ``open`` +indicates a variable of the enum type can take any values allowed by the +standard and instructs clang to be more lenient when issuing warnings. + +.. code-block:: c + + enum __attribute__((enum_extensibility(closed))) ClosedEnum { + A0, A1 + }; + + enum __attribute__((enum_extensibility(open))) OpenEnum { + B0, B1 + }; + + enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum { + C0 = 1 << 0, C1 = 1 << 1 + }; + + enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum { + D0 = 1 << 0, D1 = 1 << 1 + }; + + void foo1() { + enum ClosedEnum ce; + enum OpenEnum oe; + enum ClosedFlagEnum cfe; + enum OpenFlagEnum ofe; + + ce = A1; // no warnings + ce = 100; // warning issued + oe = B1; // no warnings + oe = 100; // no warnings + cfe = C0 | C1; // no warnings + cfe = C0 | C1 | 4; // warning issued + ofe = D0 | D1; // no warnings + ofe = D0 | D1 | 4; // no warnings + } + + }]; +} + def EmptyBasesDocs : Documentation { let Category = DocCatType; let Content = [{ @@ -2137,6 +2378,21 @@ s6.11.5 for details. }]; } +def OpenCLIntelReqdSubGroupSizeDocs : Documentation { + let Category = DocCatStmt; + let Heading = "__attribute__((intel_reqd_sub_group_size))"; + let Content = [{ +The optional attribute intel_reqd_sub_group_size can be used to indicate that +the kernel must be compiled and executed with the specified subgroup size. When +this attribute is present, get_max_sub_group_size() is guaranteed to return the +specified integer value. This is important for the correctness of many subgroup +algorithms, and in some cases may be used by the compiler to generate more optimal +code. See `cl_intel_required_subgroup_size +<https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_required_subgroup_size.txt>` +for details. + }]; +} + def OpenCLAccessDocs : Documentation { let Category = DocCatStmt; let Heading = "__read_only, __write_only, __read_write (read_only, write_only, read_write)"; @@ -2477,6 +2733,18 @@ Marking virtual functions as ``not_tail_called`` is an error: }]; } +def NoThrowDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((nothrow))`` and Microsoft style +``__declspec(nothrow)`` attribute as an equivilent of `noexcept` on function +declarations. This attribute informs the compiler that the annotated function +does not throw an exception. This prevents exception-unwinding. This attribute +is particularly useful on functions in the C Standard Library that are +guaranteed to not throw an exception. + }]; +} + def InternalLinkageDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -2525,56 +2793,62 @@ Marking virtual functions as ``disable_tail_calls`` is legal. }]; } -def AnyX86InterruptDocs : Documentation { +def AnyX86NoCallerSavedRegistersDocs : Documentation { let Category = DocCatFunction; let Content = [{ -Clang supports the GNU style ``__attribute__((interrupt))`` attribute on -x86/x86-64 targets.The compiler generates function entry and exit sequences -suitable for use in an interrupt handler when this attribute is present. -The 'IRET' instruction, instead of the 'RET' instruction, is used to return -from interrupt or exception handlers. All registers, except for the EFLAGS -register which is restored by the 'IRET' instruction, are preserved by the -compiler. +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. -Any interruptible-without-stack-switch code must be compiled with --mno-red-zone since interrupt handlers can and will, because of the -hardware design, touch the red zone. +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. -1. interrupt handler must be declared with a mandatory pointer argument: +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. - .. code-block:: c +For example: - struct interrupt_frame - { - uword_t ip; - uword_t cs; - uword_t flags; - uword_t sp; - uword_t ss; - }; + .. code-block:: c - __attribute__ ((interrupt)) - void f (struct interrupt_frame *frame) { + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { ... } -2. exception handler: + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + }]; +} - The exception handler is very similar to the interrupt handler with - a different mandatory function signature: +def X86ForceAlignArgPointerDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use this attribute to force stack alignment. + +Legacy x86 code uses 4-byte stack alignment. Newer aligned SSE instructions +(like 'movaps') that work with the stack require operands to be 16-byte aligned. +This attribute realigns the stack in the function prologue to make sure the +stack can be used with SSE instructions. + +Note that the x86_64 ABI forces 16-byte stack alignment at the call site. +Because of this, 'force_align_arg_pointer' is not needed on x86_64, except in +rare cases where the caller does not align the stack properly (e.g. flow +jumps from i386 arch code). .. code-block:: c - __attribute__ ((interrupt)) - void f (struct interrupt_frame *frame, uword_t error_code) { + __attribute__ ((force_align_arg_pointer)) + void f () { ... } - and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction. - - The exception handler should only be used for exceptions which push an - error code and all other exceptions must use the interrupt handler. - The system will crash if the wrong handler is used. }]; } @@ -2722,6 +2996,32 @@ optimizations like C++'s named return value optimization (NRVO). }]; } +def SuppressDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +The ``[[gsl::suppress]]`` attribute suppresses specific +clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable +way. The attribute can be attached to declarations, statements, and at +namespace scope. + +.. code-block:: c++ + + [[gsl::suppress("Rh-public")]] + void f_() { + int *p; + [[gsl::suppress("type")]] { + p = reinterpret_cast<int*>(7); + } + } + namespace N { + [[clang::suppress("type", "bounds")]]; + ... + } + +.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement + }]; +} + def AbiTagsDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -2898,3 +3198,18 @@ This attribute can be added to an Objective-C ``@interface`` declaration to ensure that this class cannot be subclassed. }]; } + + +def SelectAnyDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute appertains to a global symbol, causing it to have a weak +definition ( +`linkonce <https://llvm.org/docs/LangRef.html#linkage-types>`_ +), allowing the linker to select any definition. + +For more information see +`gcc documentation <https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Microsoft-Windows-Variable-Attributes.html>`_ +or `msvc documentation <https://docs.microsoft.com/pl-pl/cpp/cpp/selectany>`_. +}]; +} diff --git a/include/clang/Basic/AttrSubjectMatchRules.h b/include/clang/Basic/AttrSubjectMatchRules.h new file mode 100644 index 0000000000..4c88adf57f --- /dev/null +++ b/include/clang/Basic/AttrSubjectMatchRules.h @@ -0,0 +1,32 @@ +//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H +#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { +namespace attr { + +/// \brief A list of all the recognized kinds of attributes. +enum SubjectMatchRule { +#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X, +#include "clang/Basic/AttrSubMatchRulesList.inc" +}; + +const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule); + +using ParsedSubjectMatchRuleSet = llvm::DenseMap<int, SourceRange>; + +} // end namespace attr +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h index ea9e28ae68..c651abacd4 100644 --- a/include/clang/Basic/Attributes.h +++ b/include/clang/Basic/Attributes.h @@ -26,6 +26,8 @@ enum class AttrSyntax { Microsoft, // Is the identifier known as a C++-style attribute? CXX, + // Is the identifier known as a C-style attribute? + C, // Is the identifier known as a pragma attribute? Pragma }; diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index e7084de9ce..8e276e8445 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -52,6 +52,7 @@ // LL -> long long // LLL -> __int128_t (e.g. LLLi) // W -> int64_t +// N -> 'int' size if target is LP64, 'L' otherwise. // S -> signed // U -> unsigned // I -> Required to constant fold to an integer constant expression. @@ -699,6 +700,21 @@ BUILTIN(__atomic_signal_fence, "vi", "n") BUILTIN(__atomic_always_lock_free, "izvCD*", "n") BUILTIN(__atomic_is_lock_free, "izvCD*", "n") +// OpenCL 2.0 atomic builtins. +ATOMIC_BUILTIN(__opencl_atomic_init, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_load, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_store, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_strong, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_weak, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t") + #undef ATOMIC_BUILTIN // Non-overloaded atomic builtins. @@ -716,13 +732,14 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn") // Microsoft builtins. These are only active with -fms-extensions. LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES) LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES) -LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) +LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES) @@ -730,47 +747,47 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES) LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES) @@ -991,9 +1008,9 @@ LIBBUILTIN(modf, "ddd*", "fn", "math.h", ALL_LANGUAGES) LIBBUILTIN(modff, "fff*", "fn", "math.h", ALL_LANGUAGES) LIBBUILTIN(modfl, "LdLdLd*", "fn", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nan, "dcC*", "fnc", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nanf, "fcC*", "fnc", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nanl, "LdcC*", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nan, "dcC*", "fUn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanf, "fcC*", "fUn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanl, "LdcC*", "fUn", "math.h", ALL_LANGUAGES) LIBBUILTIN(pow, "ddd", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(powf, "fff", "fne", "math.h", ALL_LANGUAGES) @@ -1397,18 +1414,37 @@ LANGBUILTIN(get_pipe_max_packets, "Ui.", "tn", OCLC20_LANG) // OpenCL v2.0 s6.13.17 - Enqueue kernel functions. // Custom builtin check allows to perform special check of passed block arguments. LANGBUILTIN(enqueue_kernel, "i.", "tn", OCLC20_LANG) -LANGBUILTIN(get_kernel_work_group_size, "i.", "tn", OCLC20_LANG) -LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "i.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_work_group_size, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_max_sub_group_size_for_ndrange, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_sub_group_count_for_ndrange, "Ui.", "tn", OCLC20_LANG) // OpenCL v2.0 s6.13.9 - Address space qualifier functions. LANGBUILTIN(to_global, "v*v*", "tn", OCLC20_LANG) LANGBUILTIN(to_local, "v*v*", "tn", OCLC20_LANG) LANGBUILTIN(to_private, "v*v*", "tn", OCLC20_LANG) +// OpenCL half load/store builtin +LANGBUILTIN(__builtin_store_half, "vdh*", "n", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_store_halff, "vfh*", "n", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_load_half, "dhC*", "nc", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_load_halff, "fhC*", "nc", ALL_OCLC_LANGUAGES) + // Builtins for os_log/os_trace BUILTIN(__builtin_os_log_format_buffer_size, "zcC*.", "p:0:nut") BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt") +// OpenMP 4.0 +LANGBUILTIN(omp_is_initial_device, "i", "nc", OMP_LANG) + +// Builtins for XRay +BUILTIN(__xray_customevent, "vcC*z", "") + +// Win64-compatible va_list functions +BUILTIN(__builtin_ms_va_start, "vc*&.", "nt") +BUILTIN(__builtin_ms_va_end, "vc*&", "n") +BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") + #undef BUILTIN #undef LIBBUILTIN #undef LANGBUILTIN diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 87c1f93eed..963c72ea82 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -36,10 +36,13 @@ enum LanguageID { CXX_LANG = 0x4, // builtin for cplusplus only. OBJC_LANG = 0x8, // builtin for objective-c and objective-c++ MS_LANG = 0x10, // builtin requires MS mode. - OCLC20_LANG = 0x20, // builtin for OpenCL C only. + OCLC20_LANG = 0x20, // builtin for OpenCL C 2.0 only. + OCLC1X_LANG = 0x40, // builtin for OpenCL C 1.x only. + OMP_LANG = 0x80, // builtin requires OpenMP. ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages. ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. - ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. + ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG, // builtin requires MS mode. + ALL_OCLC_LANGUAGES = OCLC1X_LANG | OCLC20_LANG // builtin for OCLC languages. }; namespace Builtin { diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def index 1db4c14710..55a4f70176 100644 --- a/include/clang/Basic/BuiltinsAArch64.def +++ b/include/clang/Basic/BuiltinsAArch64.def @@ -14,6 +14,10 @@ // The format of this database matches clang/Basic/Builtins.def. +#if defined(BUILTIN) && !defined(LANGBUILTIN) +# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + // In libgcc BUILTIN(__clear_cache, "vv*v*", "i") @@ -61,4 +65,9 @@ BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc") BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc") BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc") +LANGBUILTIN(__dmb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__dsb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__isb, "vUi", "nc", ALL_MS_LANGUAGES) + #undef BUILTIN +#undef LANGBUILTIN diff --git a/include/clang/Basic/BuiltinsAMDGPU.def b/include/clang/Basic/BuiltinsAMDGPU.def index a8ab657c37..ec6a0fb917 100644 --- a/include/clang/Basic/BuiltinsAMDGPU.def +++ b/include/clang/Basic/BuiltinsAMDGPU.def @@ -21,6 +21,7 @@ // SI+ only builtins. //===----------------------------------------------------------------------===// +BUILTIN(__builtin_amdgcn_dispatch_ptr, "Uc*2", "nc") BUILTIN(__builtin_amdgcn_kernarg_segment_ptr, "Uc*2", "nc") BUILTIN(__builtin_amdgcn_implicitarg_ptr, "Uc*2", "nc") @@ -36,6 +37,7 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc") // Instruction builtins. //===----------------------------------------------------------------------===// BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n") +BUILTIN(__builtin_amdgcn_s_getpc, "LUi", "n") BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n") BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n") BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n") @@ -119,6 +121,8 @@ TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts") // Special builtins. //===----------------------------------------------------------------------===// BUILTIN(__builtin_amdgcn_read_exec, "LUi", "nc") +BUILTIN(__builtin_amdgcn_read_exec_lo, "Ui", "nc") +BUILTIN(__builtin_amdgcn_read_exec_hi, "Ui", "nc") //===----------------------------------------------------------------------===// // R600-NI only builtins. diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def index 6cc7308d4c..4e277f8a5a 100644 --- a/include/clang/Basic/BuiltinsARM.def +++ b/include/clang/Basic/BuiltinsARM.def @@ -25,11 +25,93 @@ // In libgcc BUILTIN(__clear_cache, "vv*v*", "i") +// 16-bit multiplications +BUILTIN(__builtin_arm_smulbb, "iii", "nc") +BUILTIN(__builtin_arm_smulbt, "iii", "nc") +BUILTIN(__builtin_arm_smultb, "iii", "nc") +BUILTIN(__builtin_arm_smultt, "iii", "nc") +BUILTIN(__builtin_arm_smulwb, "iii", "nc") +BUILTIN(__builtin_arm_smulwt, "iii", "nc") + // Saturating arithmetic BUILTIN(__builtin_arm_qadd, "iii", "nc") BUILTIN(__builtin_arm_qsub, "iii", "nc") BUILTIN(__builtin_arm_ssat, "iiUi", "nc") -BUILTIN(__builtin_arm_usat, "UiUiUi", "nc") +BUILTIN(__builtin_arm_usat, "UiiUi", "nc") + +BUILTIN(__builtin_arm_smlabb, "iiii", "nc") +BUILTIN(__builtin_arm_smlabt, "iiii", "nc") +BUILTIN(__builtin_arm_smlatb, "iiii", "nc") +BUILTIN(__builtin_arm_smlatt, "iiii", "nc") +BUILTIN(__builtin_arm_smlawb, "iiii", "nc") +BUILTIN(__builtin_arm_smlawt, "iiii", "nc") + +BUILTIN(__builtin_arm_ssat16, "iii", "nc") +BUILTIN(__builtin_arm_usat16, "iii", "nc") + +BUILTIN(__builtin_arm_sxtab16, "iii", "nc") +BUILTIN(__builtin_arm_sxtb16, "ii", "nc") +BUILTIN(__builtin_arm_uxtab16, "iii", "nc") +BUILTIN(__builtin_arm_uxtb16, "ii", "nc") + +BUILTIN(__builtin_arm_sel, "iii", "nc") + +BUILTIN(__builtin_arm_qadd8, "iii", "nc") +BUILTIN(__builtin_arm_qsub8, "iii", "nc") +BUILTIN(__builtin_arm_sadd8, "iii", "nc") +BUILTIN(__builtin_arm_shadd8, "iii", "nc") +BUILTIN(__builtin_arm_shsub8, "iii", "nc") +BUILTIN(__builtin_arm_ssub8, "iii", "nc") +BUILTIN(__builtin_arm_uadd8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhadd8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhsub8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqadd8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqsub8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_usub8, "UiUiUi", "nc") + +// Sum of 8-bit absolute differences +BUILTIN(__builtin_arm_usad8, "UiUiUi", "nc") +BUILTIN(__builtin_arm_usada8, "UiUiUiUi", "nc") + +// Parallel 16-bit addition and subtraction +BUILTIN(__builtin_arm_qadd16, "iii", "nc") +BUILTIN(__builtin_arm_qasx, "iii", "nc") +BUILTIN(__builtin_arm_qsax, "iii", "nc") +BUILTIN(__builtin_arm_qsub16, "iii", "nc") +BUILTIN(__builtin_arm_sadd16, "iii", "nc") +BUILTIN(__builtin_arm_sasx, "iii", "nc") +BUILTIN(__builtin_arm_shadd16, "iii", "nc") +BUILTIN(__builtin_arm_shasx, "iii", "nc") +BUILTIN(__builtin_arm_shsax, "iii", "nc") +BUILTIN(__builtin_arm_shsub16, "iii", "nc") +BUILTIN(__builtin_arm_ssax, "iii", "nc") +BUILTIN(__builtin_arm_ssub16, "iii", "nc") +BUILTIN(__builtin_arm_uadd16, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uasx, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhadd16, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhasx, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhsax, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uhsub16, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqadd16, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqasx, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqsax, "UiUiUi", "nc") +BUILTIN(__builtin_arm_uqsub16, "UiUiUi", "nc") +BUILTIN(__builtin_arm_usax, "UiUiUi", "nc") +BUILTIN(__builtin_arm_usub16, "UiUiUi", "nc") + +// Parallel 16-bit multiplication +BUILTIN(__builtin_arm_smlad, "iiii", "nc") +BUILTIN(__builtin_arm_smladx, "iiii", "nc") +BUILTIN(__builtin_arm_smlald, "LLiiiLLi", "nc") +BUILTIN(__builtin_arm_smlaldx, "LLiiiLLi", "nc") +BUILTIN(__builtin_arm_smlsd, "iiii", "nc") +BUILTIN(__builtin_arm_smlsdx, "iiii", "nc") +BUILTIN(__builtin_arm_smlsld, "LLiiiLLi", "nc") +BUILTIN(__builtin_arm_smlsldx, "LLiiiLLi", "nc") +BUILTIN(__builtin_arm_smuad, "iii", "nc") +BUILTIN(__builtin_arm_smuadx, "iii", "nc") +BUILTIN(__builtin_arm_smusd, "iii", "nc") +BUILTIN(__builtin_arm_smusdx, "iii", "nc") // Bit manipulation BUILTIN(__builtin_arm_rbit, "UiUi", "nc") @@ -133,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) -TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/include/clang/Basic/BuiltinsHexagon.def b/include/clang/Basic/BuiltinsHexagon.def index 85936cbfc0..14fc4adc25 100644 --- a/include/clang/Basic/BuiltinsHexagon.def +++ b/include/clang/Basic/BuiltinsHexagon.def @@ -882,6 +882,12 @@ BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","") BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","") BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","") BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_Y2_dccleana,"vv*","") +BUILTIN(__builtin_HEXAGON_Y2_dccleaninva,"vv*","") +BUILTIN(__builtin_HEXAGON_Y2_dcinva,"vv*","") +BUILTIN(__builtin_HEXAGON_Y2_dczeroa,"vv*","") +BUILTIN(__builtin_HEXAGON_Y4_l2fetch,"vv*Ui","") +BUILTIN(__builtin_HEXAGON_Y5_l2fetch,"vv*LLUi","") BUILTIN(__builtin_HEXAGON_S6_rol_i_r,"iii","v:60:") BUILTIN(__builtin_HEXAGON_S6_rol_i_p,"LLiLLii","v:60:") diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def index afea6cb0f1..caa860480f 100644 --- a/include/clang/Basic/BuiltinsNVPTX.def +++ b/include/clang/Basic/BuiltinsNVPTX.def @@ -378,6 +378,9 @@ BUILTIN(__nvvm_bar0_popc, "ii", "") BUILTIN(__nvvm_bar0_and, "ii", "") BUILTIN(__nvvm_bar0_or, "ii", "") BUILTIN(__nvvm_bar_sync, "vi", "n") +TARGET_BUILTIN(__nvvm_bar_warp_sync, "vUi", "n", "ptx60") +TARGET_BUILTIN(__nvvm_barrier_sync, "vUi", "n", "ptx60") +TARGET_BUILTIN(__nvvm_barrier_sync_cnt, "vUiUi", "n", "ptx60") // Shuffle @@ -390,6 +393,33 @@ BUILTIN(__nvvm_shfl_bfly_f32, "ffii", "") BUILTIN(__nvvm_shfl_idx_i32, "iiii", "") BUILTIN(__nvvm_shfl_idx_f32, "ffii", "") +TARGET_BUILTIN(__nvvm_shfl_sync_down_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_down_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_up_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_up_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_bfly_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_bfly_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_idx_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_idx_f32, "fUifii", "", "ptx60") + +// Vote +BUILTIN(__nvvm_vote_all, "bb", "") +BUILTIN(__nvvm_vote_any, "bb", "") +BUILTIN(__nvvm_vote_uni, "bb", "") +BUILTIN(__nvvm_vote_ballot, "Uib", "") + +TARGET_BUILTIN(__nvvm_vote_all_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_any_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_uni_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_ballot_sync, "UiUib", "", "ptx60") + +// Match +TARGET_BUILTIN(__nvvm_match_any_sync_i32, "UiUiUi", "", "ptx60") +TARGET_BUILTIN(__nvvm_match_any_sync_i64, "WiUiWi", "", "ptx60") +// These return a pair {value, predicate}, which requires custom lowering. +TARGET_BUILTIN(__nvvm_match_all_sync_i32p, "UiUiUii*", "", "ptx60") +TARGET_BUILTIN(__nvvm_match_all_sync_i64p, "WiUiWii*", "", "ptx60") + // Membar BUILTIN(__nvvm_membar_cta, "v", "") @@ -658,5 +688,18 @@ BUILTIN(__nvvm_ldg_f2, "E2fE2fC*", "") BUILTIN(__nvvm_ldg_f4, "E4fE4fC*", "") BUILTIN(__nvvm_ldg_d2, "E2dE2dC*", "") +// Builtins to support WMMA instructions on sm_70 +TARGET_BUILTIN(__hmma_m16n16k16_ld_a, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_b, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f16, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f32, "vf*fC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_st_c_f16, "vi*i*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_st_c_f32, "vf*f*UiIi", "", "ptx60") + +TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f16, "vi*iC*iC*iC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f16, "vf*iC*iC*iC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f32, "vf*iC*iC*fC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f32, "vi*iC*iC*fC*IiIi", "", "ptx60") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/include/clang/Basic/BuiltinsNios2.def b/include/clang/Basic/BuiltinsNios2.def new file mode 100644 index 0000000000..d9697e795c --- /dev/null +++ b/include/clang/Basic/BuiltinsNios2.def @@ -0,0 +1,70 @@ +//===-- BuiltinsNios2.def - Nios2 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 Nios2-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. + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Nios2 R1 builtins: + +//int __builtin_ldbio(volatile const void *); +BUILTIN(__builtin_ldbio, "ivDC*", "") +//int __builtin_ldbuio(volatile const void *); +BUILTIN(__builtin_ldbuio, "ivDC*", "") +//int __builtin_ldhio(volatile const void *); +BUILTIN(__builtin_ldhio, "ivDC*", "") +//int __builtin_ldhuio(volatile const void *); +BUILTIN(__builtin_ldhuio, "ivDC*", "") +//int __builtin_ldwio(volatile const void *); +BUILTIN(__builtin_ldwio, "ivDC*", "") +//int __builtin_ldwuio(int); +BUILTIN(__builtin_ldwuio, "ii", "") +// int __builtin_rdctl(int); +BUILTIN(__builtin_rdctl, "iIi", "") +// void __builtin_wrctl(int, int); +BUILTIN(__builtin_wrctl, "vIii", "") +// int __builtin_rdprs(int, int); +BUILTIN(__builtin_rdprs, "iii", "") +//void __builtin_stbio(volatile void *, int); +BUILTIN(__builtin_stbio, "vvD*i", "") +//void __builtin_sthio(volatile void *, int); +BUILTIN(__builtin_sthio, "vvD*i", "") +//void __builtin_stwio(volatile void *, int); +BUILTIN(__builtin_stwio, "vvD*i", "") +//void __builtin_sync(void); +BUILTIN(__builtin_sync, "v", "") +// void __builtin_flushd(volatile void *); +BUILTIN(__builtin_flushd, "vvD*", "") +// void __builtin_flushda(volatile void *); +BUILTIN(__builtin_flushda, "vvD*", "") + +// Nios2 R2 builtins: + +// int __builtin_wrpie(int); +TARGET_BUILTIN(__builtin_wrpie, "ii", "", "nios2r2mandatory") +// void __builtin_eni(int); +TARGET_BUILTIN(__builtin_eni, "vi", "", "nios2r2mandatory") +// int __builtin_ldex(volatile const void *); +TARGET_BUILTIN(__builtin_ldex, "ivDC*", "", "nios2r2mandatory") +// int __builtin_stex(volatile void *, int); +TARGET_BUILTIN(__builtin_stex, "ivD*i", "", "nios2r2mandatory") +// int __builtin_ldsex(volatile const void *); +TARGET_BUILTIN(__builtin_ldsex, "ivDC*", "", "nios2r2mpx") +// int __builtin_stsex(volatile void *, int); +TARGET_BUILTIN(__builtin_stsex, "ivDC*i", "", "nios2r2mpx") + +#undef BUILTIN +#undef TARGET_BUILTIN diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index f7cddc0313..faa70a48ed 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -51,10 +51,10 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "") -BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "") -BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "") -BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "") -BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "") +BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "") +BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "") +BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "") +BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "") BUILTIN(__builtin_altivec_dss, "vUi", "") BUILTIN(__builtin_altivec_dssall, "v", "") @@ -420,6 +420,9 @@ BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "") BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "") BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "") +BUILTIN(__builtin_vsx_xxpermdi, "v.", "t") +BUILTIN(__builtin_vsx_xxsldwi, "v.", "t") + // HTM builtins BUILTIN(__builtin_tbegin, "UiUIi", "") BUILTIN(__builtin_tend, "UiUIi", "") diff --git a/include/clang/Basic/BuiltinsSystemZ.def b/include/clang/Basic/BuiltinsSystemZ.def index fa96e10b39..ac92286af0 100644 --- a/include/clang/Basic/BuiltinsSystemZ.def +++ b/include/clang/Basic/BuiltinsSystemZ.def @@ -253,5 +253,29 @@ TARGET_BUILTIN(__builtin_s390_vfmsdb, "V2dV2dV2dV2d", "nc", "vector") TARGET_BUILTIN(__builtin_s390_vfsqdb, "V2dV2d", "nc", "vector") TARGET_BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc", "vector") +// Vector-enhancements facility 1 intrinsics. +TARGET_BUILTIN(__builtin_s390_vlrl, "V16ScUivC*", "", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vstrl, "vV16ScUiv*", "", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vbperm, "V2ULLiV16UcV16Uc", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vmslg, "V16UcV2ULLiV2ULLiV16UcIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfmaxdb, "V2dV2dV2dIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfmindb, "V2dV2dV2dIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfnmadb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfnmsdb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfcesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfchsbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfchesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfisb, "V4fV4fIiIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfmaxsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfminsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vflnsb, "V4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vflpsb, "V4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfnmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfnmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vfsqsb, "V4fV4f", "nc", "vector-enhancements-1") +TARGET_BUILTIN(__builtin_s390_vftcisb, "V4SiV4fIii*", "nc", "vector-enhancements-1") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/include/clang/Basic/BuiltinsWebAssembly.def b/include/clang/Basic/BuiltinsWebAssembly.def index de56908be8..19318dcebb 100644 --- a/include/clang/Basic/BuiltinsWebAssembly.def +++ b/include/clang/Basic/BuiltinsWebAssembly.def @@ -21,4 +21,8 @@ BUILTIN(__builtin_wasm_current_memory, "z", "n") BUILTIN(__builtin_wasm_grow_memory, "zz", "n") +// Exception handling builtins. +BUILTIN(__builtin_wasm_throw, "vUiv*", "r") +BUILTIN(__builtin_wasm_rethrow, "v", "r") + #undef BUILTIN diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 2400b4458c..d57ea8f119 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -32,12 +32,9 @@ // Miscellaneous builtin for checking x86 cpu features. // TODO: Make this somewhat generic so that other backends // can use it? +BUILTIN(__builtin_cpu_init, "v", "n") BUILTIN(__builtin_cpu_supports, "bcC*", "nc") - -// Win64-compatible va_list functions -BUILTIN(__builtin_ms_va_start, "vc*&.", "nt") -BUILTIN(__builtin_ms_va_end, "vc*&", "n") -BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") +BUILTIN(__builtin_cpu_is, "bcC*", "nc") // Undefined Values // @@ -269,8 +266,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "", "sse2") -TARGET_BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "", "sse2") -TARGET_BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "", "sse2") @@ -343,8 +338,8 @@ TARGET_BUILTIN(__builtin_ia32_lfence, "v", "", "sse2") TARGET_HEADER_BUILTIN(_mm_lfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2") TARGET_BUILTIN(__builtin_ia32_mfence, "v", "", "sse2") TARGET_HEADER_BUILTIN(_mm_mfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2") -TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "sse2") -TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2") +TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "") +TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "") TARGET_BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "", "sse2") @@ -391,7 +386,6 @@ TARGET_BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2dIi", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_roundpd, "V2dV2dIi", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "", "sse4.1") -TARGET_BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLiC*", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "", "sse4.1") TARGET_BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "", "sse4.1") @@ -526,8 +520,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIi", "", "avx2") -TARGET_BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "", "avx2") -TARGET_BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "", "avx2") TARGET_BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "", "avx2") @@ -576,7 +568,6 @@ TARGET_BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "", "avx2") -TARGET_BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLiC*", "", "avx2") TARGET_BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "", "avx2") TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8i", "", "avx2") TARGET_BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "", "avx2") @@ -648,7 +639,10 @@ TARGET_BUILTIN(__builtin_ia32_xsavec, "vv*ULLi", "", "xsavec") TARGET_BUILTIN(__builtin_ia32_xsaves, "vv*ULLi", "", "xsaves") //CLFLUSHOPT -TARGET_BUILTIN(__builtin_ia32_clflushopt, "vc*", "", "clflushopt") +TARGET_BUILTIN(__builtin_ia32_clflushopt, "vvC*", "", "clflushopt") + +//CLWB +TARGET_BUILTIN(__builtin_ia32_clwb, "vvC*", "", "clwb") // ADX TARGET_BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "", "adx") @@ -670,6 +664,12 @@ TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "", "bmi2") // TBM TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "", "tbm") +// LWP +TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "", "lwp") +TARGET_BUILTIN(__builtin_ia32_slwpcb, "v*", "", "lwp") +TARGET_BUILTIN(__builtin_ia32_lwpins32, "UcUiUiUi", "", "lwp") +TARGET_BUILTIN(__builtin_ia32_lwpval32, "vUiUiUi", "", "lwp") + // SHA TARGET_BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "", "sha") TARGET_BUILTIN(__builtin_ia32_sha1nexte, "V4iV4iV4i", "", "sha") @@ -976,8 +976,6 @@ TARGET_BUILTIN(__builtin_ia32_pmuldq512, "V8LLiV16iV16i", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_pmuludq512, "V8LLiV16iV16i", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16iiC*V16iUs", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLiLLiC*V8LLiUc", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loadups512_mask, "V16ffC*V16fUs", "", "avx512f") @@ -1074,8 +1072,6 @@ TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx51 TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_paddusw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pavgb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pavgw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxub512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") @@ -1103,6 +1099,9 @@ TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx5 TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd") TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd") +TARGET_BUILTIN(__builtin_ia32_vpopcntd_512, "V16iV16i", "", "avx512vpopcntdq") +TARGET_BUILTIN(__builtin_ia32_vpopcntq_512, "V8LLiV8LLi", "", "avx512vpopcntdq") + TARGET_BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") TARGET_BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw") TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw") @@ -1377,11 +1376,6 @@ TARGET_BUILTIN(__builtin_ia32_movdqa64load128_mask, "V2LLiV2LLiC*V2LLiUc","","av TARGET_BUILTIN(__builtin_ia32_movdqa64load256_mask, "V4LLiV4LLiC*V4LLiUc","","avx512vl") TARGET_BUILTIN(__builtin_ia32_movdqa64store128_mask, "vV2LLi*V2LLiUc","","avx512f") TARGET_BUILTIN(__builtin_ia32_movdqa64store256_mask, "vV4LLi*V4LLiUc","","avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb512_gpr_mask, "V64ccV64cULLi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb128_gpr_mask, "V16ccV16cUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb256_gpr_mask, "V32ccV32cUi","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd128_gpr_mask, "V4iiV4iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd256_gpr_mask, "V8iiV8iUc","","avx512vl") TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_maskz, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") TARGET_BUILTIN(__builtin_ia32_vpmadd52luq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") @@ -1592,14 +1586,6 @@ TARGET_BUILTIN(__builtin_ia32_broadcastmb128, "V2LLiUc","","avx512cd,avx512vl") TARGET_BUILTIN(__builtin_ia32_broadcastmb256, "V4LLiUc","","avx512cd,avx512vl") TARGET_BUILTIN(__builtin_ia32_broadcastmw128, "V4iUs","","avx512cd,avx512vl") TARGET_BUILTIN(__builtin_ia32_broadcastmw256, "V8iUs","","avx512cd,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_512_mask, "V16fV4fV16fUs","","avx512dq") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_512_mask, "V16iV4iV16iUs","","avx512dq") -TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_256_mask, "V8fV4fV8fUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_128_mask, "V4iV4iV4iUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_256_mask, "V8iV4iV8iUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw512_gpr_mask, "V32shV32sUi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw256_gpr_mask, "V16shV16sUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw128_gpr_mask, "V8ssV8sUc","","avx512bw,avx512vl") TARGET_BUILTIN(__builtin_ia32_pmovsdb512_mask, "V16cV16iV16cUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_pmovsdb512mem_mask, "vV16c*V16iUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_pmovswb512mem_mask, "vV32c*V32sUi","","avx512bw") @@ -1747,7 +1733,6 @@ TARGET_BUILTIN(__builtin_ia32_kortestzhi, "iUsUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_kunpckhi, "UsUsUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_kxnorhi, "UsUsUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_kxorhi, "UsUsUs","","avx512f") -TARGET_BUILTIN(__builtin_ia32_movntdqa512, "V8LLiV8LLi*","","avx512f") TARGET_BUILTIN(__builtin_ia32_palignr512_mask, "V64cV64cV64cIiV64cULLi","","avx512bw") TARGET_BUILTIN(__builtin_ia32_dbpsadbw128_mask, "V8sV16cV16cIiV8sUc","","avx512bw,avx512vl") TARGET_BUILTIN(__builtin_ia32_dbpsadbw256_mask, "V16sV32cV32cIiV16sUs","","avx512bw,avx512vl") @@ -1816,8 +1801,8 @@ TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx") TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero") // MSVC -TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") @@ -1832,6 +1817,16 @@ TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, "" TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + +TARGET_HEADER_BUILTIN(__readgsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef TARGET_BUILTIN #undef TARGET_HEADER_BUILTIN diff --git a/include/clang/Basic/BuiltinsX86_64.def b/include/clang/Basic/BuiltinsX86_64.def index d38f522c38..6e120672ff 100644 --- a/include/clang/Basic/BuiltinsX86_64.def +++ b/include/clang/Basic/BuiltinsX86_64.def @@ -22,8 +22,8 @@ # define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS) #endif -TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") @@ -69,9 +69,8 @@ TARGET_BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "", "bmi2") TARGET_BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "", "bmi2") TARGET_BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "", "bmi2") TARGET_BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "", "tbm") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq128_gpr_mask, "V2LLiULLiV2LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq256_gpr_mask, "V4LLiULLiV4LLiUc","","avx512vl") +TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcULLiUiUi", "", "lwp") +TARGET_BUILTIN(__builtin_ia32_lwpval64, "vULLiUiUi", "", "lwp") TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "LLiV2dIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_vcvtsd2usi64, "ULLiV2dIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_vcvtss2si64, "LLiV4fIi","","avx512f") diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt index e4929b5b52..821c405913 100644 --- a/include/clang/Basic/CMakeLists.txt +++ b/include/clang/Basic/CMakeLists.txt @@ -9,10 +9,12 @@ clang_diag_gen(Analysis) clang_diag_gen(AST) clang_diag_gen(Comment) clang_diag_gen(Common) +clang_diag_gen(CrossTU) clang_diag_gen(Driver) clang_diag_gen(Frontend) clang_diag_gen(Lex) clang_diag_gen(Parse) +clang_diag_gen(Refactoring) clang_diag_gen(Sema) clang_diag_gen(Serialization) clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups @@ -28,6 +30,11 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list SOURCE Attr.td TARGET ClangAttrList) +clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrSubjectMatchRuleList) + clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE Attr.td diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h index dd9c55431e..cc27bbb48e 100644 --- a/include/clang/Basic/CharInfo.h +++ b/include/clang/Basic/CharInfo.h @@ -40,14 +40,14 @@ namespace charinfo { } // end namespace charinfo /// Returns true if this is an ASCII character. -LLVM_READNONE static inline bool isASCII(char c) { +LLVM_READNONE inline bool isASCII(char c) { return static_cast<unsigned char>(c) <= 127; } /// Returns true if this is a valid first character of a C identifier, /// which is [a-zA-Z_]. -LLVM_READONLY static inline bool isIdentifierHead(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isIdentifierHead(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER)) return true; @@ -56,8 +56,8 @@ LLVM_READONLY static inline bool isIdentifierHead(unsigned char c, /// Returns true if this is a body character of a C identifier, /// which is [a-zA-Z0-9_]. -LLVM_READONLY static inline bool isIdentifierBody(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isIdentifierBody(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER)) return true; @@ -68,7 +68,7 @@ LLVM_READONLY static inline bool isIdentifierBody(unsigned char c, /// ' ', '\\t', '\\f', '\\v'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) { +LLVM_READONLY inline bool isHorizontalWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0; } @@ -76,7 +76,7 @@ LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) { /// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) { +LLVM_READONLY inline bool isVerticalWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_VERT_WS) != 0; } @@ -85,43 +85,43 @@ LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) { /// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isWhitespace(unsigned char c) { +LLVM_READONLY inline bool isWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0; } /// Return true if this character is an ASCII digit: [0-9] -LLVM_READONLY static inline bool isDigit(unsigned char c) { +LLVM_READONLY inline bool isDigit(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_DIGIT) != 0; } /// Return true if this character is a lowercase ASCII letter: [a-z] -LLVM_READONLY static inline bool isLowercase(unsigned char c) { +LLVM_READONLY inline bool isLowercase(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_LOWER) != 0; } /// Return true if this character is an uppercase ASCII letter: [A-Z] -LLVM_READONLY static inline bool isUppercase(unsigned char c) { +LLVM_READONLY inline bool isUppercase(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_UPPER) != 0; } /// Return true if this character is an ASCII letter: [a-zA-Z] -LLVM_READONLY static inline bool isLetter(unsigned char c) { +LLVM_READONLY inline bool isLetter(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0; } /// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9] -LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) { +LLVM_READONLY inline bool isAlphanumeric(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0; } /// Return true if this character is an ASCII hex digit: [0-9a-fA-F] -LLVM_READONLY static inline bool isHexDigit(unsigned char c) { +LLVM_READONLY inline bool isHexDigit(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0; } @@ -129,7 +129,7 @@ LLVM_READONLY static inline bool isHexDigit(unsigned char c) { /// Return true if this character is an ASCII punctuation character. /// /// Note that '_' is both a punctuation character and an identifier character! -LLVM_READONLY static inline bool isPunctuation(unsigned char c) { +LLVM_READONLY inline bool isPunctuation(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0; } @@ -137,7 +137,7 @@ LLVM_READONLY static inline bool isPunctuation(unsigned char c) { /// Return true if this character is an ASCII printable character; that is, a /// character that should take exactly one column to print in a fixed-width /// terminal. -LLVM_READONLY static inline bool isPrintable(unsigned char c) { +LLVM_READONLY inline bool isPrintable(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT| CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0; @@ -145,14 +145,14 @@ LLVM_READONLY static inline bool isPrintable(unsigned char c) { /// Return true if this is the body character of a C preprocessing number, /// which is [a-zA-Z0-9_.]. -LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) { +LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0; } /// Return true if this is the body character of a C++ raw string delimiter. -LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) { +LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD| CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0; @@ -162,7 +162,7 @@ LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) { /// Converts the given ASCII character to its lowercase equivalent. /// /// If the character is not an uppercase character, it is returned as is. -LLVM_READONLY static inline char toLowercase(char c) { +LLVM_READONLY inline char toLowercase(char c) { if (isUppercase(c)) return c + 'a' - 'A'; return c; @@ -171,7 +171,7 @@ LLVM_READONLY static inline char toLowercase(char c) { /// Converts the given ASCII character to its uppercase equivalent. /// /// If the character is not a lowercase character, it is returned as is. -LLVM_READONLY static inline char toUppercase(char c) { +LLVM_READONLY inline char toUppercase(char c) { if (isLowercase(c)) return c + 'A' - 'a'; return c; @@ -182,7 +182,7 @@ LLVM_READONLY static inline char toUppercase(char c) { /// /// Note that this is a very simple check; it does not accept '$' or UCNs as /// valid identifier characters. -LLVM_READONLY static inline bool isValidIdentifier(StringRef S) { +LLVM_READONLY inline bool isValidIdentifier(StringRef S) { if (S.empty() || !isIdentifierHead(S[0])) return false; diff --git a/include/clang/Basic/Cuda.h b/include/clang/Basic/Cuda.h index ad1139b8c1..1a0731c37a 100644 --- a/include/clang/Basic/Cuda.h +++ b/include/clang/Basic/Cuda.h @@ -21,6 +21,8 @@ enum class CudaVersion { CUDA_70, CUDA_75, CUDA_80, + CUDA_90, + LATEST = CUDA_90, }; const char *CudaVersionToString(CudaVersion V); @@ -41,6 +43,7 @@ enum class CudaArch { SM_60, SM_61, SM_62, + SM_70, }; const char *CudaArchToString(CudaArch A); @@ -60,6 +63,7 @@ enum class CudaVirtualArch { COMPUTE_60, COMPUTE_61, COMPUTE_62, + COMPUTE_70, }; const char *CudaVirtualArchToString(CudaVirtualArch A); @@ -72,6 +76,9 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A); /// Get the earliest CudaVersion that supports the given CudaArch. CudaVersion MinVersionForCudaArch(CudaArch A); +/// Get the latest CudaVersion that supports the given CudaArch. +CudaVersion MaxVersionForCudaArch(CudaArch A); + } // namespace clang #endif diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index ffce99bf9f..22cded21c1 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -178,12 +178,7 @@ public: private: unsigned char AllExtensionsSilenced; // Used by __extension__ - bool IgnoreAllWarnings; // Ignore all warnings: -w - bool WarningsAsErrors; // Treat warnings like errors. - bool EnableAllWarnings; // Enable all warnings. - bool ErrorsAsFatal; // Treat errors like fatal errors. - bool FatalsAsError; // Treat fatal errors like errors. - bool SuppressSystemWarnings; // Suppress warnings in system headers. + bool SuppressAfterFatalError; // Suppress diagnostics after a fatal error? bool SuppressAllDiagnostics; // Suppress all diagnostics. bool ElideType; // Elide common types of templates. bool PrintTemplateTree; // Print a tree when comparing templates. @@ -194,7 +189,6 @@ private: // 0 -> no limit. unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation // backtrace stack, 0 -> no limit. - diag::Severity ExtBehavior; // Map extensions to warnings or errors? IntrusiveRefCntPtr<DiagnosticIDs> Diags; IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; DiagnosticConsumer *Client; @@ -216,6 +210,19 @@ private: llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap; public: + // "Global" configuration state that can actually vary between modules. + unsigned IgnoreAllWarnings : 1; // Ignore all warnings: -w + unsigned EnableAllWarnings : 1; // Enable all warnings. + unsigned WarningsAsErrors : 1; // Treat warnings like errors. + unsigned ErrorsAsFatal : 1; // Treat errors like fatal errors. + unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers. + diag::Severity ExtBehavior; // Map extensions to warnings or errors? + + DiagState() + : IgnoreAllWarnings(false), EnableAllWarnings(false), + WarningsAsErrors(false), ErrorsAsFatal(false), + SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {} + typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator; typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator const_iterator; @@ -223,6 +230,9 @@ private: void setMapping(diag::kind Diag, DiagnosticMapping Info) { DiagMap[Diag] = Info; } + DiagnosticMapping lookupMapping(diag::kind Diag) const { + return DiagMap.lookup(Diag); + } DiagnosticMapping &getOrAddMapping(diag::kind Diag); @@ -490,33 +500,47 @@ public: /// \brief When set to true, any unmapped warnings are ignored. /// /// If this and WarningsAsErrors are both set, then this one wins. - void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } - bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } + void setIgnoreAllWarnings(bool Val) { + GetCurDiagState()->IgnoreAllWarnings = Val; + } + bool getIgnoreAllWarnings() const { + return GetCurDiagState()->IgnoreAllWarnings; + } /// \brief When set to true, any unmapped ignored warnings are no longer /// ignored. /// /// If this and IgnoreAllWarnings are both set, then that one wins. - void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; } - bool getEnableAllWarnings() const { return EnableAllWarnings; } + void setEnableAllWarnings(bool Val) { + GetCurDiagState()->EnableAllWarnings = Val; + } + bool getEnableAllWarnings() const { + return GetCurDiagState()->EnableAllWarnings; + } /// \brief When set to true, any warnings reported are issued as errors. - void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } - bool getWarningsAsErrors() const { return WarningsAsErrors; } + void setWarningsAsErrors(bool Val) { + GetCurDiagState()->WarningsAsErrors = Val; + } + bool getWarningsAsErrors() const { + return GetCurDiagState()->WarningsAsErrors; + } /// \brief When set to true, any error reported is made a fatal error. - void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; } - bool getErrorsAsFatal() const { return ErrorsAsFatal; } + void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; } + bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; } - /// \brief When set to true, any fatal error reported is made an error. - /// - /// This setting takes precedence over the setErrorsAsFatal setting above. - void setFatalsAsError(bool Val) { FatalsAsError = Val; } - bool getFatalsAsError() const { return FatalsAsError; } + /// \brief When set to true (the default), suppress further diagnostics after + /// a fatal error. + void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; } /// \brief When set to true mask warnings that come from system headers. - void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } - bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + void setSuppressSystemWarnings(bool Val) { + GetCurDiagState()->SuppressSystemWarnings = Val; + } + bool getSuppressSystemWarnings() const { + return GetCurDiagState()->SuppressSystemWarnings; + } /// \brief Suppress all diagnostics, to silence the front end when we /// know that we don't want any more diagnostics to be passed along to the @@ -568,11 +592,15 @@ public: } /// \brief Controls whether otherwise-unmapped extension diagnostics are - /// mapped onto ignore/warning/error. + /// mapped onto ignore/warning/error. /// /// This corresponds to the GCC -pedantic and -pedantic-errors option. - void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; } - diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; } + void setExtensionHandlingBehavior(diag::Severity H) { + GetCurDiagState()->ExtBehavior = H; + } + diag::Severity getExtensionHandlingBehavior() const { + return GetCurDiagState()->ExtBehavior; + } /// \brief Counter bumped when an __extension__ block is/ encountered. /// diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td index 39da0060dd..52ccf350e6 100644 --- a/include/clang/Basic/Diagnostic.td +++ b/include/clang/Basic/Diagnostic.td @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +// See the Internals Manual, section The Diagnostics Subsystem for an overview. + // Define the diagnostic severities. class Severity<string N> { string Name = N; @@ -100,10 +102,20 @@ class SuppressInSystemHeader { class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure { bit ShowInSystemHeader = 1; } +// Warnings default to on (but can be default-off'd with DefaultIgnore). +// This is used for warnings about questionable code; warnings about +// accepted language extensions should use Extension or ExtWarn below instead. class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>; +// Remarks can be turned on with -R flags and provide commentary, e.g. on +// optimizer decisions. class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>; +// Extensions are warnings about accepted language extensions. +// Extension warnings are default-off but enabled by -pedantic. class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>; +// ExtWarns are warnings about accepted language extensions. +// ExtWarn warnings are default-on. class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>; +// Notes can provide supplementary information on errors, warnings, and remarks. class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>; @@ -121,10 +133,12 @@ include "DiagnosticASTKinds.td" include "DiagnosticAnalysisKinds.td" include "DiagnosticCommentKinds.td" include "DiagnosticCommonKinds.td" +include "DiagnosticCrossTUKinds.td" include "DiagnosticDriverKinds.td" include "DiagnosticFrontendKinds.td" include "DiagnosticLexKinds.td" include "DiagnosticParseKinds.td" +include "DiagnosticRefactoringKinds.td" include "DiagnosticSemaKinds.td" include "DiagnosticSerializationKinds.td" diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 652d062785..215580b2e9 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -127,6 +127,10 @@ def note_constexpr_access_null : Note< def note_constexpr_access_past_end : Note< "%select{read of|assignment to|increment of|decrement of}0 " "dereferenced one-past-the-end pointer is not allowed in a constant expression">; +def note_constexpr_access_unsized_array : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "pointer to element of array without known bound " + "is not allowed in a constant expression">; def note_constexpr_access_inactive_union_member : Note< "%select{read of|assignment to|increment of|decrement of}0 " "member %1 of union with %select{active member %3|no active member}2 " @@ -154,6 +158,11 @@ def note_constexpr_baa_insufficient_alignment : Note< def note_constexpr_baa_value_insufficient_alignment : Note< "value of the aligned pointer (%0) is not a multiple of the asserted %1 " "%plural{1:byte|:bytes}1">; +def note_constexpr_unsupported_unsized_array : Note< + "array-to-pointer decay of array member without known bound is not supported">; +def note_constexpr_unsized_array_indexed : Note< + "indexing of array without known bound is not allowed " + "in a constant expression">; def warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, @@ -200,12 +209,17 @@ def note_odr_defined_here : Note<"also defined here">; def err_odr_function_type_inconsistent : Error< "external function %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; -def warn_odr_tag_type_inconsistent : Warning< - "type %0 has incompatible definitions in different translation units">, - InGroup<DiagGroup<"odr">>; +def warn_odr_tag_type_inconsistent + : Warning<"type %0 has incompatible definitions in different translation " + "units">, + InGroup<DiagGroup<"odr">>; +def err_odr_tag_type_inconsistent + : Error<"type %0 has incompatible definitions in different translation " + "units">; def note_odr_tag_kind_here: Note< "%0 is a %select{struct|interface|union|class|enum}1 here">; def note_odr_field : Note<"field %0 has type %1 here">; +def note_odr_field_name : Note<"field has name %0 here">; def note_odr_missing_field : Note<"no corresponding field here">; def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; def note_odr_not_bit_field : Note<"field %0 is not a bit-field">; diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index b8293f08c5..98fd3c4d57 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -90,10 +90,10 @@ def err_module_unavailable : Error< "module '%0' %select{is incompatible with|requires}1 feature '%2'">; def err_module_header_missing : Error< "%select{|umbrella }0header '%1' not found">; -def err_module_lock_failure : Error< - "could not acquire lock file for module '%0': %1">, DefaultFatal; -def err_module_lock_timeout : Error< - "timed out waiting to acquire lock file for module '%0'">, DefaultFatal; +def remark_module_lock_failure : Remark< + "could not acquire lock file for module '%0': %1">, InGroup<ModuleBuild>; +def remark_module_lock_timeout : Remark< + "timed out waiting to acquire lock file for module '%0'">, InGroup<ModuleBuild>; def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, DefaultFatal; def err_module_prebuilt : Error< diff --git a/include/clang/Basic/DiagnosticCrossTUKinds.td b/include/clang/Basic/DiagnosticCrossTUKinds.td new file mode 100644 index 0000000000..8b6d8b6814 --- /dev/null +++ b/include/clang/Basic/DiagnosticCrossTUKinds.td @@ -0,0 +1,18 @@ +//==--- DiagnosticCrossTUKinds.td - Cross Translation Unit diagnostics ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "CrossTU" in { + +def err_fnmap_parsing : Error< + "error parsing index file: '%0' line: %1 'UniqueID filename' format " + "expected">; + +def err_multiple_def_index : Error< + "multiple definitions are found for the same key in index ">; +} diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index b02599c8ae..dd72c958d1 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -29,9 +29,10 @@ def err_drv_no_cuda_installation : Error< def err_drv_no_cuda_libdevice : Error< "cannot find libdevice for %0. Provide path to different CUDA installation " "via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; -def err_drv_cuda_version_too_low : Error< - "GPU arch %1 requires CUDA version at least %3, but installation at %0 is %2. " - "Use --cuda-path to specify a different CUDA install, or pass " +def err_drv_cuda_version_unsupported : Error< + "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " + "but installation at %3 is %4. Use --cuda-path to specify a different CUDA " + "install, pass a different GPU arch with --cuda-gpu-arch, or pass " "--no-cuda-version-check.">; def err_drv_cuda_nvptx_host : Error<"unsupported use of NVPTX for host compilation.">; def err_drv_invalid_thread_model_for_target : Error< @@ -69,6 +70,10 @@ def err_drv_invalid_Xarch_argument_with_args : Error< "invalid Xarch argument: '%0', options requiring arguments are unsupported">; def err_drv_invalid_Xarch_argument_isdriver : Error< "invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">; +def err_drv_Xopenmp_target_missing_triple : Error< + "cannot deduce implicit triple value for -Xopenmp-target, specify triple using -Xopenmp-target=<triple>">; +def err_drv_invalid_Xopenmp_target_with_args : Error< + "invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">; def err_drv_argument_only_allowed_with : Error< "invalid argument '%0' only allowed with '%1'">; def err_drv_argument_not_allowed_with : Error< @@ -85,6 +90,8 @@ def err_drv_clang_unsupported : Error< "the clang compiler does not support '%0'">; def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error< "the clang compiler does not support '%0' for C++ on Darwin/i386">; +def err_drv_clang_unsupported_opt_faltivec : Error< + "the clang compiler does not support '%0', %1">; def err_drv_command_failed : Error< "%0 command failed with exit code %1 (use -v to see invocation)">; def err_drv_compilationdatabase : Error< @@ -92,9 +99,13 @@ def err_drv_compilationdatabase : Error< def err_drv_command_signalled : Error< "%0 command failed due to signal (use -v to see invocation)">; def err_drv_force_crash : Error< - "failing because environment variable '%0' is set">; + "failing because %select{environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set|'-gen-reproducer' is used}0">; def err_drv_invalid_mfloat_abi : Error< "invalid float ABI '%0'">; +def err_drv_invalid_mtp : Error< + "invalid thread pointer reading mode '%0'">; +def err_drv_missing_arg_mtp : Error< + "missing argument to '%0'">; def err_drv_invalid_libcxx_deployment : Error< "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; def err_drv_invalid_argument_to_fdebug_prefix_map : Error< @@ -104,6 +115,10 @@ def err_drv_malformed_sanitizer_blacklist : Error< def err_target_unsupported_arch : Error<"the target architecture '%0' is not supported by the target '%1'">; +def err_cpu_unsupported_isa + : Error<"CPU '%0' does not support '%1' execution mode">; +def err_arch_unsupported_isa + : Error<"Architecture '%0' does not support '%1' execution mode">; def err_drv_I_dash_not_supported : Error< "'%0' not supported, please use -iquote instead">; @@ -136,6 +151,10 @@ def err_drv_cc_print_options_failure : Error< def err_drv_lto_without_lld : Error<"LTO requires -fuse-ld=lld">; def err_drv_preamble_format : Error< "incorrect format for -preamble-bytes=N,END">; +def warn_invalid_ios_deployment_target : Warning< + "invalid iOS deployment version '%0', iOS 10 is the maximum deployment " + "target for 32-bit targets">, InGroup<InvalidIOSDeploymentTarget>, + DefaultError; def err_drv_conflicting_deployment_targets : Error< "conflicting deployment targets, both '%0' and '%1' are present in environment">; def err_arc_unsupported_on_runtime : Error< @@ -173,6 +192,8 @@ def warn_drv_optimization_value : Warning<"optimization level '%0' is not suppor InGroup<InvalidCommandLineArgument>; def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">, InGroup<IgnoredOptimizationArgument>; +def warn_ignored_clang_option : Warning<"the flag '%0' has been deprecated and will be ignored">, + InGroup<UnusedCommandLineArgument>; def warn_drv_unsupported_opt_for_target : Warning< "optimization flag '%0' is not supported for target '%1'">, InGroup<IgnoredOptimizationArgument>; @@ -193,8 +214,8 @@ def warn_drv_unused_argument : Warning< def warn_drv_empty_joined_argument : Warning< "joined argument expects additional value: '%0'">, InGroup<UnusedCommandLineArgument>; -def warn_drv_fdiagnostics_show_hotness_requires_pgo : Warning< - "argument '-fdiagnostics-show-hotness' requires profile-guided optimization information">, +def warn_drv_diagnostics_hotness_requires_pgo : Warning< + "argument '%0' requires profile-guided optimization information">, InGroup<UnusedCommandLineArgument>; def warn_drv_clang_unsupported : Warning< "the clang compiler does not support '%0'">; @@ -223,7 +244,10 @@ def warn_drv_enabling_rtti_with_exceptions : Warning< InGroup<DiagGroup<"rtti-for-exceptions">>; def warn_drv_disabling_vptr_no_rtti_default : Warning< "implicitly disabling vptr sanitizer because rtti wasn't enabled">, - InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>; + InGroup<AutoDisableVptrSanitizer>; +def warn_drv_object_size_disabled_O0 : Warning< + "the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">, + InGroup<InvalidCommandLineArgument>; def note_drv_command_failed_diag_msg : Note< "diagnostic msg: %0">; @@ -231,13 +255,18 @@ 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 note_drv_use_standard : Note<"use '%0' for '%1' standard">; +def note_drv_use_standard : Note<"use '%0'" + "%select{| or '%3'|, '%3', or '%4'|, '%3', '%4', or '%5'}2 " + "for '%1' standard">; def err_analyzer_config_no_value : Error< "analyzer-config option '%0' has a key but no value">; def err_analyzer_config_multiple_values : Error< "analyzer-config option '%0' should contain only one '='">; +def err_drv_invalid_hvx_length : Error< + "-mhvx-length is not supported without a -mhvx/-mhvx= flag">; + def err_drv_modules_validate_once_requires_timestamp : Error< "option '-fmodules-validate-once-per-build-session' requires " "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">; @@ -264,9 +293,27 @@ def warn_target_unsupported_nan2008 : Warning< def warn_target_unsupported_nanlegacy : Warning< "ignoring '-mnan=legacy' option because the '%0' architecture does not support it">, InGroup<UnsupportedNan>; +def warn_target_unsupported_abslegacy : Warning< + "ignoring '-mabs=legacy' option because the '%0' architecture does not support it">, + InGroup<UnsupportedAbs>; +def warn_target_unsupported_abs2008 : Warning< + "ignoring '-mabs=2008' option because the '%0' architecture does not support it">, + InGroup<UnsupportedAbs>; def warn_target_unsupported_compact_branches : Warning< "ignoring '-mcompact-branches=' option because the '%0' architecture does not" " support it">, InGroup<UnsupportedCB>; +def warn_drv_unsupported_gpopt : Warning< + "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" + " usage of }0-mabicalls">, + InGroup<UnsupportedGPOpt>; +def warn_drv_unsupported_longcalls : Warning< + "ignoring '-mlong-calls' option as it is not currently supported with " + "%select{|the implicit usage of }0-mabicalls">, + InGroup<OptionIgnored>; +def warn_drv_unsupported_abicalls : Warning< + "ignoring '-mabicalls' option as it cannot be used with " + "non position-independent code and the N64 ABI">, + InGroup<OptionIgnored>; def warn_drv_unable_to_find_directory_expected : Warning< "unable to find %0 directory, expected to be in '%1'">, @@ -283,4 +330,12 @@ def warn_drv_ps4_sdk_dir : Warning< def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">; def err_drv_defsym_invalid_format : Error<"defsym must be of the form: sym=value: %0">; def err_drv_defsym_invalid_symval : Error<"Value is not an integer: %0">; +def warn_drv_msvc_not_found : Warning< + "unable to find a Visual Studio installation; " + "try running Clang from a developer command prompt">, + InGroup<DiagGroup<"msvc-not-found">>; + +def warn_drv_fine_grained_bitfield_accesses_ignored : Warning< + "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">, + InGroup<OptionIgnored>; } diff --git a/include/clang/Basic/DiagnosticError.h b/include/clang/Basic/DiagnosticError.h new file mode 100644 index 0000000000..6b4b073736 --- /dev/null +++ b/include/clang/Basic/DiagnosticError.h @@ -0,0 +1,61 @@ +//===--- DiagnosticError.h - Diagnostic payload for llvm::Error -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Error.h" + +namespace clang { + +/// \brief Carries a Clang diagnostic in an llvm::Error. +/// +/// Users should emit the stored diagnostic using the DiagnosticsEngine. +class DiagnosticError : public llvm::ErrorInfo<DiagnosticError> { +public: + DiagnosticError(PartialDiagnosticAt Diag) : Diag(std::move(Diag)) {} + + void log(raw_ostream &OS) const override { OS << "clang diagnostic"; } + + PartialDiagnosticAt &getDiagnostic() { return Diag; } + const PartialDiagnosticAt &getDiagnostic() const { return Diag; } + + /// Creates a new \c DiagnosticError that contains the given diagnostic at + /// the given location. + static llvm::Error create(SourceLocation Loc, PartialDiagnostic Diag) { + return llvm::make_error<DiagnosticError>( + PartialDiagnosticAt(Loc, std::move(Diag))); + } + + /// Extracts and returns the diagnostic payload from the given \c Error if + /// the error is a \c DiagnosticError. Returns none if the given error is not + /// a \c DiagnosticError. + static Optional<PartialDiagnosticAt> take(llvm::Error &Err) { + Optional<PartialDiagnosticAt> Result; + Err = llvm::handleErrors(std::move(Err), [&](DiagnosticError &E) { + Result = std::move(E.getDiagnostic()); + }); + return Result; + } + + static char ID; + +private: + // Users are not expected to use error_code. + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + + PartialDiagnosticAt Diag; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 1267f8d09f..392a340a3b 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -116,6 +116,8 @@ def err_fe_action_not_available : Error< "action %0 not compiled in">; def err_fe_invalid_alignment : Error< "invalid value '%1' in '%0'; alignment must be a power of 2">; +def err_fe_invalid_wchar_type + : Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">; def warn_fe_serialized_diag_merge_failure : Warning< "unable to merge a subprocess's serialized diagnostics">, @@ -179,6 +181,8 @@ def warn_incompatible_analyzer_plugin_api : Warning< def note_incompatible_analyzer_plugin_api : Note< "current API version is '%0', but plugin was compiled with version '%1'">; +def err_module_build_requires_fmodules : Error< + "module compilation requires '-fmodules'">; def err_module_interface_requires_modules_ts : Error< "module interface compilation requires '-fmodules-ts'">; def warn_module_config_mismatch : Warning< @@ -196,6 +200,7 @@ def err_no_submodule_suggest : Error< "no submodule named %0 in module '%1'; did you mean '%2'?">; def warn_missing_submodule : Warning<"missing submodule '%0'">, InGroup<IncompleteUmbrella>; +def note_module_import_here : Note<"module imported here">; def err_module_cannot_create_includes : Error< "cannot create includes file for module %0: %1">; def warn_module_config_macro_undef : Warning< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 6153b8e7ed..c23183c81a 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -27,14 +27,23 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; def GNUAutoType : DiagGroup<"gnu-auto-type">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; +def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">; def Availability : DiagGroup<"availability">; def Section : DiagGroup<"section">; def AutoImport : DiagGroup<"auto-import">; def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">; +def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">; def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">; +def BinaryLiteral : DiagGroup<"binary-literal", [CXX14BinaryLiteral, + CXXPre14CompatBinaryLiteral, + GNUBinaryLiteral]>; def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">; def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; +def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">; def BitFieldWidth : DiagGroup<"bitfield-width">; +def CoroutineMissingUnhandledException : + DiagGroup<"coroutine-missing-unhandled-exception">; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>; def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; def LiteralConversion : DiagGroup<"literal-conversion">; @@ -56,7 +65,9 @@ def FloatConversion : def DoublePromotion : DiagGroup<"double-promotion">; def EnumTooLarge : DiagGroup<"enum-too-large">; def UnsupportedNan : DiagGroup<"unsupported-nan">; +def UnsupportedAbs : DiagGroup<"unsupported-abs">; def UnsupportedCB : DiagGroup<"unsupported-cb">; +def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">; def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; def NullConversion : DiagGroup<"null-conversion">; def ImplicitConversionFloatingPointToBool : @@ -83,6 +94,7 @@ def GNUStringLiteralOperatorTemplate : DiagGroup<"gnu-string-literal-operator-template">; def UndefinedVarTemplate : DiagGroup<"undefined-var-template">; def UndefinedFuncTemplate : DiagGroup<"undefined-func-template">; +def MissingNoEscape : DiagGroup<"missing-noescape">; def DeleteIncomplete : DiagGroup<"delete-incomplete">; def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; @@ -94,7 +106,9 @@ def CXX11CompatDeprecatedWritableStr : def DeprecatedAttributes : DiagGroup<"deprecated-attributes">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; -def UnguardedAvailability : DiagGroup<"unguarded-availability">; +def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">; +def UnguardedAvailability : DiagGroup<"unguarded-availability", + [UnguardedAvailabilityNew]>; // partial-availability is an alias of unguarded-availability. def : DiagGroup<"partial-availability", [UnguardedAvailability]>; def DeprecatedDynamicExceptionSpec @@ -146,13 +160,24 @@ def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; +def InvalidIOSDeploymentTarget : DiagGroup<"invalid-ios-deployment-target">; + +def CXX17CompatMangling : DiagGroup<"c++17-compat-mangling">; +def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>; +// Name of this warning in GCC. +def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>; + // Warnings for C++1y code which is not compatible with prior C++ standards. def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", - [CXXPre14Compat]>; -def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; -def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", - [CXXPre1zCompat]>; + [CXXPre14Compat, + CXXPre14CompatBinaryLiteral]>; +def CXXPre17Compat : DiagGroup<"c++98-c++11-c++14-compat">; +def CXXPre17CompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", + [CXXPre17Compat]>; +def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">; +def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", + [CXXPre2aCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -165,13 +190,15 @@ def CXX98Compat : DiagGroup<"c++98-compat", [CXX98CompatLocalTypeTemplateArgs, CXX98CompatUnnamedTypeTemplateArgs, CXXPre14Compat, - CXXPre1zCompat]>; + CXXPre17Compat, + CXXPre2aCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, CXX98CompatBindToTemporaryCopy, CXXPre14CompatPedantic, - CXXPre1zCompatPedantic]>; + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; @@ -196,18 +223,34 @@ def CXX11Compat : DiagGroup<"c++11-compat", CXX11CompatReservedUserDefinedLiteral, CXX11CompatDeprecatedWritableStr, CXXPre14Compat, - CXXPre1zCompat]>; + CXXPre17Compat, + CXXPre2aCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", - [CXXPre14CompatPedantic, - CXXPre1zCompatPedantic]>; + [CXX11Compat, + CXXPre14CompatPedantic, + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; -def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; +def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre17Compat, + CXXPre2aCompat]>; def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", - [CXXPre1zCompatPedantic]>; - -def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister, - DeprecatedIncrementBool]>; + [CXX14Compat, + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; + +def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister, + DeprecatedIncrementBool, + CXX17CompatMangling, + CXXPre2aCompat]>; +def CXX17CompatPedantic : DiagGroup<"c++17-compat-pedantic", + [CXX17Compat, + CXXPre2aCompatPedantic]>; +def : DiagGroup<"c++1z-compat", [CXX17Compat]>; + +def CXX2aCompat : DiagGroup<"c++2a-compat">; +def CXX2aCompatPedantic : DiagGroup<"c++2a-compat-pedantic", + [CXX2aCompat]>; def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; @@ -301,8 +344,10 @@ def NonPODVarargs : DiagGroup<"non-pod-varargs">; def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>; def : DiagGroup<"nonportable-cfstrings">; def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; +def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">; def : DiagGroup<"effc++", [NonVirtualDtor]>; def OveralignedType : DiagGroup<"over-aligned">; +def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">; def OldStyleCast : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; @@ -329,6 +374,7 @@ def ObjCRootClass : DiagGroup<"objc-root-class">; def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">; def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; +def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; @@ -389,12 +435,18 @@ def StringCompare : DiagGroup<"string-compare">; def StringPlusInt : DiagGroup<"string-plus-int">; def StringPlusChar : DiagGroup<"string-plus-char">; def StrncatSize : DiagGroup<"strncat-size">; +def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">; +def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">; def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; +def TautologicalConstantCompare : DiagGroup<"tautological-constant-compare", + [TautologicalUnsignedZeroCompare, + TautologicalUnsignedEnumZeroCompare, + TautologicalOutOfRangeCompare]>; def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">; def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">; def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">; def TautologicalCompare : DiagGroup<"tautological-compare", - [TautologicalOutOfRangeCompare, + [TautologicalConstantCompare, TautologicalPointerCompare, TautologicalOverlapCompare, TautologicalUndefinedCompare]>; @@ -438,6 +490,8 @@ def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; def SwitchBool : DiagGroup<"switch-bool">; def SwitchEnum : DiagGroup<"switch-enum">; def Switch : DiagGroup<"switch">; +def EnumCompareSwitch : DiagGroup<"enum-compare-switch">; +def EnumCompare : DiagGroup<"enum-compare", [EnumCompareSwitch]>; def ImplicitFallthroughPerFunction : DiagGroup<"implicit-fallthrough-per-function">; def ImplicitFallthrough : DiagGroup<"implicit-fallthrough", @@ -457,9 +511,16 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">; def UnknownPragmas : DiagGroup<"unknown-pragmas">; def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>; -def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>; +def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">; +def PragmaPackSuspiciousInclude : DiagGroup<"pragma-pack-suspicious-include">; +def PragmaPack : DiagGroup<"pragma-pack", [PragmaPackSuspiciousInclude]>; +def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas, + PragmaClangAttribute, PragmaPack]>; def UnknownWarningOption : DiagGroup<"unknown-warning-option">; def NSobjectAttribute : DiagGroup<"NSObject-attribute">; +def NSConsumedMismatch : DiagGroup<"nsconsumed-mismatch">; +def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">; + def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">; def UnknownAttributes : DiagGroup<"unknown-attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; @@ -480,6 +541,7 @@ def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">; def UnneededMemberFunction : DiagGroup<"unneeded-member-function">; def UnusedPrivateField : DiagGroup<"unused-private-field">; def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>; +def UnusedTemplate : DiagGroup<"unused-template", [UnneededInternalDecl]>; def UnusedMemberFunction : DiagGroup<"unused-member-function", [UnneededMemberFunction]>; def UnusedLabel : DiagGroup<"unused-label">; @@ -606,6 +668,7 @@ def Conversion : DiagGroup<"conversion", [BoolConversion, ConstantConversion, EnumConversion, + BitFieldEnumConversion, FloatConversion, Shorten64To32, IntConversion, @@ -620,6 +683,7 @@ def Conversion : DiagGroup<"conversion", def Unused : DiagGroup<"unused", [UnusedArgument, UnusedFunction, UnusedLabel, // UnusedParameter, (matches GCC's behavior) + // UnusedTemplate, (clean-up libc++ before enabling) // UnusedMemberFunction, (clean-up llvm before enabling) UnusedPrivateField, UnusedLambdaCapture, UnusedLocalTypedef, UnusedValue, UnusedVariable, @@ -657,7 +721,8 @@ def Extra : DiagGroup<"extra", [ SemiBeforeMethodBody, MissingMethodReturnType, SignCompare, - UnusedParameter + UnusedParameter, + NullPointerArithmetic ]>; def Most : DiagGroup<"most", [ @@ -686,6 +751,7 @@ def Most : DiagGroup<"most", [ VolatileRegisterVar, ObjCMissingSuperCalls, ObjCDesignatedInit, + ObjCFlexibleArray, OverloadedVirtual, PrivateExtern, SelTypeCast, @@ -724,6 +790,7 @@ def Pedantic : DiagGroup<"pedantic">; // Aliases. def : DiagGroup<"", [Extra]>; // -W = -Wextra def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens +def : DiagGroup<"cpp", [PoundWarning]>; // -Wcpp = -W#warnings def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment def : DiagGroup<"conversion-null", [NullConversion]>; // -Wconversion-null = -Wnull-conversion @@ -750,12 +817,17 @@ def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11InlineNamespace, // earlier C++ versions. def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>; -// A warning group for warnings about using C++1z features as extensions in +// A warning group for warnings about using C++17 features as extensions in +// earlier C++ versions. +def CXX17 : DiagGroup<"c++17-extensions">; + +// A warning group for warnings about using C++2a features as extensions in // earlier C++ versions. -def CXX1z : DiagGroup<"c++1z-extensions">; +def CXX2a : DiagGroup<"c++2a-extensions">; def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; +def : DiagGroup<"c++1z-extensions", [CXX17]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; @@ -818,6 +890,7 @@ def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">; def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">; def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">; def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">; +def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; // -Wmsvc-include = -Wmicrosoft-include @@ -883,6 +956,7 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; def BackendOptimizationFailure : DiagGroup<"pass-failed">; // Instrumentation based profiling warnings. +def ProfileInstrMissing : DiagGroup<"profile-instr-missing">; def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index fcd04a0be1..a62d6af744 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -18,6 +18,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringRef.h" +#include <vector> namespace clang { class DiagnosticsEngine; @@ -25,19 +26,36 @@ namespace clang { // Import the diagnostic enums themselves. namespace diag { + // Size of each of the diagnostic categories. + enum { + DIAG_SIZE_COMMON = 300, + DIAG_SIZE_DRIVER = 200, + DIAG_SIZE_FRONTEND = 100, + DIAG_SIZE_SERIALIZATION = 120, + DIAG_SIZE_LEX = 400, + DIAG_SIZE_PARSE = 500, + DIAG_SIZE_AST = 150, + DIAG_SIZE_COMMENT = 100, + DIAG_SIZE_CROSSTU = 100, + DIAG_SIZE_SEMA = 3500, + DIAG_SIZE_ANALYSIS = 100, + DIAG_SIZE_REFACTORING = 1000, + }; // Start position for diagnostics. enum { - DIAG_START_COMMON = 0, - DIAG_START_DRIVER = DIAG_START_COMMON + 300, - DIAG_START_FRONTEND = DIAG_START_DRIVER + 200, - DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100, - DIAG_START_LEX = DIAG_START_SERIALIZATION + 120, - DIAG_START_PARSE = DIAG_START_LEX + 300, - DIAG_START_AST = DIAG_START_PARSE + 500, - DIAG_START_COMMENT = DIAG_START_AST + 110, - DIAG_START_SEMA = DIAG_START_COMMENT + 100, - DIAG_START_ANALYSIS = DIAG_START_SEMA + 3500, - DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 + DIAG_START_COMMON = 0, + DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON, + DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER, + DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND, + DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION, + DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX, + DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE, + DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST, + DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_CROSSTU, + DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_COMMENT, + DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA, + DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS, + DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING }; class CustomDiagInfo; @@ -84,6 +102,7 @@ class DiagnosticMapping { unsigned IsPragma : 1; unsigned HasNoWarningAsError : 1; unsigned HasNoErrorAsFatal : 1; + unsigned WasUpgradedFromWarning : 1; public: static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, @@ -94,6 +113,7 @@ public: Result.IsPragma = IsPragma; Result.HasNoWarningAsError = 0; Result.HasNoErrorAsFatal = 0; + Result.WasUpgradedFromWarning = 0; return Result; } @@ -103,11 +123,39 @@ public: bool isUser() const { return IsUser; } bool isPragma() const { return IsPragma; } + bool isErrorOrFatal() const { + return getSeverity() == diag::Severity::Error || + getSeverity() == diag::Severity::Fatal; + } + bool hasNoWarningAsError() const { return HasNoWarningAsError; } void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; } bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; } void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; } + + /// Whether this mapping attempted to map the diagnostic to a warning, but + /// was overruled because the diagnostic was already mapped to an error or + /// fatal error. + bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; } + void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; } + + /// Serialize this mapping as a raw integer. + unsigned serialize() const { + return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) | + (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity; + } + /// Deserialize a mapping. + static DiagnosticMapping deserialize(unsigned Bits) { + DiagnosticMapping Result; + Result.IsUser = (Bits >> 7) & 1; + Result.IsPragma = (Bits >> 6) & 1; + Result.HasNoWarningAsError = (Bits >> 5) & 1; + Result.HasNoErrorAsFatal = (Bits >> 4) & 1; + Result.WasUpgradedFromWarning = (Bits >> 3) & 1; + Result.Severity = Bits & 0x7; + return Result; + } }; /// \brief Used for handling and querying diagnostic IDs. @@ -233,6 +281,13 @@ public: /// are not SFINAE errors. static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID); + /// \brief Get the string of all diagnostic flags. + /// + /// \returns A list of all diagnostics flags as they would be written in a + /// command line invocation including their `no-` variants. For example: + /// `{"-Wempty-body", "-Wno-empty-body", ...}` + static std::vector<std::string> getDiagnosticFlags(); + /// \brief Get the set of all diagnostic IDs in the group with the given name. /// /// \param[out] Diags - On return, the diagnostics in the group. diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 7f7022b49e..8bc6d77c92 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -71,6 +71,8 @@ def ext_token_used : Extension<"extension used">, def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">, InGroup<CXX11Compat>, DefaultIgnore; +def warn_cxx2a_keyword : Warning<"'%0' is a keyword in C++2a">, + InGroup<CXX2aCompat>, DefaultIgnore; def ext_unterminated_char_or_string : ExtWarn< "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>; @@ -173,26 +175,24 @@ def warn_char_constant_too_large : Warning< def err_multichar_utf_character_literal : Error< "Unicode character literals may not contain multiple characters">; def err_exponent_has_no_digits : Error<"exponent has no digits">; -def ext_imaginary_constant : Extension< - "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def err_hex_constant_requires : Error< "hexadecimal floating %select{constant|literal}0 requires " "%select{an exponent|a significand}1">; def ext_hex_constant_invalid : Extension< "hexadecimal floating constants are a C99 feature">, InGroup<C99>; def ext_hex_literal_invalid : Extension< - "hexadecimal floating literals are a C++1z feature">, InGroup<CXX1z>; -def warn_cxx1z_hex_literal : Warning< + "hexadecimal floating literals are a C++17 feature">, InGroup<CXX17>; +def warn_cxx17_hex_literal : Warning< "hexadecimal floating literals are incompatible with " - "C++ standards before C++1z">, - InGroup<CXXPre1zCompatPedantic>, DefaultIgnore; + "C++ standards before C++17">, + InGroup<CXXPre17CompatPedantic>, DefaultIgnore; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>; def ext_binary_literal_cxx14 : Extension< "binary integer literals are a C++14 extension">, InGroup<CXX14BinaryLiteral>; def warn_cxx11_compat_binary_literal : Warning< "binary integer literals are incompatible with C++ standards before C++14">, - InGroup<CXXPre14CompatPedantic>, DefaultIgnore; + InGroup<CXXPre14CompatBinaryLiteral>, DefaultIgnore; def err_pascal_string_too_long : Error<"Pascal string is too long">; def err_escape_too_large : Error< "%select{hex|octal}0 escape sequence out of range">; @@ -208,8 +208,8 @@ 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; + "unicode literals are incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; def warn_cxx11_compat_user_defined_literal : Warning< "identifier after literal will be treated as a user-defined literal suffix " "in C++11">, InGroup<CXX11Compat>, DefaultIgnore; @@ -242,6 +242,7 @@ def warn_bad_character_encoding : ExtWarn< "illegal character encoding in character literal">, InGroup<InvalidSourceEncoding>; def err_lexing_string : Error<"failure when lexing a string">; +def err_placeholder_in_source : Error<"editor placeholder in source file">; //===----------------------------------------------------------------------===// @@ -345,6 +346,23 @@ def ext_pp_extra_tokens_at_eol : ExtWarn< def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; def ext_pp_bad_vaargs_use : Extension< "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; + +def ext_pp_bad_vaopt_use + : ExtWarn< + "__VA_OPT__ can only appear in the expansion of a variadic macro">, + InGroup<VariadicMacros>; + +def err_pp_missing_lparen_in_vaopt_use : Error< + "missing '(' following __VA_OPT__">; +def err_pp_vaopt_nested_use : Error< + "__VA_OPT__ cannot be nested within its own replacement tokens">; + +def err_vaopt_paste_at_start : Error< + "'##' cannot appear at start of __VA_OPT__ argument">; + +def err_vaopt_paste_at_end + : Error<"'##' cannot appear at end of __VA_OPT__ argument">; + def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">, InGroup<MacroRedefined>; def ext_variadic_macro : Extension<"variadic macros are a C99 feature">, InGroup<VariadicMacros>; @@ -502,12 +520,34 @@ def warn_pragma_diagnostic_invalid_token : InGroup<UnknownPragmas>; def warn_pragma_diagnostic_unknown_warning : ExtWarn<"unknown warning group '%0', ignored">, - InGroup<UnknownPragmas>; + InGroup<UnknownWarningOption>; // - #pragma __debug def warn_pragma_debug_unexpected_command : Warning< "unexpected debug command '%0'">, InGroup<IgnoredPragmas>; def warn_pragma_debug_missing_argument : Warning< "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>; +// #pragma module +def err_pp_expected_module_name : Error< + "expected %select{identifier after '.' in |}0module name">; +def err_pp_module_begin_wrong_module : Error< + "must specify '-fmodule-name=%0' to enter %select{|submodule of }1" + "this module%select{ (current module is %3)|}2">; +def err_pp_module_begin_no_module_map : Error< + "no module map available for module %0">; +def err_pp_module_begin_no_submodule : Error< + "submodule %0.%1 not declared in module map">; +def err_pp_module_begin_without_module_end : Error< + "no matching '#pragma clang module end' for this " + "'#pragma clang module begin'">; +def err_pp_module_end_without_module_begin : Error< + "no matching '#pragma clang module begin' for this " + "'#pragma clang module end'">; +def note_pp_module_begin_here : Note< + "entering module '%0' due to this pragma">; +def err_pp_module_build_pth : Error< + "'#pragma clang module build' not supported in pretokenized header">; +def err_pp_module_build_missing_end : Error< + "no matching '#pragma clang module endbuild' for this '#pragma clang module build'">; def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; def err_paste_at_start : Error< @@ -594,8 +634,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; -def err_mmap_umbrella_dir_not_found : Error< - "umbrella directory '%0' not found">; def err_mmap_umbrella_clash : Error< "umbrella for module '%0' already covers this directory">; def err_mmap_module_id : Error< @@ -647,6 +685,19 @@ def warn_mmap_mismatched_top_level_private : Warning< InGroup<PrivateModule>; def note_mmap_rename_top_level_private_as_submodule : Note< "make '%0' a submodule of '%1' to ensure it can be found by name">; +def err_mmap_duplicate_header_attribute : Error< + "header attribute '%0' specified multiple times">; +def err_mmap_invalid_header_attribute_value : Error< + "expected integer literal as value for header attribute '%0'">; +def err_mmap_expected_header_attribute : Error< + "expected a header attribute name ('size' or 'mtime')">; +def err_mmap_conflicting_export_as : Error< + "conflicting re-export of module '%0' as '%1' or '%2'">; +def warn_mmap_redundant_export_as : Warning< + "module '%0' already re-exported as '%1'">, + InGroup<PrivateModule>; +def err_mmap_submodule_export_as : Error< + "only top-level modules can be re-exported as public">; def warn_auto_module_import : Warning< "treating #%select{include|import|include_next|__include_macros}0 as an " @@ -656,6 +707,9 @@ def note_implicit_top_level_module_import_here : Note< def warn_uncovered_module_header : Warning< "umbrella header for module '%0' does not include header '%1'">, InGroup<IncompleteUmbrella>; +def warn_mmap_umbrella_dir_not_found : Warning< + "umbrella directory '%0' not found">, + InGroup<IncompleteUmbrella>; def err_expected_id_building_module : Error< "expected a module name in '__building_module' expression">; def warn_use_of_private_header_outside_module : Warning< diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def index 0ab6724ed9..2467b24fd9 100644 --- a/include/clang/Basic/DiagnosticOptions.def +++ b/include/clang/Basic/DiagnosticOptions.def @@ -87,6 +87,8 @@ VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit) VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit) /// Limit number of times to perform spell checking. VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit) +/// Limit number of lines shown in a snippet. +VALUE_DIAGOPT(SnippetLineLimit, 32, DefaultSnippetLineLimit) VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops. /// Column limit for formatting message diagnostics, or 0 if unused. diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h index c9b0c5def9..c195003de5 100644 --- a/include/clang/Basic/DiagnosticOptions.h +++ b/include/clang/Basic/DiagnosticOptions.h @@ -63,11 +63,15 @@ public: enum TextDiagnosticFormat { Clang, MSVC, Vi }; // Default values. - enum { DefaultTabStop = 8, MaxTabStop = 100, + enum { + DefaultTabStop = 8, + MaxTabStop = 100, DefaultMacroBacktraceLimit = 6, DefaultTemplateBacktraceLimit = 10, DefaultConstexprBacktraceLimit = 10, - DefaultSpellCheckingLimit = 50 }; + DefaultSpellCheckingLimit = 50, + DefaultSnippetLineLimit = 1, + }; // 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 b486e62c35..a8d6955da3 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -211,11 +211,11 @@ 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 ext_nested_namespace_definition : ExtWarn< - "nested namespace definition is a C++1z extension; " - "define each namespace separately">, InGroup<CXX1z>; + "nested namespace definition is a C++17 extension; " + "define each namespace separately">, InGroup<CXX17>; def warn_cxx14_compat_nested_namespace_definition : Warning< - "nested namespace definition is incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + "nested namespace definition is incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; def err_inline_nested_namespace_definition : Error< "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< @@ -358,14 +358,12 @@ def err_expected_coloncolon_after_super : Error< "expected '::' after '__super'">; def ext_decomp_decl_empty : ExtWarn< - "ISO C++1z does not allow a decomposition group to be empty">, + "ISO C++17 does not allow a decomposition group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< "method type specifier must start with '-' or '+'">; -def err_objc_no_attributes_on_category : Error< - "attributes may not be specified on a category">; def err_objc_missing_end : Error<"missing '@end'">; def note_objc_container_start : Note< "%select{class|protocol|category|class extension|implementation" @@ -438,6 +436,13 @@ def err_declaration_does_not_declare_param : Error< "declaration does not declare a parameter">; def err_no_matching_param : Error<"parameter named %0 is missing">; +/// Objective-C++ parser diagnostics +def err_expected_token_instead_of_objcxx_keyword : Error< + "expected %0; %1 is a keyword in Objective-C++">; +def err_expected_member_name_or_semi_objcxx_keyword : Error< + "expected member name or ';' after declaration specifiers; " + "%0 is a keyword in Objective-C++">; + /// C++ parser diagnostics def err_invalid_operator_on_type : Error< "cannot use %select{dot|arrow}0 operator on a type">; @@ -517,16 +522,16 @@ def err_function_is_not_record : Error< def err_super_in_using_declaration : Error< "'__super' cannot be used with a using declaration">; def ext_constexpr_if : ExtWarn< - "constexpr if is a C++1z extension">, InGroup<CXX1z>; + "constexpr if is a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_constexpr_if : Warning< - "constexpr if is incompatible with C++ standards before C++1z">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + "constexpr if is incompatible with C++ standards before C++17">, + DefaultIgnore, InGroup<CXXPre17Compat>; def ext_init_statement : ExtWarn< - "'%select{if|switch}0' initialization statements are a C++1z extension">, - InGroup<CXX1z>; + "'%select{if|switch}0' initialization statements are a C++17 extension">, + InGroup<CXX17>; def warn_cxx14_compat_init_statement : Warning< "%select{if|switch}0 initialization statements are incompatible with " - "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>; + "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; @@ -553,10 +558,13 @@ def warn_cxx98_compat_noexcept_expr : Warning< def warn_cxx98_compat_nullptr : Warning< "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def warn_cxx14_compat_attribute : Warning< +def ext_ns_enum_attribute : Extension< + "attributes on %select{a namespace|an enumerator}0 declaration are " + "a C++17 extension">, InGroup<CXX17>; +def warn_cxx14_compat_ns_enum_attribute : Warning< "attributes on %select{a namespace|an enumerator}0 declaration are " - "incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + "incompatible with C++ standards before C++17">, + InGroup<CXXPre17CompatPedantic>, DefaultIgnore; def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def warn_cxx98_compat_attribute : Warning< @@ -572,10 +580,10 @@ def err_cxx11_attribute_repeated : Error< "attribute %0 cannot appear multiple times in an attribute specifier">; def warn_cxx14_compat_using_attribute_ns : Warning< "default scope specifier for attributes is incompatible with C++ standards " - "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; def ext_using_attribute_ns : ExtWarn< - "default scope specifier for attributes is a C++1z extension">, - InGroup<CXX1z>; + "default scope specifier for attributes is a C++17 extension">, + InGroup<CXX17>; def err_using_attribute_ns_conflict : Error< "attribute with scope specifier cannot follow default scope specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; @@ -612,12 +620,12 @@ def err_expected_comma_greater : Error< def err_class_on_template_template_param : Error< "template template parameter requires 'class' after the parameter list">; def ext_template_template_param_typename : ExtWarn< - "template template parameter using 'typename' is a C++1z extension">, - InGroup<CXX1z>; + "template template parameter using 'typename' is a C++17 extension">, + InGroup<CXX17>; 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; + "incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function template|" @@ -690,11 +698,11 @@ def err_default_template_template_parameter_not_template : Error< "template">; def ext_fold_expression : ExtWarn< - "pack fold expression is a C++1z extension">, - InGroup<CXX1z>; + "pack fold expression is a C++17 extension">, + InGroup<CXX17>; def warn_cxx14_compat_fold_expression : Warning< - "pack fold expression is incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + "pack fold expression is incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; def err_expected_fold_operator : Error< "expected a foldable binary operator in fold expression">; def err_fold_operator_mismatch : Error< @@ -725,8 +733,12 @@ def ext_nonstatic_member_init : ExtWarn< def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def err_bitfield_member_init: Error< - "bit-field member cannot have an in-class initializer">; +def ext_bitfield_member_init: ExtWarn< + "default member initializer for bit-field is a C++2a extension">, + InGroup<CXX2a>; +def warn_cxx17_compat_bitfield_member_init: Warning< + "default member initializer for bit-field is incompatible with " + "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; @@ -743,19 +755,19 @@ def err_alias_declaration_specialization : Error< def err_alias_declaration_pack_expansion : Error< "alias declaration cannot be a pack expansion">; -// C++1z using-declaration pack expansions +// C++17 using-declaration pack expansions def ext_multi_using_declaration : ExtWarn< "use of multiple declarators in a single using declaration is " - "a C++1z extension">, InGroup<CXX1z>; -def warn_cxx1z_compat_multi_using_declaration : Warning< + "a C++17 extension">, InGroup<CXX17>; +def warn_cxx17_compat_multi_using_declaration : Warning< "use of multiple declarators in a single using declaration is " - "incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + "incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; def ext_using_declaration_pack : ExtWarn< - "pack expansion of using declaration is a C++1z extension">, InGroup<CXX1z>; -def warn_cxx1z_compat_using_declaration_pack : Warning< + "pack expansion of using declaration is a C++17 extension">, InGroup<CXX17>; +def warn_cxx17_compat_using_declaration_pack : Warning< "pack expansion using declaration is incompatible with C++ standards " - "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; // C++11 override control def ext_override_control_keyword : ExtWarn< @@ -806,16 +818,16 @@ def err_lambda_missing_parens : Error< "attribute specifier|'constexpr'}0">; def err_lambda_decl_specifier_repeated : Error< "%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">; -// C++1z lambda expressions +// C++17 lambda expressions def err_expected_star_this_capture : Error< "expected 'this' following '*' in lambda capture list">; -// C++1z constexpr lambda expressions +// C++17 constexpr lambda expressions def warn_cxx14_compat_constexpr_on_lambda : Warning< - "constexpr on lambda expressions is incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; -def ext_constexpr_on_lambda_cxx1z : ExtWarn< - "'constexpr' on lambda expressions is a C++1z extension">, InGroup<CXX1z>; + "constexpr on lambda expressions is incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; +def ext_constexpr_on_lambda_cxx17 : ExtWarn< + "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>; // Availability attribute def err_expected_version : Error< @@ -882,9 +894,16 @@ def warn_pragma_expected_rparen : Warning< "missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>; + +// '#pragma clang section' related errors +def err_pragma_expected_clang_section_name : Error< + "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">; +def err_pragma_clang_section_expected_equal : Error< + "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>; + def warn_pragma_expected_section_push_pop_or_name : Warning< "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>; @@ -974,6 +993,43 @@ def err_pragma_optimize_invalid_argument : Error< "expected 'on' or 'off'">; def err_pragma_optimize_extra_argument : Error< "unexpected extra argument '%0' to '#pragma clang optimize'">; +// - #pragma clang attribute +def err_pragma_attribute_expected_push_pop : Error< + "expected 'push' or 'pop' after '#pragma clang attribute'">; +def err_pragma_attribute_invalid_argument : Error< + "unexpected argument '%0' to '#pragma clang attribute'; " + "expected 'push' or 'pop'">; +def err_pragma_attribute_expected_attribute : Error< + "expected an attribute after '('">; +def err_pragma_attribute_expected_attribute_name : Error< + "expected identifier that represents an attribute name">; +def err_pragma_attribute_extra_tokens_after_attribute : Error< + "extra tokens after attribute in a '#pragma clang attribute push'">; +def err_pragma_attribute_unsupported_attribute : Error< + "attribute %0 is not supported by '#pragma clang attribute'">; +def err_pragma_attribute_multiple_attributes : Error< + "more than one attribute specified in '#pragma clang attribute push'">; +def err_pragma_attribute_expected_attribute_syntax : Error< + "expected an attribute that is specified using the GNU, C++11 or '__declspec'" + " syntax">; +def note_pragma_attribute_use_attribute_kw : Note<"use the GNU '__attribute__' " + "syntax">; +def err_pragma_attribute_invalid_subject_set_specifier : Error< + "expected attribute subject set specifier 'apply_to'">; +def err_pragma_attribute_expected_subject_identifier : Error< + "expected an identifier that corresponds to an attribute subject rule">; +def err_pragma_attribute_unknown_subject_rule : Error< + "unknown attribute subject rule '%0'">; +def err_pragma_attribute_expected_subject_sub_identifier : Error< + "expected an identifier that corresponds to an attribute subject matcher " + "sub-rule; '%0' matcher %select{does not support sub-rules|supports the " + "following sub-rules: %2|}1">; +def err_pragma_attribute_unknown_subject_sub_rule : Error< + "%select{invalid use of|unknown}2 attribute subject matcher sub-rule '%0'; " + "'%1' matcher %select{does not support sub-rules|supports the following " + "sub-rules: %3}2">; +def err_pragma_attribute_duplicate_subject : Error< + "duplicate attribute subject matcher '%0'">; def err_opencl_unroll_hint_on_non_loop : Error< "OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">; @@ -1042,6 +1098,16 @@ def err_pragma_loop_missing_argument : Error< def err_pragma_loop_invalid_option : Error< "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, " "vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute">; + +def err_pragma_fp_invalid_option : Error< + "%select{invalid|missing}0 option%select{ %1|}0; expected contract">; +def err_pragma_fp_invalid_argument : Error< + "unexpected argument '%0' to '#pragma clang fp %1'; " + "expected 'on', 'fast' or 'off'">; +def err_pragma_fp_scope : Error< + "'#pragma clang fp' can only appear at file scope or at the start of a " + "compound statement">; + def err_pragma_invalid_keyword : Error< "invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">; @@ -1062,14 +1128,12 @@ def err_pragma_cannot_end_force_cuda_host_device : Error< } // end of Parse Issue category. let CategoryName = "Modules Issue" in { -def err_expected_module_interface_decl : Error< - "expected module declaration at start of module interface">; def err_unexpected_module_decl : Error< - "module declaration must be the first declaration in the translation unit">; + "module declaration can only appear at the top level">; def err_module_expected_ident : Error< - "expected a module name after module%select{| import}0">; -def err_unexpected_module_kind : Error< - "unexpected module kind %0; expected 'implementation' or 'partition'">; + "expected a module name after '%select{module|import}0'">; +def err_module_implementation_partition : Error< + "module partition must be declared 'export'">; def err_attribute_not_module_attr : Error< "%0 attribute cannot be applied to a module">; def err_attribute_not_import_attr : Error< diff --git a/include/clang/Basic/DiagnosticRefactoringKinds.td b/include/clang/Basic/DiagnosticRefactoringKinds.td new file mode 100644 index 0000000000..ee396b9307 --- /dev/null +++ b/include/clang/Basic/DiagnosticRefactoringKinds.td @@ -0,0 +1,34 @@ +//==--- DiagnosticRefactoringKinds.td - refactoring diagnostics -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Refactoring Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Refactoring" in { + +let CategoryName = "Refactoring Invocation Issue" in { + +def err_refactor_no_selection : Error<"refactoring action can't be initiated " + "without a selection">; +def err_refactor_selection_no_symbol : Error<"there is no symbol at the given " + "location">; +def err_refactor_selection_invalid_ast : Error<"the provided selection does " + "not overlap with the AST nodes of interest">; + +def err_refactor_code_outside_of_function : Error<"the selected code is not a " + "part of a function's / method's body">; +def err_refactor_extract_simple_expression : Error<"the selected expression " + "is too simple to extract">; +def err_refactor_extract_prohibited_expression : Error<"the selected " + "expression can't be extracted">; + +} + +} // end of Refactoring diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9764c9ee34..b8538f92cb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -194,6 +194,8 @@ def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, InGroup<DuplicateDeclSpecifier>; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_imaginary_constant : Extension< + "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>; @@ -211,9 +213,9 @@ def warn_auto_storage_class : Warning< def warn_deprecated_register : Warning< "'register' storage class specifier is deprecated " - "and incompatible with C++1z">, InGroup<DeprecatedRegister>; + "and incompatible with C++17">, InGroup<DeprecatedRegister>; def ext_register_storage_class : ExtWarn< - "ISO C++1z does not allow 'register' storage class specifier">, + "ISO C++17 does not allow 'register' storage class specifier">, DefaultError, InGroup<Register>; def err_invalid_decl_spec_combination : Error< @@ -293,8 +295,20 @@ def warn_empty_parens_are_function_decl : Warning< def warn_parens_disambiguated_as_function_declaration : Warning< "parentheses were disambiguated as a function declaration">, InGroup<VexingParse>; +def warn_parens_disambiguated_as_variable_declaration : Warning< + "parentheses were disambiguated as redundant parentheses around declaration " + "of variable named %0">, InGroup<VexingParse>; +def warn_redundant_parens_around_declarator : Warning< + "redundant parentheses surrounding declarator">, + InGroup<DiagGroup<"redundant-parens">>, DefaultIgnore; def note_additional_parens_for_variable_declaration : Note< "add a pair of parentheses to declare a variable">; +def note_raii_guard_add_name : Note< + "add a variable name to declare a %0 initialized with %1">; +def note_function_style_cast_add_parentheses : Note< + "add enclosing parentheses to perform a function-style cast">; +def note_remove_parens_for_variable_declaration : Note< + "remove parentheses to silence this warning">; def note_empty_parens_function_call : Note< "change this ',' to a ';' to call %0">; def note_empty_parens_default_ctor : Note< @@ -303,6 +317,8 @@ def note_empty_parens_zero_initialize : Note< "replace parentheses with an initializer to declare a variable">; def warn_unused_function : Warning<"unused function %0">, InGroup<UnusedFunction>, DefaultIgnore; +def warn_unused_template : Warning<"unused %select{function|variable}0 template %1">, + InGroup<UnusedTemplate>, DefaultIgnore; def warn_unused_member_function : Warning<"unused member function %0">, InGroup<UnusedMemberFunction>, DefaultIgnore; def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, @@ -339,7 +355,7 @@ def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup<ImplicitFunctionDeclare>, DefaultIgnore; def ext_implicit_function_decl : ExtWarn< - "implicit declaration of function %0 is invalid in C99">, + "implicit declaration of function %0 is invalid in %select{C99|OpenCL}1">, InGroup<ImplicitFunctionDeclare>; def note_function_suggestion : Note<"did you mean %0?">; @@ -350,8 +366,10 @@ def err_language_linkage_spec_unknown : Error<"unknown linkage language">; def err_language_linkage_spec_not_ascii : Error< "string literal in language linkage specifier cannot have an " "encoding-prefix">; -def warn_use_out_of_scope_declaration : Warning< - "use of out-of-scope declaration of %0">; +def ext_use_out_of_scope_declaration : ExtWarn< + "use of out-of-scope declaration of %0%select{| whose type is not " + "compatible with that of an implicit declaration}1">, + InGroup<DiagGroup<"out-of-scope-function">>; def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< @@ -369,7 +387,9 @@ def warn_decl_shadow : "local variable|" "variable in %2|" "static data member of %2|" - "field of %2}1">, + "field of %2|" + "typedef in %2|" + "type alias in %2}1">, InGroup<Shadow>, DefaultIgnore; def warn_decl_shadow_uncaptured_local : Warning<warn_decl_shadow.Text>, @@ -387,9 +407,9 @@ def err_decomp_decl_context : Error< "decomposition declaration not permitted in this context">; def warn_cxx14_compat_decomp_decl : Warning< "decomposition declarations are incompatible with " - "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>; + "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>; def ext_decomp_decl : ExtWarn< - "decomposition declarations are a C++1z extension">, InGroup<CXX1z>; + "decomposition declarations are a C++17 extension">, InGroup<CXX17>; def err_decomp_decl_spec : Error< "decomposition declaration cannot be declared " "%plural{1:'%1'|:with '%1' specifiers}0">; @@ -490,7 +510,7 @@ def err_access_decl : Error< "ISO C++11 does not allow access declarations; " "use using declarations instead">; def ext_dynamic_exception_spec : ExtWarn< - "ISO C++1z does not allow dynamic exception specifications">, + "ISO C++17 does not allow dynamic exception specifications">, InGroup<DynamicExceptionSpec>, DefaultError; def warn_exception_spec_deprecated : Warning< "dynamic exception specifications are deprecated">, @@ -501,9 +521,9 @@ def warn_deprecated_copy_operation : Warning< "for %0 is deprecated because it has a user-declared " "%select{copy %select{assignment operator|constructor}1|destructor}2">, InGroup<Deprecated>, DefaultIgnore; -def warn_cxx1z_compat_exception_spec_in_signature : Warning< +def warn_cxx17_compat_exception_spec_in_signature : Warning< "mangled name of %0 will change in C++17 due to non-throwing exception " - "specification in function signature">, InGroup<CXX1zCompat>; + "specification in function signature">, InGroup<CXX17CompatMangling>; def warn_global_constructor : Warning< "declaration requires a global constructor">, @@ -533,10 +553,10 @@ def err_maybe_falloff_nonvoid_block : Error< def err_falloff_nonvoid_block : Error< "control reaches end of non-void block">; def warn_maybe_falloff_nonvoid_coroutine : Warning< - "control may reach end of non-void coroutine">, + "control may reach end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">, InGroup<ReturnType>; def warn_falloff_nonvoid_coroutine : Warning< - "control reaches end of non-void coroutine">, + "control reaches end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">, InGroup<ReturnType>; def warn_suggest_noreturn_function : Warning< "%select{function|method}0 %1 could be declared with attribute 'noreturn'">, @@ -577,6 +597,7 @@ def warn_redecl_library_builtin : Warning< def err_builtin_definition : Error<"definition of builtin function %0">; def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; +def err_invalid_cpu_is : Error<"invalid cpu name for builtin">; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; def err_function_needs_feature : Error<"always_inline function %1 requires target feature '%2', but would " @@ -708,6 +729,19 @@ def err_pragma_options_align_mac68k_target_unsupported : Error< def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, InGroup<IgnoredPragmas>; +def warn_pragma_pack_non_default_at_include : Warning< + "non-default #pragma pack value changes the alignment of struct or union " + "members in the included file">, InGroup<PragmaPackSuspiciousInclude>, + DefaultIgnore; +def warn_pragma_pack_modified_after_include : Warning< + "the current #pragma pack aligment value is modified in the included " + "file">, InGroup<PragmaPack>; +def warn_pragma_pack_no_pop_eof : Warning<"unterminated " + "'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>; +def note_pragma_pack_here : Note< + "previous '#pragma pack' directive that modifies alignment is here">; +def note_pragma_pack_pop_instead_reset : Note< + "did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?">; // Follow the Microsoft implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; def warn_pragma_pack_pop_identifer_and_alignment : Warning< @@ -728,6 +762,9 @@ def err_super_in_lambda_unsupported : Error< def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, InGroup<IgnoredPragmas>; +def warn_atl_uuid_deprecated : Warning< + "specifying 'uuid' as an ATL attribute is deprecated; use __declspec instead">, + InGroup<DeprecatedDeclarations>; def warn_pragma_unused_expected_var_arg : Warning< "only variables can be arguments to '#pragma unused'">, InGroup<IgnoredPragmas>; @@ -748,6 +785,25 @@ def err_pragma_loop_compatibility : Error< def err_pragma_loop_precedes_nonloop : Error< "expected a for, while, or do-while loop to follow '%0'">; +def err_pragma_attribute_matcher_subrule_contradicts_rule : Error< + "redundant attribute subject matcher sub-rule '%0'; '%1' already matches " + "those declarations">; +def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error< + "negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">; +def err_pragma_attribute_invalid_matchers : Error< + "attribute %0 can't be applied to %1">; +def err_pragma_attribute_stack_mismatch : Error< + "'#pragma clang attribute pop' with no matching '#pragma clang attribute push'">; +def warn_pragma_attribute_unused : Warning< + "unused attribute %0 in '#pragma clang attribute push' region">, + InGroup<PragmaClangAttribute>; +def note_pragma_attribute_region_ends_here : Note< + "'#pragma clang attribute push' regions ends here">; +def err_pragma_attribute_no_pop_eof : Error<"unterminated " + "'#pragma clang attribute push' at end of file">; +def note_pragma_attribute_applied_decl_here : Note< + "when applied to this declaration">; + /// Objective-C parser diagnostics def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; @@ -782,8 +838,10 @@ def warn_property_types_are_incompatible : Warning< "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">, + "property %select{of type %1|with attribute '%1'|without attribute '%1'|with " + "getter %1|with setter %1}0 was selected for synthesis">, InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>; +def err_protocol_property_mismatch: Error<warn_protocol_property_mismatch.Text>; def err_undef_interface : Error<"cannot find interface declaration for %0">; def err_category_forward_interface : Error< "cannot define %select{category|class extension}0 for undefined class %1">; @@ -1003,6 +1061,8 @@ def warn_auto_synthesizing_protocol_property :Warning< "auto property synthesis will not synthesize property %0" " declared in protocol %1">, InGroup<DiagGroup<"objc-protocol-property-synthesis">>; +def note_add_synthesize_directive : Note< + "add a '@synthesize' directive">; def warn_no_autosynthesis_shared_ivar_property : Warning < "auto property synthesis will not synthesize property " "%0 because it cannot share an ivar with another synthesized property">, @@ -1060,7 +1120,9 @@ def err_category_property : Error< def note_property_declare : Note< "property declared here">; def note_protocol_property_declare : Note< - "it could also be property of type %0 declared here">; + "it could also be property " + "%select{of type %1|without attribute '%1'|with attribute '%1'|with getter " + "%1|with setter %1}0 declared here">; def note_property_synthesize : Note< "property synthesized here">; def err_synthesize_category_decl : Error< @@ -1159,21 +1221,31 @@ def err_objc_kindof_nonobject : Error< def err_objc_kindof_wrong_position : Error< "'__kindof' type specifier must precede the declarator">; +def err_objc_method_unsupported_param_ret_type : Error< + "%0 %select{parameter|return}1 type is unsupported; " + "support for vector types for this target is introduced in %2">; + +def warn_messaging_unqualified_id : Warning< + "messaging unqualified id">, DefaultIgnore, + InGroup<DiagGroup<"objc-messaging-id">>; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; +def err_static_assert_requirement_failed : Error< + "static_assert failed due to requirement '%0'%select{ %2|}1">; def ext_static_assert_no_message : ExtWarn< - "static_assert with no message is a C++1z extension">, InGroup<CXX1z>; + "static_assert with no message is a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_static_assert_no_message : Warning< - "static_assert with no message is incompatible with C++ standards before C++1z">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + "static_assert with no message is incompatible with C++ standards before C++17">, + DefaultIgnore, InGroup<CXXPre17Compat>; def ext_inline_variable : ExtWarn< - "inline variables are a C++1z extension">, InGroup<CXX1z>; + "inline variables are a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_inline_variable : Warning< - "inline variables are incompatible with C++ standards before C++1z">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + "inline variables are incompatible with C++ standards before C++17">, + DefaultIgnore, InGroup<CXXPre17Compat>; def warn_inline_namespace_reopened_noninline : Warning< "inline namespace reopened as a non-inline namespace">; @@ -1277,6 +1349,8 @@ def err_type_defined_in_alias_template : Error< "%0 cannot be defined in a type alias template">; def err_type_defined_in_condition : Error< "%0 cannot be defined in a condition">; +def err_type_defined_in_enum : Error< + "%0 cannot be defined in an enumeration">; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; @@ -1524,11 +1598,9 @@ def note_ivar_decl : Note<"instance variable is declared here">; def note_bitfield_decl : Note<"bit-field is declared here">; def note_implicit_param_decl : Note<"%0 is an implicit parameter">; def note_member_synthesized_at : Note< - "implicit %select{default constructor|copy constructor|move constructor|copy " - "assignment operator|move assignment operator|destructor}0 for %1 first " - "required here">; -def note_inhctor_synthesized_at : Note< - "inherited constructor for %0 first required here">; + "in implicit %select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}0 for %1 " + "first required here">; def err_missing_default_ctor : Error< "%select{constructor for %1 must explicitly initialize the|" "implicit default constructor for %1 must explicitly initialize the|" @@ -1603,6 +1675,11 @@ def err_conflicting_overriding_cc_attributes : Error< "virtual function %0 has different calling convention attributes " "%diff{($) than the function it overrides (which has calling convention $)|" "than the function it overrides}1,2">; +def warn_overriding_method_missing_noescape : Warning< + "parameter of overriding method should be annotated with " + "__attribute__((noescape))">, InGroup<MissingNoEscape>; +def note_overridden_marked_noescape : Note< + "parameter of overridden method is annotated with __attribute__((noescape))">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " @@ -1687,8 +1764,8 @@ def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " "base class|a constructor delegation|a vector element|a block element|a " - "complex element|a lambda capture|a compound literal initializer|a " - "related result|a parameter of CF audited function}0 " + "block element|a complex element|a lambda capture|a compound literal " + "initializer|a related result|a parameter of CF audited function}0 " "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|" "with an %select{rvalue|lvalue}2 of incompatible type}1,3" "%select{|: different classes%diff{ ($ vs $)|}5,6" @@ -1814,8 +1891,9 @@ def note_uninit_fixit_remove_cond : Note< "remove the %select{'%1' if its condition|condition if it}0 " "is always %select{false|true}2">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; -def err_list_init_in_parens : Error<"list-initializer for non-class type %0 " - "must not be parenthesized">; +def err_list_init_in_parens : Error< + "cannot initialize %select{non-class|reference}0 type %1 with a " + "parenthesized initializer list">; def warn_unsequenced_mod_mod : Warning< "multiple unsequenced modifications to %0">, InGroup<Unsequenced>; @@ -1887,7 +1965,7 @@ def err_auto_not_allowed : Error< "|in non-static struct member|in struct member" "|in non-static union member|in union member" "|in non-static class member|in interface member" - "|in exception declaration|in template parameter until C++1z|in block literal" + "|in exception declaration|in template parameter until C++17|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter" @@ -1929,6 +2007,9 @@ def err_auto_var_deduction_failure_from_init_list : Error< "cannot deduce actual type for variable %0 with type %1 from initializer list">; def err_auto_new_deduction_failure : Error< "new expression for type %0 has incompatible constructor argument of type %1">; +def err_auto_inconsistent_deduction : Error< + "deduced conflicting types %diff{($ vs $) |}0,1" + "for initializer list element type">; def err_auto_different_deductions : Error< "%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 " "deduced as %1 in declaration of %2 and " @@ -1964,7 +2045,7 @@ def err_decltype_auto_compound_type : Error< def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; -// C++1z deduced class template specialization types +// C++17 deduced class template specialization types def err_deduced_class_template_compound_type : Error< "cannot %select{form pointer to|form reference to|form array of|" "form function returning|use parentheses when declaring variable with}0 " @@ -2062,7 +2143,7 @@ def err_enum_invalid_underlying : Error< "non-integral type %0 is an invalid underlying type">; def err_enumerator_too_large : Error< "enumerator value is not representable in the underlying type %0">; -def ext_enumerator_too_large : ExtWarn< +def ext_enumerator_too_large : Extension< "enumerator value is not representable in the underlying type %0">, InGroup<MicrosoftEnumValue>; def err_enumerator_wrapped : Error< @@ -2112,11 +2193,11 @@ def err_for_range_iter_deduction_failure : Error< def err_for_range_member_begin_end_mismatch : Error< "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">; def ext_for_range_begin_end_types_differ : ExtWarn< - "'begin' and 'end' returning different types (%0 and %1) is a C++1z extension">, - InGroup<CXX1z>; + "'begin' and 'end' returning different types (%0 and %1) is a C++17 extension">, + InGroup<CXX17>; def warn_for_range_begin_end_types_differ : Warning< "'begin' and 'end' returning different types (%0 and %1) is incompatible " - "with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "with C++ standards before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; def note_in_for_range: Note< "when looking up '%select{begin|end}0' function for range expression " "of type %1">; @@ -2352,8 +2433,9 @@ def err_attribute_requires_positive_integer : Error< def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; def warn_unsupported_target_attribute - : Warning<"Ignoring unsupported '%0' in the target attribute string">, - InGroup<IgnoredAttributes>; + : Warning<"ignoring %select{unsupported|duplicate}0" + "%select{| architecture}1 '%2' in the target attribute string">, + InGroup<IgnoredAttributes>; def err_attribute_unsupported : Error<"%0 attribute is not supported for this target">; // The err_*_attribute_argument_not_int are separate because they're used by @@ -2434,6 +2516,9 @@ def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; def err_attribute_size_too_large : Error<"vector size too large">; +def err_typecheck_vector_not_convertable_implict_truncation : Error< + "cannot convert between %select{scalar|vector}0 type %1 and vector type" + " %2 as implicit conversion would cause truncation">; def err_typecheck_vector_not_convertable : Error< "cannot convert between vector values of different size (%0 and %1)">; def err_typecheck_vector_not_convertable_non_scalar : Error< @@ -2456,7 +2541,7 @@ def err_attribute_address_multiple_qualifiers : Error< def err_attribute_address_function_type : Error< "function type may not be qualified with an address space">; def err_as_qualified_auto_decl : Error< - "automatic variable qualified with an address space">; + "automatic variable qualified with an%select{| invalid}0 address space">; def err_arg_with_address_space : Error< "parameter may not be qualified with an address space">; def err_field_with_address_space : Error< @@ -2549,6 +2634,8 @@ def err_attribute_section_invalid_for_target : Error< "argument to 'section' attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup<Section>; +def warn_attribute_section_on_redeclaration : Warning< + "section attribute is specified on redeclared variable">, InGroup<Section>; def err_anonymous_property: Error< "anonymous property is not supported">; @@ -2735,6 +2822,7 @@ def warn_attribute_wrong_decl_type : Warning< "|types and namespaces" "|Objective-C interfaces" "|methods and properties" + "|functions, methods, and properties" "|struct or union" "|struct, union or class" "|types" @@ -2794,9 +2882,9 @@ def warn_cconv_structors : Warning< def err_regparm_mismatch : Error<"function declared with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; -def err_returns_retained_mismatch : Error< - "function declared with the ns_returns_retained attribute " - "was previously declared without the ns_returns_retained attribute">; +def err_function_attribute_mismatch : Error< + "function declared with %0 attribute " + "was previously declared without the %0 attribute">; def err_objc_precise_lifetime_bad_type : Error< "objc_precise_lifetime only applies to retainable types; type here is %0">; def warn_objc_precise_lifetime_meaningless : Error< @@ -2837,17 +2925,18 @@ def note_protocol_method : Note< def warn_unguarded_availability : Warning<"%0 is only available on %1 %2 or newer">, InGroup<UnguardedAvailability>, DefaultIgnore; -def warn_partial_availability : Warning<"%0 is only available conditionally">, - InGroup<UnguardedAvailability>, DefaultIgnore; -def note_partial_availability_silence : Note< - "explicitly redeclare %0 to silence this warning">; +def warn_unguarded_availability_new : + Warning<warn_unguarded_availability.Text>, + InGroup<UnguardedAvailabilityNew>; +def note_decl_unguarded_availability_silence : Note< + "annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">; def note_unguarded_available_silence : Note< - "enclose %0 in an @available check to silence this warning">; -def warn_partial_message : Warning<"%0 is partial: %1">, - InGroup<UnguardedAvailability>, DefaultIgnore; -def warn_partial_fwdclass_message : Warning< - "%0 may be partial because the receiver type is unknown">, - InGroup<UnguardedAvailability>, DefaultIgnore; + "enclose %0 in %select{an @available|a __builtin_available}1 check to silence" + " this warning">; +def warn_at_available_unchecked_use : Warning< + "%select{@available|__builtin_available}0 does not guard availability here; " + "use if (%select{@available|__builtin_available}0) instead">, + InGroup<DiagGroup<"unsupported-availability-guard">>; // Thread Safety Attributes def warn_invalid_capability_name : Warning< @@ -3009,6 +3098,8 @@ def warn_impcast_vector_scalar : Warning< def warn_impcast_complex_scalar : Warning< "implicit conversion discards imaginary component: %0 to %1">, InGroup<Conversion>, DefaultIgnore; +def err_impcast_complex_scalar : Error< + "implicit conversion from %0 to %1 is not permitted in C++">; def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup<Conversion>, DefaultIgnore; @@ -3134,6 +3225,9 @@ def warn_int_to_void_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup<IntToVoidPointerCast>; +def warn_attribute_ignored_for_field_of_type : Warning< + "%0 attribute ignored for field of type %1">, + InGroup<IgnoredAttributes>; def warn_no_underlying_type_specified_for_enum_bitfield : Warning< "enums in the Microsoft ABI are signed integers by default; consider giving " "the enum %0 an unsigned underlying type to make this code portable">, @@ -3228,7 +3322,8 @@ def err_attribute_regparm_invalid_number : Error< "'regparm' parameter must be between 0 and %0 inclusive">; def err_attribute_not_supported_in_lang : Error< "%0 attribute is not supported in %select{C|C++|Objective-C}1">; - +def err_attribute_not_supported_on_arch + : Error<"%0 attribute is not supported on '%1'">; // Clang-Specific Attributes def warn_attribute_iboutlet : Warning< @@ -3245,13 +3340,15 @@ def warn_iboutletcollection_property_assign : Warning< "IBOutletCollection properties should be copy/strong and not assign">, InGroup<ObjCInvalidIBOutletProperty>; -def err_attribute_overloadable_missing : Error< - "%select{overloaded function|redeclaration of}0 %1 must have the " - "'overloadable' attribute">; +def err_attribute_overloadable_mismatch : Error< + "redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">; def note_attribute_overloadable_prev_overload : Note< - "previous overload of function is here">; + "previous %select{unmarked |}0overload of function is here">; def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; +def err_attribute_overloadable_multiple_unmarked_overloads : Error< + "at most one overload for a given name may lack the 'overloadable' " + "attribute">; def warn_ns_attribute_wrong_return_type : Warning< "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, @@ -3465,6 +3562,8 @@ def note_ovl_candidate_substitution_failure : Note< "candidate template ignored: substitution failure%0%1">; def note_ovl_candidate_disabled_by_enable_if : Note< "candidate template ignored: disabled by %0%1">; +def note_ovl_candidate_disabled_by_requirement : Note< + "candidate template ignored: requirement '%0' was not satisfied%1">; def note_ovl_candidate_has_pass_object_size_params: Note< "candidate address cannot be taken because parameter %0 has " "pass_object_size attribute">; @@ -3846,8 +3945,8 @@ def err_template_nontype_parm_bad_type : Error< "a non-type template parameter cannot have type %0">; def warn_cxx14_compat_template_nontype_parm_auto_type : Warning< "non-type template parameters declared with %0 are incompatible with C++ " - "standards before C++1z">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + "standards before C++17">, + DefaultIgnore, InGroup<CXXPre17Compat>; def err_template_param_default_arg_redefinition : Error< "template parameter redefines default argument">; def note_template_param_prev_default_arg : Note< @@ -4021,6 +4120,13 @@ def err_pointer_to_member_call_drops_quals : Error< def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; +def ext_pointer_to_const_ref_member_on_rvalue : Extension< + "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">, + InGroup<CXX2a>, SFINAEFailure; +def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning< + "invoking a pointer to a 'const &' member function on an rvalue is " + "incompatible with C++ standards before C++2a">, + InGroup<CXXPre2aCompatPedantic>, DefaultIgnore; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup<MicrosoftTemplate>; @@ -4378,6 +4484,9 @@ def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_enable_if : Error< "no type named 'type' in %0; 'enable_if' cannot be used to disable " "this declaration">; +def err_typename_nested_not_found_requirement : Error< + "failed requirement '%0'; 'enable_if' cannot be used to disable this " + "declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; def note_typename_refers_here : Note< @@ -4517,8 +4626,11 @@ def warn_deprecated_fwdclass_message : Warning< "%0 may be deprecated because the receiver type is unknown">, InGroup<DeprecatedDeclarations>; def warn_deprecated_def : Warning< - "Implementing deprecated %select{method|class|category}0">, - InGroup<DeprecatedImplementations>, DefaultIgnore; + "implementing deprecated %select{method|class|category}0">, + InGroup<DeprecatedImplementations>, DefaultIgnore; +def warn_unavailable_def : Warning< + "implementing unavailable method">, + InGroup<DeprecatedImplementations>, DefaultIgnore; def err_unavailable : Error<"%0 is unavailable">; def err_property_method_unavailable : Error<"property access is using %0 method which is unavailable">; @@ -4545,7 +4657,7 @@ def warn_missing_prototype : Warning< def note_declaration_not_a_prototype : Note< "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; def warn_strict_prototypes : Warning< - "this %select{function declaration is not|" + "this %select{function declaration is not|block declaration is not|" "old-style function definition is not preceded by}0 a prototype">, InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore; def warn_missing_variable_declarations : Warning< @@ -4576,6 +4688,8 @@ def err_abi_tag_on_redeclaration : Error< "cannot add 'abi_tag' attribute in a redeclaration">; def err_new_abi_tag_on_redeclaration : Error< "'abi_tag' %0 missing in original declaration">; +def note_use_ifdef_guards : Note< + "unguarded header; consider using #ifdef guards or #pragma once">; def note_deleted_dtor_no_operator_delete : Note< "virtual destructor requires an unambiguous, accessible 'operator delete'">; @@ -4614,6 +4728,14 @@ def note_deleted_assign_field : Note< def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, InGroup<DiagGroup<"undefined-internal">>; +def err_undefined_internal_type : Error< + "%select{function|variable}0 %q1 is used but not defined in this " + "translation unit, and cannot be defined in any other translation unit " + "because its type does not have linkage">; +def ext_undefined_internal_type : Extension< + "ISO C++ requires a definition in this translation unit for " + "%select{function|variable}0 %q1 because its type does not have linkage">, + InGroup<DiagGroup<"undefined-internal-type">>; def warn_undefined_inline : Warning<"inline function %q0 is not defined">, InGroup<DiagGroup<"undefined-inline">>; def err_undefined_inline_var : Error<"inline variable %q0 is not defined">; @@ -4679,6 +4801,9 @@ def err_thread_non_thread : Error< def err_thread_thread_different_kind : Error< "thread-local declaration of %0 with %select{static|dynamic}1 initialization " "follows declaration with %select{dynamic|static}1 initialization">; +def err_mismatched_owning_module : Error< + "declaration of %0 in %select{the global module|module %2}1 follows " + "declaration in %select{the global module|module %4}3">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< @@ -4732,7 +4857,7 @@ def ext_forward_ref_enum : Extension< "ISO C forbids forward references to 'enum' types">; def err_forward_ref_enum : Error< "ISO C++ forbids forward references to 'enum' types">; -def ext_ms_forward_ref_enum : Extension< +def ext_ms_forward_ref_enum : ExtWarn< "forward references to 'enum' types are a Microsoft extension">, InGroup<MicrosoftEnumForwardReference>; def ext_forward_ref_enum_def : Extension< @@ -4908,6 +5033,21 @@ def warn_bitfield_width_exceeds_type_width: Warning< def warn_anon_bitfield_width_exceeds_type_width : Warning< "width of anonymous bit-field (%0 bits) exceeds width of its type; value " "will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>; +def warn_bitfield_too_small_for_enum : Warning< + "bit-field %0 is not wide enough to store all enumerators of %1">, + InGroup<BitFieldEnumConversion>, DefaultIgnore; +def note_widen_bitfield : Note< + "widen this field to %0 bits to store all values of %1">; +def warn_unsigned_bitfield_assigned_signed_enum : Warning< + "assigning value of signed enum type %1 to unsigned bit-field %0; " + "negative enumerators of enum %1 will be converted to positive values">, + InGroup<BitFieldEnumConversion>, DefaultIgnore; +def warn_signed_bitfield_enum_conversion : Warning< + "signed bit-field %0 needs an extra bit to represent the largest positive " + "enumerators of %1">, + InGroup<BitFieldEnumConversion>, DefaultIgnore; +def note_change_bitfield_sign : Note< + "consider making the bitfield type %select{unsigned|signed}0">; def warn_missing_braces : Warning< "suggest braces around initialization of subobject">, @@ -4962,6 +5102,8 @@ def note_protected_by_if_available : Note< "jump enters controlled statement of if available">; def note_protected_by_vla : Note< "jump bypasses initialization of variable length array">; +def note_protected_by_objc_fast_enumeration : Note< + "jump enters Objective-C fast enumeration loop">; def note_protected_by_objc_try : Note< "jump bypasses initialization of @try block">; def note_protected_by_objc_catch : Note< @@ -5080,6 +5222,28 @@ def ext_flexible_array_empty_aggregate_gnu : Extension< def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>; +def err_flexible_array_not_at_end : Error< + "flexible array member %0 with type %1 is not at the end of" + " %select{struct|interface|union|class|enum}2">; +def err_objc_variable_sized_type_not_at_end : Error< + "field %0 with variable sized type %1 is not at the end of class">; +def note_next_field_declaration : Note< + "next field declaration is here">; +def note_next_ivar_declaration : Note< + "next %select{instance variable declaration|synthesized instance variable}0" + " is here">; +def err_synthesize_variable_sized_ivar : Error< + "synthesized property with variable size type %0" + " requires an existing instance variable">; +def err_flexible_array_arc_retainable : Error< + "ARC forbids flexible array members with retainable object type">; +def warn_variable_sized_ivar_visibility : Warning< + "field %0 with variable sized type %1 is not visible to subclasses and" + " can conflict with their instance variables">, InGroup<ObjCFlexibleArray>; +def warn_superclass_variable_sized_type_not_at_end : Warning< + "field %0 can overwrite instance variable %1 with variable sized type %2" + " in superclass %3">, InGroup<ObjCFlexibleArray>; + let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. @@ -5391,6 +5555,12 @@ def err_offsetof_field_of_virtual_base : Error< def warn_sub_ptr_zero_size_types : Warning< "subtraction of pointers to type %0 of zero size has undefined behavior">, InGroup<PointerArith>; +def warn_pointer_arith_null_ptr : Warning< + "performing pointer arithmetic on a null pointer has undefined behavior%select{| if the offset is nonzero}0">, + InGroup<NullPointerArithmetic>, DefaultIgnore; +def warn_gnu_null_ptr_arith : Warning< + "arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">, + InGroup<NullPointerArithmetic>, DefaultIgnore; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, @@ -5555,6 +5725,11 @@ def err_enumerator_does_not_exist : Error< def note_enum_specialized_here : Note< "enum %0 was explicitly specialized here">; +def err_specialization_not_primary_template : Error< + "cannot reference member of primary template because deduced class " + "template specialization %0 is %select{instantiated from a partial|" + "an explicit}1 specialization">; + def err_member_redeclared : Error<"class member cannot be redeclared">; def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">, InGroup<RedeclaredClassMember>; @@ -5727,6 +5902,9 @@ def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">; +def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error< + "logical expression with vector %select{type %1 and non-vector type %2|types" + " %1 and %2}0 is only supported in C++">; def err_typecheck_sub_ptr_compatible : Error< "%diff{$ and $ are not pointers to compatible types|" "pointers to incompatible types}0,1">; @@ -5770,6 +5948,8 @@ def err_typecheck_assign_const : Error< "cannot assign to %select{non-|}1static data member %2 " "with const-qualified type %3|" "cannot assign to non-static data member within const member function %1|" + "cannot assign to %select{variable %2|non-static data member %2|lvalue}1 " + "with %select{|nested }3const-qualified data member %4|" "read-only variable is not assignable}0">; def note_typecheck_assign_const : Note< @@ -5777,25 +5957,37 @@ def note_typecheck_assign_const : Note< "function %1 which returns const-qualified type %2 declared here|" "variable %1 declared const here|" "%select{non-|}1static data member %2 declared const here|" - "member function %q1 is declared const here}0">; + "member function %q1 is declared const here|" + "%select{|nested }1data member %2 declared const here}0">; + +def warn_unsigned_always_true_comparison : Warning< + "comparison of %select{%3|unsigned expression}0 %2 " + "%select{unsigned expression|%3}0 is always %select{false|true}4">, + InGroup<TautologicalUnsignedZeroCompare>; +def warn_unsigned_enum_always_true_comparison : Warning< + "comparison of %select{%3|unsigned enum expression}0 %2 " + "%select{unsigned enum expression|%3}0 is always %select{false|true}4">, + InGroup<TautologicalUnsignedEnumZeroCompare>; +def warn_tautological_constant_compare : Warning< + "comparison %select{%3|%1}0 %2 " + "%select{%1|%3}0 is always %select{false|true}4">, + InGroup<TautologicalConstantCompare>; def warn_mixed_sign_comparison : Warning< "comparison of integers of different signs: %0 and %1">, InGroup<SignCompare>, DefaultIgnore; -def warn_lunsigned_always_true_comparison : Warning< - "comparison of unsigned%select{| enum}2 expression %0 is always %1">, - InGroup<TautologicalCompare>; def warn_out_of_range_compare : Warning< "comparison of %select{constant %0|true|false}1 with " "%select{expression of type %2|boolean expression}3 is always " "%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>; -def warn_runsigned_always_true_comparison : Warning< - "comparison of %0 unsigned%select{| enum}2 expression is always %1">, - InGroup<TautologicalCompare>; def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types" "%diff{ ($ and $)|}0,1">, - InGroup<DiagGroup<"enum-compare">>; + InGroup<EnumCompare>; +def warn_comparison_of_mixed_enum_types_switch : Warning< + "comparison of two values with different enumeration types in switch statement" + "%diff{ ($ and $)|}0,1">, + InGroup<EnumCompareSwitch>; def warn_null_in_arithmetic_operation : Warning< "use of NULL in arithmetic operation">, InGroup<NullArithmetic>; @@ -5850,8 +6042,8 @@ def err_builtin_func_cast_more_than_one_arg : Error< "function-style cast to a builtin type can only take one argument">; def err_value_init_for_array_type : Error< "array types cannot be value-initialized">; -def err_value_init_for_function_type : Error< - "function types cannot be value-initialized">; +def err_init_for_function_type : Error< + "cannot create object of function type %0">; def warn_format_nonliteral_noargs : Warning< "format string is not a string literal (potentially insecure)">, InGroup<FormatSecurity>; @@ -6240,12 +6432,14 @@ def warn_ambiguous_suitable_delete_function_found : Warning< InGroup<DiagGroup<"ambiguous-delete">>; def note_member_declared_here : Note< "member %0 declared here">; +def note_member_first_declared_here : Note< + "member %0 first declared here">; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated and " - "incompatible with C++1z">, InGroup<DeprecatedIncrementBool>; + "incompatible with C++17">, InGroup<DeprecatedIncrementBool>; def ext_increment_bool : ExtWarn< - "ISO C++1z does not allow incrementing expression of type bool">, + "ISO C++17 does not allow incrementing expression of type bool">, DefaultError, InGroup<IncrementBool>; def err_increment_decrement_enum : Error< "cannot %select{decrement|increment}0 expression of enum type %1">; @@ -6273,6 +6467,13 @@ def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; +def warn_throw_in_noexcept_func : Warning< + "%0 has a non-throwing exception specification but can still throw">, + InGroup<Exceptions>; +def note_throw_in_dtor : Note< + "%select{destructor|deallocator}0 has a %select{non-throwing|implicit " + "non-throwing}1 exception specification">; +def note_throw_in_function : Note<"function declared non-throwing here">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< @@ -6290,12 +6491,12 @@ def warn_non_virtual_dtor : Warning< def warn_delete_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on non-final %1 that has " "virtual functions but non-virtual destructor">, - InGroup<DeleteNonVirtualDtor>, DefaultIgnore; + InGroup<DeleteNonVirtualDtor>, DefaultIgnore, ShowInSystemHeader; def note_delete_non_virtual : Note< "qualify call to silence this warning">; def warn_delete_abstract_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on %1 that is abstract but has " - "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>; + "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>, ShowInSystemHeader; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup<OverloadedVirtual>, DefaultIgnore; @@ -6318,6 +6519,12 @@ def warn_overaligned_type : Warning< "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup<OveralignedType>, DefaultIgnore; +def warn_aligned_allocation_unavailable :Warning< + "aligned %select{allocation|deallocation}0 function of type '%1' is only " + "available on %2 %3 or newer">, InGroup<AlignedAllocationUnavailable>, DefaultError; +def note_silence_unligned_allocation_unavailable : Note< + "if you supply your own aligned allocation functions, use " + "-Wno-aligned-allocation-unavailable to silence this diagnostic">; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " @@ -6351,8 +6558,6 @@ let CategoryName = "Lambda Issue" in { "%0 can appear only once in a capture list">; def err_reference_capture_with_reference_default : Error< "'&' cannot precede a capture when the capture default is '&'">; - def err_this_capture_with_copy_default : Error< - "'this' cannot be explicitly captured when the capture default is '='">; def err_copy_capture_with_copy_default : Error< "'&' must precede a capture when the capture default is '='">; def err_capture_does_not_name_variable : Error< @@ -6419,12 +6624,20 @@ let CategoryName = "Lambda Issue" in { def err_init_capture_deduction_failure_from_init_list : Error< "cannot deduce type for lambda capture %0 from initializer list">; - // C++1z '*this' captures. + // C++17 '*this' captures. def warn_cxx14_compat_star_this_lambda_capture : Warning< - "by value capture of '*this' is incompatible with C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; - def ext_star_this_lambda_capture_cxx1z : ExtWarn< - "capture of '*this' by copy is a C++1z extension">, InGroup<CXX1z>; + "by value capture of '*this' is incompatible with C++ standards before C++17">, + InGroup<CXXPre17Compat>, DefaultIgnore; + def ext_star_this_lambda_capture_cxx17 : ExtWarn< + "capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>; + + // C++2a [=, this] captures. + def warn_cxx17_compat_equals_this_lambda_capture : Warning< + "explicit capture of 'this' with a capture default of '=' is incompatible " + "with C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; + def ext_equals_this_lambda_capture_cxx2a : ExtWarn< + "explicit capture of 'this' with a capture default of '=' " + "is a C++2a extension">, InGroup<CXX2a>; } def err_return_in_captured_stmt : Error< @@ -6874,8 +7087,8 @@ def err_atomic_op_needs_atomic : Error< "address argument to atomic operation must be a pointer to _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_non_const_atomic : Error< - "address argument to atomic operation must be a pointer to non-const _Atomic " - "type (%0 invalid)">; + "address argument to atomic operation must be a pointer to non-%select{const|constant}0 _Atomic " + "type (%1 invalid)">; def err_atomic_op_needs_non_const_pointer : Error< "address argument to atomic operation must be a pointer to non-const " "type (%0 invalid)">; @@ -6891,6 +7104,8 @@ def err_atomic_op_bitwise_needs_atomic_int : Error< def warn_atomic_op_has_invalid_memory_order : Warning< "memory order argument to atomic operation is invalid">, InGroup<DiagGroup<"atomic-memory-ordering">>; +def err_atomic_op_has_invalid_synch_scope : Error< + "synchronization scope argument to atomic operation is invalid">; def err_overflow_builtin_must_be_int : Error< "operand argument to overflow builtin must be an integer (%0 invalid)">; @@ -7092,8 +7307,8 @@ def warn_unused_volatile : Warning< def ext_cxx14_attr : Extension< "use of the %0 attribute is a C++14 extension">, InGroup<CXX14>; -def ext_cxx1z_attr : Extension< - "use of the %0 attribute is a C++1z extension">, InGroup<CXX1z>; +def ext_cxx17_attr : Extension< + "use of the %0 attribute is a C++17 extension">, InGroup<CXX17>; def warn_unused_comparison : Warning< "%select{%select{|in}1equality|relational}0 comparison result unused">, @@ -7205,11 +7420,11 @@ def err_invalid_conversion_between_vector_and_integer : Error< "invalid conversion between vector type %0 and integer type %1 " "of different size">; -def err_opencl_function_pointer_variable : Error< +def err_opencl_function_pointer : Error< "pointers to functions are not allowed">; -def err_opencl_taking_function_address : Error< - "taking address of function is not allowed">; +def err_opencl_taking_address_capture : Error< + "taking address of a capture is not allowed">; def err_invalid_conversion_between_vector_and_scalar : Error< "invalid conversion between vector type %0 and scalar type %1">; @@ -7350,6 +7565,9 @@ def err_ambiguous_derived_to_base_conv : Error< def err_ambiguous_memptr_conv : Error< "ambiguous conversion from pointer to member of %select{base|derived}0 " "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; +def ext_ms_ambiguous_direct_base : ExtWarn< + "accessing inaccessible direct base %0 of %1 is a Microsoft extension">, + InGroup<MicrosoftInaccessibleBase>; def err_memptr_conv_via_virtual : Error< "conversion from pointer to member of class %0 to pointer to member " @@ -7419,6 +7637,11 @@ def err_operator_delete_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; use %1 instead">; def err_operator_delete_param_type : Error< "first parameter of %0 must have type %1">; +def err_destroying_operator_delete_not_usual : Error< + "destroying operator delete can have only an optional size and optional " + "alignment parameter">; +def note_implicit_delete_this_in_destructor_here : Note< + "while checking implicit 'delete this' for virtual destructor">; // C++ literal operators def err_literal_operator_outside_namespace : Error< @@ -7761,6 +7984,8 @@ def err_builtin_annotation_first_arg : Error< "first argument to __builtin_annotation must be an integer">; def err_builtin_annotation_second_arg : Error< "second argument to __builtin_annotation must be a non-wide string constant">; +def err_msvc_annotation_wide_str : Error< + "arguments to __annotation must be wide string constants">; // CFString checking def err_cfstring_literal_not_string_constant : Error< @@ -7876,7 +8101,11 @@ def warn_empty_switch_body : Warning< def note_empty_body_on_separate_line : Note< "put the semicolon on a separate line to silence this warning">; -def err_va_start_used_in_non_variadic_function : Error< +def err_va_start_captured_stmt : Error< + "'va_start' cannot be used in a captured statement">; +def err_va_start_outside_function : Error< + "'va_start' cannot be used outside a function">; +def err_va_start_fixed_function : Error< "'va_start' used in function with fixed args">; def err_va_start_used_in_wrong_abi_function : Error< "'va_start' used in %select{System V|Win64}0 ABI function">; @@ -7947,10 +8176,13 @@ def err_block_on_nonlocal : Error< def err_block_on_vm : Error< "__block attribute not allowed on declaration with a variably modified type">; -def err_shufflevector_non_vector : Error< - "first two arguments to __builtin_shufflevector must be vectors">; -def err_shufflevector_incompatible_vector : Error< - "first two arguments to __builtin_shufflevector must have the same type">; +def err_vec_builtin_non_vector : Error< + "first two arguments to %0 must be vectors">; +def err_vec_builtin_incompatible_vector : Error< + "first two arguments to %0 must have the same type">; +def err_vsx_builtin_nonconstant_argument : Error< + "argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">; + def err_shufflevector_nonconstant_argument : Error< "index for __builtin_shufflevector must be a constant integer">; def err_shufflevector_argument_too_large : Error< @@ -7999,10 +8231,10 @@ def err_systemz_invalid_tabort_code : Error< "invalid transaction abort code">; def err_64_bit_builtin_32_bit_tgt : Error< "this builtin is only available on 64-bit targets">; +def err_builtin_x64_aarch64_only : Error< + "this builtin is only available on x86-64 and aarch64 targets">; def err_ppc_builtin_only_on_pwr7 : Error< "this builtin is only valid on POWER7 or later CPUs">; -def err_x86_builtin_32_bit_tgt : Error< - "this builtin is only available on x86-64 targets">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< @@ -8081,12 +8313,12 @@ def err_c99_array_usage_cxx : Error< "feature, not permitted in C++">; def err_type_unsupported : Error< "%0 is not supported on this target">; -def err_nsconsumed_attribute_mismatch : Error< +def warn_nsconsumed_attribute_mismatch : Warning< "overriding method has mismatched ns_consumed attribute on its" - " parameter">; -def err_nsreturns_retained_attribute_mismatch : Error< + " parameter">, InGroup<NSConsumedMismatch>; +def warn_nsreturns_retained_attribute_mismatch : Warning< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" - " attributes">; + " attributes">, InGroup<NSReturnsMismatch>; def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; @@ -8134,9 +8366,20 @@ def err_undeclared_use_suggest : Error< "use of undeclared %0; did you mean %1?">; def err_undeclared_var_use_suggest : Error< "use of undeclared identifier %0; did you mean %1?">; +def err_no_template : Error<"no template named %0">; def err_no_template_suggest : Error<"no template named %0; did you mean %1?">; +def err_no_member_template : Error<"no template named %0 in %1">; def err_no_member_template_suggest : Error< "no template named %0 in %1; did you mean %select{|simply }2%3?">; +def err_non_template_in_template_id : Error< + "%0 does not name a template but is followed by template arguments">; +def err_non_template_in_template_id_suggest : Error< + "%0 does not name a template but is followed by template arguments; " + "did you mean %1?">; +def err_non_template_in_member_template_id_suggest : Error< + "member %0 of %1 is not a template; did you mean %select{|simply }2%3?">; +def note_non_template_in_template_id_found : Note< + "non-template declaration found by name lookup">; def err_mem_init_not_member_or_class_suggest : Error< "initializer %0 does not name a non-static data member or base " "class; did you mean the %select{base class|member}1 %2?">; @@ -8221,14 +8464,22 @@ def err_opencl_ptrptr_kernel_param : Error< def err_kernel_arg_address_space : Error< "pointer arguments to kernel functions must reside in '__global', " "'__constant' or '__local' address space">; +def err_opencl_ext_vector_component_invalid_length : Error< + "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">; def err_opencl_function_variable : Error< "%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">; +def err_opencl_addrspace_scope : Error< + "variables in the %0 address space can only be declared in the outermost " + "scope of a kernel function">; def err_static_function_scope : Error< "variables in function scope cannot be declared static">; def err_opencl_bitfields : Error< "bit-fields are not supported in OpenCL">; def err_opencl_vla : Error< "variable length arrays are not supported in OpenCL">; +def err_opencl_scalar_type_rank_greater_than_vector_type : Error< + "scalar operand type has greater rank than the type of the vector " + "element. (%0 and %1)">; def err_bad_kernel_param_type : Error< "%0 cannot be used as the type of a kernel parameter">; def err_record_with_pointers_kernel_param : Error< @@ -8251,6 +8502,8 @@ def err_sampler_argument_required : Error< "sampler_t variable required - got %0">; def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; +def err_opencl_nonconst_global_sampler : Error< + "global sampler requires a const or constant address space qualifier">; def err_opencl_cast_non_zero_to_event_t : Error< "cannot cast non-zero value '%0' to 'event_t'">; def err_opencl_global_invalid_addr_space : Error< @@ -8266,9 +8519,9 @@ def err_opencl_return_value_with_address_space : Error< "return value cannot be qualified with address space">; def err_opencl_constant_no_init : Error< "variable in constant address space must be initialized">; -def err_atomic_init_constant : Error< - "atomic variable can only be assigned to a compile time constant" - " in the declaration statement in the program scope">; +def err_opencl_atomic_init: Error< + "atomic variable can be %select{assigned|initialized}0 to a variable only " + "in global address space">; def err_opencl_implicit_vector_conversion : Error< "implicit conversions between vector types (%0 and %1) are not permitted">; def err_opencl_invalid_type_array : Error< @@ -8285,7 +8538,7 @@ def warn_opencl_attr_deprecated_ignored : Warning < def err_opencl_variadic_function : Error< "invalid prototype, variadic arguments are not allowed in OpenCL">; def err_opencl_requires_extension : Error< - "use of %select{type |declaration}0%1 requires %2 extension to be enabled">; + "use of %select{type|declaration}0 %1 requires %2 extension to be enabled">; // OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions def err_opencl_builtin_pipe_first_arg : Error< @@ -8330,8 +8583,6 @@ def err_opencl_builtin_to_addr_invalid_arg : Error< // OpenCL v2.0 s6.13.17 Enqueue kernel restrictions. def err_opencl_enqueue_kernel_incorrect_args : Error< "illegal call to enqueue_kernel, incorrect argument types">; -def err_opencl_enqueue_kernel_expected_type : Error< - "illegal call to enqueue_kernel, expected %0 argument type">; def err_opencl_enqueue_kernel_local_size_args : Error< "mismatch in number of block parameters and local size arguments passed">; def err_opencl_enqueue_kernel_invalid_local_size_type : Error< @@ -8341,6 +8592,9 @@ def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error< def err_opencl_enqueue_kernel_blocks_no_args : Error< "blocks with parameters are not accepted in this prototype of enqueue_kernel call">; +def err_opencl_builtin_expected_type : Error< + "illegal call to %0, expected %1 argument type">; + // OpenCL v2.2 s2.1.2.3 - Vector Component Access def ext_opencl_ext_vector_type_rgba_selector: ExtWarn< "vector component name '%0' is an OpenCL version 2.2 feature">, @@ -8380,6 +8634,8 @@ def err_omp_expected_var_name_member_expr : Error< "expected variable name%select{| or data member of current class}0">; def err_omp_expected_var_name_member_expr_or_array_item : Error< "expected variable name%select{|, data member of current class}0, array element or array section">; +def err_omp_expected_addressable_lvalue_or_array_item : Error< + "expected addressable lvalue expression, array element or array section">; def err_omp_expected_named_var_member_or_array_expression: Error< "expected expression containing only member accesses and/or array sections based on named variables">; def err_omp_bit_fields_forbidden_in_clause : Error< @@ -8517,11 +8773,11 @@ def err_omp_unknown_reduction_identifier : Error< def err_omp_not_resolved_reduction_identifier : Error< "unable to resolve declare reduction construct for type %0">; def err_omp_reduction_ref_type_arg : Error< - "argument of OpenMP clause 'reduction' must reference the same object in all threads">; + "argument of OpenMP clause '%0' must reference the same object in all threads">; def err_omp_clause_not_arithmetic_type_arg : Error< - "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">; + "arguments of OpenMP clause '%0' for 'min' or 'max' must be of %select{scalar|arithmetic}1 type">; def err_omp_clause_floating_type_arg : Error< - "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">; + "arguments of OpenMP clause '%0' with bitwise operators cannot be of floating type">; def err_omp_once_referenced : Error< "variable can appear only once in OpenMP '%0' clause">; def err_omp_once_referenced_in_target_update : Error< @@ -8532,6 +8788,12 @@ def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< "list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; +def err_omp_in_reduction_not_task_reduction : Error< + "in_reduction variable must appear in a task_reduction clause">; +def err_omp_reduction_identifier_mismatch : Error< + "in_reduction variable must have the same reduction operation as in a task_reduction clause">; +def note_omp_previous_reduction_identifier : Note< + "previously marked as task_reduction with different reduction operation">; def err_omp_prohibited_region : Error< "region cannot be%select{| closely}0 nested inside '%1' region" "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" @@ -8655,16 +8917,10 @@ def err_omp_expected_base_var_name : Error< "expected variable name as a base of the array %select{subscript|section}0">; def err_omp_map_shared_storage : Error< "variable already marked as mapped in current construct">; -def err_omp_not_mappable_type : Error< - "type %0 is not mappable to target">; def err_omp_invalid_map_type_for_directive : Error< "%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">; -def err_omp_no_map_for_directive : Error< - "expected at least one map clause for '#pragma omp %0'">; -def note_omp_polymorphic_in_target : Note< - "mappable type cannot be polymorphic">; -def note_omp_static_member_in_target : Note< - "mappable type cannot contain static members">; +def err_omp_no_clause_for_directive : Error< + "expected at least one %0 clause for '#pragma omp %1'">; def err_omp_threadprivate_in_clause : Error< "threadprivate variables are not allowed in '%0' clause">; def err_omp_wrong_ordered_loop_count : Error< @@ -8683,16 +8939,10 @@ def note_omp_critical_hint_here : Note< "%select{|previous }0'hint' clause with value '%1'">; def note_omp_critical_no_hint : Note< "%select{|previous }0directive with no 'hint' clause specified">; -def err_omp_firstprivate_distribute_private_teams : Error< - "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; -def err_omp_firstprivate_and_lastprivate_in_distribute : Error< - "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">; -def err_omp_firstprivate_distribute_in_teams_reduction : Error< - "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; def err_omp_depend_clause_thread_simd : Error< "'depend' clauses cannot be mixed with '%0' clause">; def err_omp_depend_sink_expected_loop_iteration : Error< - "expected %0 loop iteration variable">; + "expected%select{| %1}0 loop iteration variable">; def err_omp_depend_sink_unexpected_expr : Error< "unexpected expression: number of expressions is larger than the number of associated loops">; def err_omp_depend_sink_expected_plus_minus : Error< @@ -8729,6 +8979,10 @@ def warn_omp_nesting_simd : Warning< def err_omp_orphaned_device_directive : Error< "orphaned 'omp %0' directives are prohibited" "; perhaps you forget to enclose the directive into a %select{|||target |teams }1region?">; +def err_omp_reduction_non_addressable_expression : Error< + "expected addressable reduction item for the task-based directives">; +def err_omp_reduction_with_nogroup : Error< + "'reduction' clause cannot be used with 'nogroup' clause">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { @@ -8759,15 +9013,25 @@ def err_invalid_type_for_program_scope_var : Error< } let CategoryName = "Modules Issue" in { +def err_module_decl_in_module_map_module : Error< + "'module' declaration found while building module from module map">; def err_module_interface_implementation_mismatch : Error< - "%select{'module'|'module partition'|'module implementation'}0 declaration " - "found while %select{not |not |}0building module interface">; + "missing 'export' specifier in module declaration while " + "building module interface">; def err_current_module_name_mismatch : Error< "module name '%0' specified on command line does not match name of module">; def err_module_redefinition : Error< "redefinition of module '%0'">; def note_prev_module_definition : Note<"previously defined here">; def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">; +def err_module_not_defined : Error< + "definition of module '%0' is not available; use -fmodule-file= to specify " + "path to precompiled module interface">; +def err_module_redeclaration : Error< + "translation unit contains multiple module declarations">; +def note_prev_module_declaration : Note<"previous module declaration is here">; +def err_module_declaration_missing : Error< + "missing 'export module' declaration in module interface unit">; def err_module_private_specialization : Error< "%select{template|partial|member}0 specialization cannot be " "declared __module_private__">; @@ -8804,14 +9068,24 @@ def err_module_self_import : Error< "import of module '%0' appears within same top-level module '%1'">; def err_module_import_in_implementation : Error< "@import of module '%0' in implementation of '%1'; use #import">; + +// C++ Modules TS def err_export_within_export : Error< "export declaration appears within another export declaration">; +def err_export_not_in_module_interface : Error< + "export declaration can only be used within a module interface unit after " + "the module declaration">; def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< "ambiguous use of internal linkage declaration %0 defined in multiple modules">, InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>; def note_equivalent_internal_linkage_decl : Note< "declared here%select{ in module '%1'|}0">; + +def note_redefinition_modules_same_file : Note< + "'%0' included multiple times, additional include site in header from module '%1'">; +def note_redefinition_include_same_file : Note< + "'%0' included multiple times, additional include site here">; } let CategoryName = "Coroutines Issue" in { @@ -8833,6 +9107,11 @@ def err_coroutine_invalid_func_context : Error< def err_implied_coroutine_type_not_found : Error< "%0 type was not found; include <experimental/coroutine> before defining " "a coroutine">; +def err_implicit_coroutine_std_nothrow_type_not_found : Error< + "std::nothrow was not found; include <new> before defining a coroutine which " + "uses get_return_object_on_allocation_failure()">; +def err_malformed_std_nothrow : Error< + "std::nothrow must be a valid variable declaration">; def err_malformed_std_coroutine_handle : Error< "std::experimental::coroutine_handle must be a class template">; def err_coroutine_handle_missing_member : Error< @@ -8848,18 +9127,35 @@ def err_coroutine_promise_type_incomplete : Error< def err_coroutine_type_missing_specialization : Error< "this function cannot be a coroutine: missing definition of " "specialization %q0">; -def err_implied_std_current_exception_not_found : Error< - "you need to include <exception> before defining a coroutine that implicitly " - "uses 'set_exception'">; -def err_malformed_std_current_exception : Error< - "'std::current_exception' must be a function">; -def err_coroutine_promise_return_ill_formed : Error< - "%0 declares both 'return_value' and 'return_void'">; +def err_coroutine_promise_incompatible_return_functions : Error< + "the coroutine promise type %0 declares both 'return_value' and 'return_void'">; +def err_coroutine_promise_requires_return_function : Error< + "the coroutine promise type %0 must declare either 'return_value' or 'return_void'">; def note_coroutine_promise_implicit_await_transform_required_here : Note< "call to 'await_transform' implicitly required by 'co_await' here">; -def note_coroutine_promise_call_implicitly_required : Note< +def note_coroutine_promise_suspend_implicitly_required : Note< "call to '%select{initial_suspend|final_suspend}0' implicitly " "required by the %select{initial suspend point|final suspend point}0">; +def err_coroutine_promise_unhandled_exception_required : Error< + "%0 is required to declare the member 'unhandled_exception()'">; +def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning< + "%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">, + InGroup<CoroutineMissingUnhandledException>; +def err_coroutine_promise_get_return_object_on_allocation_failure : Error< + "%0: 'get_return_object_on_allocation_failure()' must be a static member function">; +def err_seh_in_a_coroutine_with_cxx_exceptions : Error< + "cannot use SEH '__try' in a coroutine when C++ exceptions are enabled">; +def err_coroutine_promise_new_requires_nothrow : Error< + "%0 is required to have a non-throwing noexcept specification when the promise " + "type declares 'get_return_object_on_allocation_failure()'">; +def note_coroutine_promise_call_implicitly_required : Note< + "call to %0 implicitly required by coroutine function here">; +def err_await_suspend_invalid_return_type : Error< + "return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)" +>; +def note_await_ready_no_bool_conversion : Note< + "return type of 'await_ready' is required to be contextually convertible to 'bool'" +>; } let CategoryName = "Documentation Issue" in { @@ -8870,8 +9166,13 @@ def warn_not_a_doxygen_trailing_member_comment : Warning< let CategoryName = "Instrumentation Issue" in { def warn_profile_data_out_of_date : Warning< "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" - " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, + " mismatched data that will be ignored">, InGroup<ProfileInstrOutOfDate>; +def warn_profile_data_missing : Warning< + "profile data may be incomplete: of %0 function%s0, %1 %plural{1:has|:have}1" + " no data">, + InGroup<ProfileInstrMissing>, + DefaultIgnore; def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup<ProfileInstrUnprofiled>; @@ -8901,6 +9202,9 @@ def warn_nullability_lost : Warning< "implicit conversion from nullable pointer %0 to non-nullable pointer " "type %1">, InGroup<NullableToNonNullConversion>, DefaultIgnore; +def warn_zero_as_null_pointer_constant : Warning< + "zero as null pointer constant">, + InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore; def err_nullability_cs_multilevel : Error< "nullability keyword %0 cannot be applied to multi-level pointer type %1">; diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index d6e040a442..3f0a14c59f 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -112,19 +112,65 @@ def note_module_odr_violation_possible_decl : Note< def err_module_odr_violation_different_definitions : Error< "%q0 has different definitions in different modules; " "%select{definition in module '%2' is here|defined here}1">; +def note_first_module_difference : Note< + "in first definition, possible difference is here">; def note_module_odr_violation_different_definitions : Note< "definition in module '%0' is here">; +def note_second_module_difference : Note< + "in second definition, possible difference is here">; + def err_module_odr_violation_different_instantiations : Error< "instantiation of %q0 is different in different modules">; +def err_module_odr_violation_definition_data : Error < + "%q0 has different definitions in different modules; first difference is " + "%select{definition in module '%2'|defined here}1 found " + "%select{" + "%4 base %plural{1:class|:classes}4|" + "%4 virtual base %plural{1:class|:classes}4|" + "%ordinal4 base class with type %5|" + "%ordinal4 %select{non-virtual|virtual}5 base class %6|" + "%ordinal4 base class %5 with " + "%select{public|protected|private|no}6 access specifier}3">; + +def note_module_odr_violation_definition_data : Note < + "but in '%0' found " + "%select{" + "%2 base %plural{1:class|:classes}2|" + "%2 virtual base %plural{1:class|:classes}2|" + "%ordinal2 base class with different type %3|" + "%ordinal2 %select{non-virtual|virtual}3 base class %4|" + "%ordinal2 base class %3 with " + "%select{public|protected|private|no}4 access specifier}1">; + +def err_module_odr_violation_template_parameter : Error < + "%q0 has different definitions in different modules; first difference is " + "%select{definition in module '%2'|defined here}1 found " + "%select{" + "unnamed template parameter|" + "template parameter %4|" + "template parameter with %select{no |}4default argument|" + "template parameter with default argument}3">; + + +def note_module_odr_violation_template_parameter : Note < + "but in '%0' found " + "%select{" + "unnamed template parameter %2|" + "template parameter %2|" + "template parameter with %select{no |}2default argument|" + "template parameter with different default argument}1">; + def err_module_odr_violation_mismatch_decl : Error< "%q0 has different definitions in different modules; first difference is " "%select{definition in module '%2'|defined here}1 found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert|field|method}3">; + "protected access specifier|static assert|field|method|type alias|typedef|" + "data member|friend declaration}3">; def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert|field|method}1">; + "protected access specifier|static assert|field|method|type alias|typedef|" + "data member|friend declaration}1">; def err_module_odr_violation_mismatch_decl_diff : Error< "%q0 has different definitions in different modules; first difference is " @@ -140,13 +186,40 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "%select{non-|}5mutable field %4|" "field %4 with %select{no|an}5 initalizer|" "field %4 with an initializer|" - "method %4|" - "method %4 is %select{not deleted|deleted}5|" - "method %4 is %select{|pure }5%select{not virtual|virtual}6|" - "method %4 is %select{not static|static}5|" - "method %4 is %select{not volatile|volatile}5|" - "method %4 is %select{not const|const}5|" - "method %4 is %select{not inline|inline}5}3">; + "%select{method %5|constructor|destructor}4|" + "%select{method %5|constructor|destructor}4 " + "is %select{not deleted|deleted}6|" + "%select{method %5|constructor|destructor}4 " + "is %select{|pure }6%select{not virtual|virtual}7|" + "%select{method %5|constructor|destructor}4 " + "is %select{not static|static}6|" + "%select{method %5|constructor|destructor}4 " + "is %select{not volatile|volatile}6|" + "%select{method %5|constructor|destructor}4 " + "is %select{not const|const}6|" + "%select{method %5|constructor|destructor}4 " + "is %select{not inline|inline}6|" + "%select{method %5|constructor|destructor}4 " + "that has %6 parameter%s6|" + "%select{method %5|constructor|destructor}4 " + "with %ordinal6 parameter of type %7%select{| decayed from %9}8|" + "%select{method %5|constructor|destructor}4 " + "with %ordinal6 parameter named %7|" + "%select{method %5|constructor|destructor}4 " + "with %ordinal6 parameter with%select{out|}7 a default argument|" + "%select{method %5|constructor|destructor}4 " + "with %ordinal6 parameter with a default argument|" + "%select{typedef|type alias}4 name %5|" + "%select{typedef|type alias}4 %5 with underlying type %6|" + "data member with name %4|" + "data member %4 with type %5|" + "data member %4 with%select{out|}5 an initializer|" + "data member %4 with an initializer|" + "data member %4 %select{is constexpr|is not constexpr}5|" + "friend %select{class|function}4|" + "friend %4|" + "friend function %4|" + "}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{" @@ -160,22 +233,69 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{non-|}3mutable field %2|" "field %2 with %select{no|an}3 initializer|" "field %2 with a different initializer|" - "method %2|" - "method %2 is %select{not deleted|deleted}3|" - "method %2 is %select{|pure }3%select{not virtual|virtual}4|" - "method %2 is %select{not static|static}3|" - "method %2 is %select{not volatile|volatile}3|" - "method %2 is %select{not const|const}3|" - "method %2 is %select{not inline|inline}3}1">; + "%select{method %3|constructor|destructor}2|" + "%select{method %3|constructor|destructor}2 " + "is %select{not deleted|deleted}4|" + "%select{method %3|constructor|destructor}2 " + "is %select{|pure }4%select{not virtual|virtual}5|" + "%select{method %3|constructor|destructor}2 " + "is %select{not static|static}4|" + "%select{method %3|constructor|destructor}2 " + "is %select{not volatile|volatile}4|" + "%select{method %3|constructor|destructor}2 " + "is %select{not const|const}4|" + "%select{method %3|constructor|destructor}2 " + "is %select{not inline|inline}4|" + "%select{method %3|constructor|destructor}2 " + "that has %4 parameter%s4|" + "%select{method %3|constructor|destructor}2 " + "with %ordinal4 parameter of type %5%select{| decayed from %7}6|" + "%select{method %3|constructor|destructor}2 " + "with %ordinal4 parameter named %5|" + "%select{method %3|constructor|destructor}2 " + "with %ordinal4 parameter with%select{out|}5 a default argument|" + "%select{method %3|constructor|destructor}2 " + "with %ordinal4 parameter with a different default argument|" + "%select{typedef|type alias}2 name %3|" + "%select{typedef|type alias}2 %3 with different underlying type %4|" + "data member with name %2|" + "data member %2 with different type %3|" + "data member %2 with%select{out|}3 an initializer|" + "data member %2 with a different initializer|" + "data member %2 %select{is constexpr|is not constexpr}3|" + "friend %select{class|function}2|" + "friend %2|" + "friend function %2|" + "}1">; -def warn_module_uses_date_time : Warning< - "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, - InGroup<DiagGroup<"pch-date-time">>; +def err_module_odr_violation_mismatch_decl_unknown : Error< + "%q0 %select{with definition in module '%2'|defined here}1 has different " + "definitions in different modules; first difference is this " + "%select{||||static assert|field|method|type alias|typedef|data member|" + "friend declaration|unexpected decl}3">; +def note_module_odr_violation_mismatch_decl_unknown : Note< + "but in '%0' found " + "%select{||||different static assert|different field|different method|" + "different type alias|different typedef|different data member|" + "different friend declaration|another unexpected decl}1">; def warn_duplicate_module_file_extension : Warning< "duplicate module file extension block name '%0'">, InGroup<ModuleFileExtension>; +def warn_module_system_bit_conflict : Warning< + "module file '%0' was validated as a system module and is now being imported " + "as a non-system module; any difference in diagnostic options will be ignored">, + InGroup<ModuleConflict>; +} // let CategoryName + +let CategoryName = "AST Serialization Issue" in { +def warn_module_uses_date_time : Warning< + "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, + InGroup<DiagGroup<"pch-date-time">>; +def err_module_no_size_mtime_for_header : Error< + "cannot emit module %0: %select{size|mtime}1 must be explicitly specified " + "for missing header file \"%2\"">; } // let CategoryName } // let Component diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index aaed481906..3938e09890 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -272,15 +272,15 @@ public: /// this identifier is a C++ alternate representation of an operator. void setIsCPlusPlusOperatorKeyword(bool Val = true) { IsCPPOperatorKeyword = Val; - if (Val) - NeedsHandleIdentifier = true; - else - RecomputeNeedsHandleIdentifier(); } bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } /// \brief Return true if this token is a keyword in the specified language. - bool isKeyword(const LangOptions &LangOpts); + bool isKeyword(const LangOptions &LangOpts) const; + + /// \brief Return true if this token is a C++ keyword in the specified + /// language. + bool isCPlusPlusKeyword(const LangOptions &LangOpts) const; /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to /// associate arbitrary metadata with this token. @@ -351,6 +351,19 @@ public: RecomputeNeedsHandleIdentifier(); } + /// Return true if this identifier is an editor placeholder. + /// + /// Editor placeholders are produced by the code-completion engine and are + /// represented as characters between '<#' and '#>' in the source code. An + /// example of auto-completed call with a placeholder parameter is shown + /// below: + /// \code + /// function(<#int x#>); + /// \endcode + bool isEditorPlaceholder() const { + return getName().startswith("<#") && getName().endswith("#>"); + } + /// \brief Provide less than operator for lexicographical sorting. bool operator<(const IdentifierInfo &RHS) const { return getName() < RHS.getName(); @@ -364,10 +377,9 @@ private: /// This method is very tied to the definition of HandleIdentifier. Any /// change to it should be reflected here. void RecomputeNeedsHandleIdentifier() { - NeedsHandleIdentifier = - (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() | - isExtensionToken() | isFutureCompatKeyword() || isOutOfDate() || - isModulesImport()); + NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() || + isExtensionToken() || isFutureCompatKeyword() || + isOutOfDate() || isModulesImport(); } }; @@ -862,11 +874,10 @@ struct DenseMapInfo<clang::Selector> { template <> struct isPodLike<clang::Selector> { static const bool value = true; }; -template <typename T> class PointerLikeTypeTraits; +template <typename T> struct PointerLikeTypeTraits; template<> -class PointerLikeTypeTraits<clang::Selector> { -public: +struct PointerLikeTypeTraits<clang::Selector> { static inline const void *getAsVoidPointer(clang::Selector P) { return P.getAsOpaquePtr(); } @@ -881,8 +892,7 @@ public: // Provide PointerLikeTypeTraits for IdentifierInfo pointers, which // are not guaranteed to be 8-byte aligned. template<> -class PointerLikeTypeTraits<clang::IdentifierInfo*> { -public: +struct PointerLikeTypeTraits<clang::IdentifierInfo*> { static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { return P; } @@ -895,8 +905,7 @@ public: }; template<> -class PointerLikeTypeTraits<const clang::IdentifierInfo*> { -public: +struct PointerLikeTypeTraits<const clang::IdentifierInfo*> { static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { return P; } diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h index f32ab5e11b..e60284d1b4 100644 --- a/include/clang/Basic/LLVM.h +++ b/include/clang/Basic/LLVM.h @@ -35,6 +35,7 @@ namespace llvm { template<typename T, unsigned N> class SmallVector; template<typename T> class SmallVectorImpl; template<typename T> class Optional; + template <class T> class Expected; template<typename T> struct SaveAndRestore; @@ -71,6 +72,9 @@ namespace clang { using llvm::SmallVectorImpl; using llvm::SaveAndRestore; + // Error handling. + using llvm::Expected; + // Reference counting. using llvm::IntrusiveRefCntPtr; using llvm::IntrusiveRefCntPtrInfo; diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 7126275503..78a743750e 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -89,7 +89,8 @@ LANGOPT(Borland , 1, 0, "Borland extensions") LANGOPT(CPlusPlus , 1, 0, "C++") LANGOPT(CPlusPlus11 , 1, 0, "C++11") LANGOPT(CPlusPlus14 , 1, 0, "C++14") -LANGOPT(CPlusPlus1z , 1, 0, "C++1z") +LANGOPT(CPlusPlus1z , 1, 0, "C++17") +LANGOPT(CPlusPlus2a , 1, 0, "C++2a") LANGOPT(ObjC1 , 1, 0, "Objective-C 1") LANGOPT(ObjC2 , 1, 0, "Objective-C 2") BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0, @@ -136,6 +137,8 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly") LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS") LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") +LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") + BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") LANGOPT(Blocks , 1, 0, "blocks extension to C") @@ -174,7 +177,8 @@ BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __w BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control") LANGOPT(CharIsSigned , 1, 1, "signed char") -LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t") +LANGOPT(WCharSize , 4, 0, "width of wchar_t") +LANGOPT(WCharIsSigned , 1, 0, "signed or unsigned wchar_t") ENUM_LANGOPT(MSPointerToMemberRepresentationMethod, PragmaMSPointersToMembersKind, 2, PPTMK_BestCase, "member-pointer representation method") ENUM_LANGOPT(DefaultCallingConv, DefaultCallingConvention, 3, DCC_None, "default calling convention") @@ -199,9 +203,11 @@ LANGOPT(CUDADeviceApproxTranscendentals, 1, 0, "using approximate transcendental LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") +LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'") LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts") -BENIGN_LANGOPT(ModularCodegen , 1, 0, "Modular codegen") +BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation") +BENIGN_LANGOPT(ModulesDebugInfo , 1, 0, "Modules debug info") BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision") BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records") BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form") @@ -216,7 +222,8 @@ BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and su BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking") LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") -LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT") +/// \brief FP_CONTRACT mode (on/off/fast). +ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") @@ -262,6 +269,11 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "field padding (0: none, 1:least " "aggressive, 2: more aggressive)") +LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") + +BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, + "allow editor placeholders in source") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 10635b1122..51fb5ad661 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -58,6 +58,7 @@ public: SOB_Trapping // -ftrapv }; + // FIXME: Unify with TUKind. enum CompilingModuleKind { CMK_None, ///< Not compiling a module interface at all. CMK_ModuleMap, ///< Compiling a module from a module map. @@ -88,6 +89,12 @@ public: MSVC2015 = 19 }; + enum FPContractModeKind { + FPC_Off, // Form fused FP ops only where result will not be affected. + FPC_On, // Form fused FP ops according to FP_CONTRACT rules. + FPC_Fast // Aggressively fuse FP ops (E.g. FMA). + }; + public: /// \brief Set of enabled sanitizers. SanitizerSet Sanitize; @@ -96,6 +103,16 @@ public: /// (files, functions, variables) should not be instrumented. std::vector<std::string> SanitizerBlacklistFiles; + /// \brief Paths to the XRay "always instrument" files specifying which + /// objects (files, functions, variables) should be imbued with the XRay + /// "always instrument" attribute. + std::vector<std::string> XRayAlwaysInstrumentFiles; + + /// \brief Paths to the XRay "never instrument" files specifying which + /// objects (files, functions, variables) should be imbued with the XRay + /// "never instrument" attribute. + std::vector<std::string> XRayNeverInstrumentFiles; + clang::ObjCRuntime ObjCRuntime; std::string ObjCConstantStringClass; @@ -150,6 +167,11 @@ public: return getCompilingModule() != CMK_None; } + /// Do we need to track the owning module for a local declaration? + bool trackLocalOwningModule() const { + return isCompilingModule() || ModulesLocalVisibility || ModulesTS; + } + bool isSignedOverflowDefined() const { return getSignedOverflowBehavior() == SOB_Defined; } @@ -170,17 +192,49 @@ public: /// \brief Is this a libc/libm function that is no longer recognized as a /// builtin because a -fno-builtin-* option has been specified? bool isNoBuiltinFunc(StringRef Name) const; + + /// \brief True if any ObjC types may have non-trivial lifetime qualifiers. + bool allowsNonTrivialObjCLifetimeQualifiers() const { + return ObjCAutoRefCount || ObjCWeak; + } + + bool assumeFunctionsAreConvergent() const { + return (CUDA && CUDAIsDevice) || OpenCL; + } }; /// \brief Floating point control options class FPOptions { public: - unsigned fp_contract : 1; + FPOptions() : fp_contract(LangOptions::FPC_Off) {} + + // Used for serializing. + explicit FPOptions(unsigned I) + : fp_contract(static_cast<LangOptions::FPContractModeKind>(I)) {} + + explicit FPOptions(const LangOptions &LangOpts) + : fp_contract(LangOpts.getDefaultFPContractMode()) {} + + bool allowFPContractWithinStatement() const { + return fp_contract == LangOptions::FPC_On; + } + bool allowFPContractAcrossStatement() const { + return fp_contract == LangOptions::FPC_Fast; + } + void setAllowFPContractWithinStatement() { + fp_contract = LangOptions::FPC_On; + } + void setAllowFPContractAcrossStatement() { + fp_contract = LangOptions::FPC_Fast; + } + void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; } - FPOptions() : fp_contract(0) {} + /// Used to serialize this. + unsigned getInt() const { return fp_contract; } - FPOptions(const LangOptions &LangOpts) : - fp_contract(LangOpts.DefaultFPContract) {} +private: + /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this. + unsigned fp_contract : 2; }; /// \brief Describes the kind of translation unit being processed. diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index e96fb568c0..6ec8763f24 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -45,6 +45,17 @@ enum Linkage : unsigned char { /// translation units because of types defined in a inline function. VisibleNoLinkage, + /// \brief Internal linkage according to the Modules TS, but can be referred + /// to from other translation units indirectly through inline functions and + /// templates in the module interface. + ModuleInternalLinkage, + + /// \brief Module linkage, which indicates that the entity can be referred + /// to from other translation units within the same module, and indirectly + /// from arbitrary other translation units through inline functions and + /// templates in the module interface. + ModuleLinkage, + /// \brief External linkage, which indicates that the entity can /// be referred to from other translation units. ExternalLinkage @@ -74,15 +85,20 @@ inline bool isDiscardableGVALinkage(GVALinkage L) { } inline bool isExternallyVisible(Linkage L) { - return L == ExternalLinkage || L == VisibleNoLinkage; + return L >= VisibleNoLinkage; } inline Linkage getFormalLinkage(Linkage L) { - if (L == UniqueExternalLinkage) + switch (L) { + case UniqueExternalLinkage: return ExternalLinkage; - if (L == VisibleNoLinkage) + case VisibleNoLinkage: return NoLinkage; - return L; + case ModuleInternalLinkage: + return InternalLinkage; + default: + return L; + } } inline bool isExternalFormalLinkage(Linkage L) { diff --git a/include/clang/Basic/MemoryBufferCache.h b/include/clang/Basic/MemoryBufferCache.h new file mode 100644 index 0000000000..c79c3c40e4 --- /dev/null +++ b/include/clang/Basic/MemoryBufferCache.h @@ -0,0 +1,80 @@ +//===- MemoryBufferCache.h - Cache for loaded memory buffers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H +#define LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringMap.h" +#include <memory> + +namespace llvm { +class MemoryBuffer; +} // end namespace llvm + +namespace clang { + +/// Manage memory buffers across multiple users. +/// +/// Ensures that multiple users have a consistent view of each buffer. This is +/// used by \a CompilerInstance when building PCMs to ensure that each \a +/// ModuleManager sees the same files. +/// +/// \a finalizeCurrentBuffers() should be called before creating a new user. +/// This locks in the current buffers, ensuring that no buffer that has already +/// been accessed can be purged, preventing use-after-frees. +class MemoryBufferCache : public llvm::RefCountedBase<MemoryBufferCache> { + struct BufferEntry { + std::unique_ptr<llvm::MemoryBuffer> Buffer; + + /// Track the timeline of when this was added to the cache. + unsigned Index; + }; + + /// Cache of buffers. + llvm::StringMap<BufferEntry> Buffers; + + /// Monotonically increasing index. + unsigned NextIndex = 0; + + /// Bumped to prevent "older" buffers from being removed. + unsigned FirstRemovableIndex = 0; + +public: + /// Store the Buffer under the Filename. + /// + /// \pre There is not already buffer is not already in the cache. + /// \return a reference to the buffer as a convenience. + llvm::MemoryBuffer &addBuffer(llvm::StringRef Filename, + std::unique_ptr<llvm::MemoryBuffer> Buffer); + + /// Try to remove a buffer from the cache. + /// + /// \return false on success, iff \c !isBufferFinal(). + bool tryToRemoveBuffer(llvm::StringRef Filename); + + /// Get a pointer to the buffer if it exists; else nullptr. + llvm::MemoryBuffer *lookupBuffer(llvm::StringRef Filename); + + /// Check whether the buffer is final. + /// + /// \return true iff \a finalizeCurrentBuffers() has been called since the + /// buffer was added. This prevents buffers from being removed. + bool isBufferFinal(llvm::StringRef Filename); + + /// Finalize the current buffers in the cache. + /// + /// Should be called when creating a new user to ensure previous uses aren't + /// invalidated. + void finalizeCurrentBuffers(); +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index 51ad109088..0b2a665f05 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -62,6 +62,22 @@ public: /// \brief The location of the module definition. SourceLocation DefinitionLoc; + enum ModuleKind { + /// \brief This is a module that was defined by a module map and built out + /// of header files. + ModuleMapModule, + + /// \brief This is a C++ Modules TS module interface unit. + ModuleInterfaceUnit, + + /// \brief This is a fragment of the global module within some C++ Modules + /// TS module. + GlobalModuleFragment, + }; + + /// \brief The kind of this module. + ModuleKind Kind = ModuleMapModule; + /// \brief The parent of this module. This will be NULL for the top-level /// module. Module *Parent; @@ -71,6 +87,10 @@ public: /// are found. const DirectoryEntry *Directory; + /// \brief The presumed file name for the module map defining this module. + /// Only non-empty when building from preprocessed source. + std::string PresumedModuleMapFile; + /// \brief The umbrella header or directory. llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella; @@ -79,6 +99,10 @@ public: /// \brief The name of the umbrella entry, as written in the module map. std::string UmbrellaAsWritten; + + /// \brief The module through which entities defined in this module will + /// eventually be exposed, for use in "private" modules. + std::string ExportAsModule; private: /// \brief The submodules of this module, indexed by name. @@ -138,11 +162,19 @@ public: /// \brief Stored information about a header directive that was found in the /// module map file but has not been resolved to a file. struct UnresolvedHeaderDirective { + HeaderKind Kind = HK_Normal; SourceLocation FileNameLoc; std::string FileName; - bool IsUmbrella; + bool IsUmbrella = false; + bool HasBuiltinHeader = false; + Optional<off_t> Size; + Optional<time_t> ModTime; }; + /// Headers that are mentioned in the module map file but that we have not + /// yet attempted to resolve to a file on the file system. + SmallVector<UnresolvedHeaderDirective, 1> UnresolvedHeaders; + /// \brief Headers that are mentioned in the module map file but could not be /// found on the file system. SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders; @@ -215,8 +247,6 @@ public: /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; - unsigned WithCodegen : 1; - /// \brief Describes the visibility of the various names within a /// particular module. enum NameVisibilityKind { @@ -369,9 +399,20 @@ public: return IsFramework && Parent && Parent->isPartOfFramework(); } + /// Set the parent of this module. This should only be used if the parent + /// could not be set during module creation. + void setParent(Module *M) { + assert(!Parent); + Parent = M; + Parent->SubModuleIndex[Name] = Parent->SubModules.size(); + Parent->SubModules.push_back(this); + } + /// \brief Retrieve the full name of this module, including the path from /// its top-level module. - std::string getFullModuleName() const; + /// \param AllowStringLiterals If \c true, components that might not be + /// lexically valid as identifiers will be emitted as string literals. + std::string getFullModuleName(bool AllowStringLiterals = false) const; /// \brief Whether the full name of this module is equal to joining /// \p nameParts with "."s. diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h index 78fc899882..8dc259c7ab 100644 --- a/include/clang/Basic/ObjCRuntime.h +++ b/include/clang/Basic/ObjCRuntime.h @@ -326,6 +326,20 @@ public: } } + /// Are the empty collection symbols available? + bool hasEmptyCollections() const { + switch (getKind()) { + default: + return false; + case MacOSX: + return getVersion() >= VersionTuple(10, 11); + case iOS: + return getVersion() >= VersionTuple(9); + case WatchOS: + return getVersion() >= VersionTuple(2); + } + } + /// \brief Try to parse an Objective-C runtime specification from the given /// string. /// diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index 74ec26f19a..3fedaf71dc 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -168,6 +168,9 @@ #ifndef OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE #define OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name) #endif +#ifndef OPENMP_TASKGROUP_CLAUSE +#define OPENMP_TASKGROUP_CLAUSE(Name) +#endif // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) @@ -270,6 +273,8 @@ OPENMP_CLAUSE(to, OMPToClause) OPENMP_CLAUSE(from, OMPFromClause) OPENMP_CLAUSE(use_device_ptr, OMPUseDevicePtrClause) OPENMP_CLAUSE(is_device_ptr, OMPIsDevicePtrClause) +OPENMP_CLAUSE(task_reduction, OMPTaskReductionClause) +OPENMP_CLAUSE(in_reduction, OMPInReductionClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -430,6 +435,7 @@ OPENMP_TASK_CLAUSE(untied) OPENMP_TASK_CLAUSE(mergeable) OPENMP_TASK_CLAUSE(depend) OPENMP_TASK_CLAUSE(priority) +OPENMP_TASK_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'atomic'. OPENMP_ATOMIC_CLAUSE(read) @@ -552,6 +558,8 @@ OPENMP_TASKLOOP_CLAUSE(priority) OPENMP_TASKLOOP_CLAUSE(grainsize) OPENMP_TASKLOOP_CLAUSE(nogroup) OPENMP_TASKLOOP_CLAUSE(num_tasks) +OPENMP_TASKLOOP_CLAUSE(reduction) +OPENMP_TASKLOOP_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'taskloop simd'. OPENMP_TASKLOOP_SIMD_CLAUSE(if) @@ -572,6 +580,8 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen) OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize) OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup) OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks) +OPENMP_TASKLOOP_SIMD_CLAUSE(reduction) +OPENMP_TASKLOOP_SIMD_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'critical'. OPENMP_CRITICAL_CLAUSE(hint) @@ -846,6 +856,10 @@ OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(aligned) OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(safelen) OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(simdlen) +// Clauses allowed for OpenMP directive 'taskgroup'. +OPENMP_TASKGROUP_CLAUSE(task_reduction) + +#undef OPENMP_TASKGROUP_CLAUSE #undef OPENMP_TASKLOOP_SIMD_CLAUSE #undef OPENMP_TASKLOOP_CLAUSE #undef OPENMP_LINEAR_KIND diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index 53ce95cab1..b2f14afe56 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -329,6 +329,15 @@ public: bool hasStorage() const { return DiagStorage != nullptr; } + /// Retrieve the string argument at the given index. + StringRef getStringArg(unsigned I) { + assert(DiagStorage && "No diagnostic storage?"); + assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args"); + assert(DiagStorage->DiagArgumentsKind[I] + == DiagnosticsEngine::ak_std_string && "Not a string arg"); + return DiagStorage->DiagArgumentsStr[I]; + } + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, unsigned I) { PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); diff --git a/include/clang/Basic/SanitizerBlacklist.h b/include/clang/Basic/SanitizerBlacklist.h index e651e18316..1ae5c36eea 100644 --- a/include/clang/Basic/SanitizerBlacklist.h +++ b/include/clang/Basic/SanitizerBlacklist.h @@ -15,29 +15,30 @@ #define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H #include "clang/Basic/LLVM.h" +#include "clang/Basic/SanitizerSpecialCaseList.h" +#include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/SpecialCaseList.h" #include <memory> namespace clang { class SanitizerBlacklist { - std::unique_ptr<llvm::SpecialCaseList> SCL; + std::unique_ptr<SanitizerSpecialCaseList> SSCL; SourceManager &SM; public: SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths, SourceManager &SM); - bool isBlacklistedGlobal(StringRef GlobalName, + bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName, StringRef Category = StringRef()) const; - bool isBlacklistedType(StringRef MangledTypeName, + bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName, StringRef Category = StringRef()) const; - bool isBlacklistedFunction(StringRef FunctionName) const; - bool isBlacklistedFile(StringRef FileName, + bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const; + bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName, StringRef Category = StringRef()) const; - bool isBlacklistedLocation(SourceLocation Loc, + bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc, StringRef Category = StringRef()) const; }; diff --git a/include/clang/Basic/SanitizerSpecialCaseList.h b/include/clang/Basic/SanitizerSpecialCaseList.h new file mode 100644 index 0000000000..e3252022a4 --- /dev/null +++ b/include/clang/Basic/SanitizerSpecialCaseList.h @@ -0,0 +1,54 @@ +//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H +#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SpecialCaseList.h" +#include <memory> + +namespace clang { + +class SanitizerSpecialCaseList : public llvm::SpecialCaseList { +public: + static std::unique_ptr<SanitizerSpecialCaseList> + create(const std::vector<std::string> &Paths, std::string &Error); + + static std::unique_ptr<SanitizerSpecialCaseList> + createOrDie(const std::vector<std::string> &Paths); + + // Query blacklisted entries if any bit in Mask matches the entry's section. + bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, + StringRef Category = StringRef()) const; + +protected: + // Initialize SanitizerSections. + void createSanitizerSections(); + + struct SanitizerSection { + SanitizerSection(SanitizerMask SM, SectionEntries &E) + : Mask(SM), Entries(E){}; + + SanitizerMask Mask; + SectionEntries &Entries; + }; + + std::vector<SanitizerSection> SanitizerSections; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def index c574045e13..d6df617172 100644 --- a/include/clang/Basic/Sanitizers.def +++ b/include/clang/Basic/Sanitizers.def @@ -47,6 +47,12 @@ SANITIZER("kernel-address", KernelAddress) // MemorySanitizer SANITIZER("memory", Memory) +// libFuzzer +SANITIZER("fuzzer", Fuzzer) + +// libFuzzer-required instrumentation, no linking. +SANITIZER("fuzzer-no-link", FuzzerNoLink) + // ThreadSanitizer SANITIZER("thread", Thread) @@ -57,6 +63,7 @@ SANITIZER("leak", Leak) SANITIZER("alignment", Alignment) SANITIZER("array-bounds", ArrayBounds) SANITIZER("bool", Bool) +SANITIZER("builtin", Builtin) SANITIZER("enum", Enum) SANITIZER("float-cast-overflow", FloatCastOverflow) SANITIZER("float-divide-by-zero", FloatDivideByZero) @@ -70,6 +77,7 @@ SANITIZER("nullability-return", NullabilityReturn) SANITIZER_GROUP("nullability", Nullability, NullabilityArg | NullabilityAssign | NullabilityReturn) SANITIZER("object-size", ObjectSize) +SANITIZER("pointer-overflow", PointerOverflow) SANITIZER("return", Return) SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute) SANITIZER("shift-base", ShiftBase) @@ -103,11 +111,12 @@ SANITIZER("safe-stack", SafeStack) // -fsanitize=undefined includes all the sanitizers which have low overhead, no // ABI or address space layout implications, and only catch undefined behavior. SANITIZER_GROUP("undefined", Undefined, - Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow | - FloatDivideByZero | IntegerDivideByZero | NonnullAttribute | - Null | ObjectSize | Return | ReturnsNonnullAttribute | - Shift | SignedIntegerOverflow | Unreachable | VLABound | - Function | Vptr) + Alignment | Bool | Builtin | ArrayBounds | Enum | + FloatCastOverflow | FloatDivideByZero | + IntegerDivideByZero | NonnullAttribute | Null | ObjectSize | + PointerOverflow | Return | ReturnsNonnullAttribute | Shift | + SignedIntegerOverflow | Unreachable | VLABound | Function | + Vptr) // -fsanitize=undefined-trap is an alias for -fsanitize=undefined. SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h index bfa8e516ed..1b936c7d11 100644 --- a/include/clang/Basic/Sanitizers.h +++ b/include/clang/Basic/Sanitizers.h @@ -61,8 +61,8 @@ struct SanitizerSet { Mask = Value ? (Mask | K) : (Mask & ~K); } - /// \brief Disable all sanitizers. - void clear() { Mask = 0; } + /// Disable the sanitizers specified in \p K. + void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } /// \brief Returns true if at least one sanitizer is enabled. bool empty() const { return Mask == 0; } @@ -79,6 +79,12 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); /// this group enables. SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); +/// Return the sanitizers which do not affect preprocessing. +inline SanitizerMask getPPTransparentSanitizers() { + return SanitizerKind::CFI | SanitizerKind::Integer | + SanitizerKind::Nullability | SanitizerKind::Undefined; +} + } // end namespace clang #endif diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 006cf3dc95..7418b50f9d 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -39,10 +39,9 @@ class SourceManager; class FileID { /// \brief A mostly-opaque identifier, where 0 is "invalid", >0 is /// this module, and <-1 is something loaded from another module. - int ID; -public: - FileID() : ID(0) {} + int ID = 0; +public: bool isValid() const { return ID != 0; } bool isInvalid() const { return ID == 0; } @@ -86,17 +85,15 @@ private: /// /// It is important that this type remains small. It is currently 32 bits wide. class SourceLocation { - unsigned ID; + unsigned ID = 0; friend class SourceManager; friend class ASTReader; friend class ASTWriter; enum : unsigned { MacroIDBit = 1U << 31 }; -public: - - SourceLocation() : ID(0) {} +public: bool isFileID() const { return (ID & MacroIDBit) == 0; } bool isMacroID() const { return (ID & MacroIDBit) != 0; } @@ -172,6 +169,11 @@ public: return getFromRawEncoding((unsigned)(uintptr_t)Encoding); } + static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { + return Start.isValid() && Start.isFileID() && End.isValid() && + End.isFileID(); + } + void print(raw_ostream &OS, const SourceManager &SM) const; std::string printToString(const SourceManager &SM) const; void dump(const SourceManager &SM) const; @@ -193,8 +195,9 @@ inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { class SourceRange { SourceLocation B; SourceLocation E; + public: - SourceRange(): B(SourceLocation()), E(SourceLocation()) {} + SourceRange() = default; SourceRange(SourceLocation loc) : B(loc), E(loc) {} SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} @@ -225,9 +228,10 @@ public: /// range. class CharSourceRange { SourceRange Range; - bool IsTokenRange; + bool IsTokenRange = false; + public: - CharSourceRange() : IsTokenRange(false) {} + CharSourceRange() = default; CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} static CharSourceRange getTokenRange(SourceRange R) { @@ -262,18 +266,84 @@ public: bool isInvalid() const { return !isValid(); } }; +/// \brief Represents an unpacked "presumed" location which can be presented +/// to the user. +/// +/// A 'presumed' location can be modified by \#line and GNU line marker +/// directives and is always the expansion point of a normal location. +/// +/// You can get a PresumedLoc from a SourceLocation with SourceManager. +class PresumedLoc { + const char *Filename; + unsigned Line, Col; + SourceLocation IncludeLoc; + +public: + PresumedLoc() : Filename(nullptr) {} + PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) + : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {} + + /// \brief Return true if this object is invalid or uninitialized. + /// + /// This occurs when created with invalid source locations or when walking + /// off the top of a \#include stack. + bool isInvalid() const { return Filename == nullptr; } + bool isValid() const { return Filename != nullptr; } + + /// \brief Return the presumed filename of this location. + /// + /// This can be affected by \#line etc. + const char *getFilename() const { + assert(isValid()); + return Filename; + } + + /// \brief Return the presumed line number of this location. + /// + /// This can be affected by \#line etc. + unsigned getLine() const { + assert(isValid()); + return Line; + } + + /// \brief Return the presumed column number of this location. + /// + /// This cannot be affected by \#line, but is packaged here for convenience. + unsigned getColumn() const { + assert(isValid()); + return Col; + } + + /// \brief Return the presumed include location of this location. + /// + /// This can be affected by GNU linemarker directives. + SourceLocation getIncludeLoc() const { + assert(isValid()); + return IncludeLoc; + } +}; + +class FileEntry; + /// \brief A SourceLocation and its associated SourceManager. /// /// This is useful for argument passing to functions that expect both objects. class FullSourceLoc : public SourceLocation { - const SourceManager *SrcMgr; + const SourceManager *SrcMgr = nullptr; + public: /// \brief Creates a FullSourceLoc where isValid() returns \c false. - explicit FullSourceLoc() : SrcMgr(nullptr) {} + FullSourceLoc() = default; explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} + bool hasManager() const { + bool hasSrcMgr = SrcMgr != nullptr; + assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager"); + return hasSrcMgr; + } + /// \pre This FullSourceLoc has an associated SourceManager. const SourceManager &getManager() const { assert(SrcMgr && "SourceManager is NULL."); @@ -284,6 +354,13 @@ public: FullSourceLoc getExpansionLoc() const; FullSourceLoc getSpellingLoc() const; + FullSourceLoc getFileLoc() const; + std::pair<FullSourceLoc, FullSourceLoc> getImmediateExpansionRange() const; + PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const; + bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const; + FullSourceLoc getImmediateMacroCallerLoc() const; + std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const; + unsigned getFileOffset() const; unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; @@ -293,6 +370,12 @@ public: const char *getCharacterData(bool *Invalid = nullptr) const; + unsigned getLineNumber(bool *Invalid = nullptr) const; + unsigned getColumnNumber(bool *Invalid = nullptr) const; + + std::pair<FullSourceLoc, FullSourceLoc> getExpansionRange() const; + + const FileEntry *getFileEntry() const; /// \brief Return a StringRef to the source buffer data for the /// specified FileID. @@ -321,8 +404,7 @@ public: } /// \brief Comparison function class, useful for sorting FullSourceLocs. - struct BeforeThanCompare : public std::binary_function<FullSourceLoc, - FullSourceLoc, bool> { + struct BeforeThanCompare { bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { return lhs.isBeforeInTranslationUnitThan(rhs); } @@ -346,50 +428,6 @@ public: }; -/// \brief Represents an unpacked "presumed" location which can be presented -/// to the user. -/// -/// A 'presumed' location can be modified by \#line and GNU line marker -/// directives and is always the expansion point of a normal location. -/// -/// You can get a PresumedLoc from a SourceLocation with SourceManager. -class PresumedLoc { - const char *Filename; - unsigned Line, Col; - SourceLocation IncludeLoc; -public: - PresumedLoc() : Filename(nullptr) {} - PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) - : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { - } - - /// \brief Return true if this object is invalid or uninitialized. - /// - /// This occurs when created with invalid source locations or when walking - /// off the top of a \#include stack. - bool isInvalid() const { return Filename == nullptr; } - bool isValid() const { return Filename != nullptr; } - - /// \brief Return the presumed filename of this location. - /// - /// This can be affected by \#line etc. - const char *getFilename() const { assert(isValid()); return Filename; } - - /// \brief Return the presumed line number of this location. - /// - /// This can be affected by \#line etc. - unsigned getLine() const { assert(isValid()); return Line; } - - /// \brief Return the presumed column number of this location. - /// - /// This cannot be affected by \#line, but is packaged here for convenience. - unsigned getColumn() const { assert(isValid()); return Col; } - - /// \brief Return the presumed include location of this location. - /// - /// This can be affected by GNU linemarker directives. - SourceLocation getIncludeLoc() const { assert(isValid()); return IncludeLoc; } -}; } // end namespace clang @@ -422,8 +460,7 @@ namespace llvm { // Teach SmallPtrSet how to handle SourceLocation. template<> - class PointerLikeTypeTraits<clang::SourceLocation> { - public: + struct PointerLikeTypeTraits<clang::SourceLocation> { static inline void *getAsVoidPointer(clang::SourceLocation L) { return L.getPtrEncoding(); } diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index c8fe2ab90c..16bd5616a6 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -80,9 +80,19 @@ namespace SrcMgr { /// system_header is seen or in various other cases. /// enum CharacteristicKind { - C_User, C_System, C_ExternCSystem + C_User, C_System, C_ExternCSystem, C_User_ModuleMap, C_System_ModuleMap }; + /// Determine whether a file / directory characteristic is for system code. + inline bool isSystem(CharacteristicKind CK) { + return CK != C_User && CK != C_User_ModuleMap; + } + + /// Determine whether a file characteristic is for a module map. + inline bool isModuleMap(CharacteristicKind CK) { + return CK == C_User_ModuleMap || CK == C_System_ModuleMap; + } + /// \brief One instance of this struct is kept for every file loaded or used. /// /// This object owns the MemoryBuffer object. @@ -202,12 +212,6 @@ namespace SrcMgr { /// this content cache. This is used for performance analysis. llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const; - void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) { - assert(!Buffer.getPointer() && "MemoryBuffer already set."); - Buffer.setPointer(B.release()); - Buffer.setInt(0); - } - /// \brief Get the underlying buffer, returning NULL if the buffer is not /// yet available. llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); } @@ -251,12 +255,14 @@ namespace SrcMgr { /// preprocessing of this \#include, including this SLocEntry. /// /// Zero means the preprocessor didn't provide such info for this SLocEntry. - unsigned NumCreatedFIDs; + unsigned NumCreatedFIDs : 31; - /// \brief Contains the ContentCache* and the bits indicating the - /// characteristic of the file and whether it has \#line info, all - /// bitmangled together. - uintptr_t Data; + /// \brief Whether this FileInfo has any \#line directives. + unsigned HasLineDirectives : 1; + + /// \brief The content cache and the characteristic of the file. + llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind> + ContentAndKind; friend class clang::SourceManager; friend class clang::ASTWriter; @@ -269,10 +275,9 @@ namespace SrcMgr { FileInfo X; X.IncludeLoc = IL.getRawEncoding(); X.NumCreatedFIDs = 0; - X.Data = (uintptr_t)Con; - assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); - assert((unsigned)FileCharacter < 4 && "invalid file character"); - X.Data |= (unsigned)FileCharacter; + X.HasLineDirectives = false; + X.ContentAndKind.setPointer(Con); + X.ContentAndKind.setInt(FileCharacter); return X; } @@ -280,22 +285,22 @@ namespace SrcMgr { return SourceLocation::getFromRawEncoding(IncludeLoc); } - const ContentCache* getContentCache() const { - return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7)); + const ContentCache *getContentCache() const { + return ContentAndKind.getPointer(); } /// \brief Return whether this is a system header or not. CharacteristicKind getFileCharacteristic() const { - return (CharacteristicKind)(Data & 3); + return ContentAndKind.getInt(); } /// \brief Return true if this FileID has \#line directives in it. - bool hasLineDirectives() const { return (Data & 4) != 0; } + bool hasLineDirectives() const { return HasLineDirectives; } /// \brief Set the flag that indicates that this FileID has /// line table entries associated with it. void setHasLineDirectives() { - Data |= 4; + HasLineDirectives = true; } }; @@ -407,6 +412,8 @@ namespace SrcMgr { }; public: + SLocEntry() : Offset(), IsExpansion(), File() {} + unsigned getOffset() const { return Offset; } bool isExpansion() const { return IsExpansion; } @@ -722,6 +729,10 @@ public: void clearIDTables(); + /// Initialize this source manager suitably to replay the compilation + /// described by \p Old. Requires that \p Old outlive \p *this. + void initializeForReplay(const SourceManager &Old); + DiagnosticsEngine &getDiagnostics() const { return Diag; } FileManager &getFileManager() const { return FileMgr; } @@ -785,9 +796,8 @@ public: FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID = 0, unsigned LoadedOffset = 0) { - const SrcMgr::ContentCache * - IR = getOrCreateContentCache(SourceFile, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + const SrcMgr::ContentCache *IR = + getOrCreateContentCache(SourceFile, isSystem(FileCharacter)); assert(IR && "getOrCreateContentCache() cannot return NULL"); return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); } @@ -800,7 +810,22 @@ public: SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { - return createFileID(createMemBufferContentCache(std::move(Buffer)), + return createFileID( + createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false), + IncludeLoc, FileCharacter, LoadedID, LoadedOffset); + } + + enum UnownedTag { Unowned }; + + /// \brief Create a new FileID that represents the specified memory buffer. + /// + /// This does no caching of the buffer and takes ownership of the + /// MemoryBuffer, so only pass a MemoryBuffer to this once. + FileID createFileID(UnownedTag, llvm::MemoryBuffer *Buffer, + SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, + int LoadedID = 0, unsigned LoadedOffset = 0, + SourceLocation IncludeLoc = SourceLocation()) { + return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true), IncludeLoc, FileCharacter, LoadedID, LoadedOffset); } @@ -865,7 +890,7 @@ public: const FileEntry *NewFile); /// \brief Returns true if the file contents have been overridden. - bool isFileOverridden(const FileEntry *File) { + bool isFileOverridden(const FileEntry *File) const { if (OverriddenFilesInfo) { if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File)) return true; @@ -1356,7 +1381,7 @@ public: /// \brief Returns if a SourceLocation is in a system header. bool isInSystemHeader(SourceLocation Loc) const { - return getFileCharacteristic(Loc) != SrcMgr::C_User; + return isSystem(getFileCharacteristic(Loc)); } /// \brief Returns if a SourceLocation is in an "extern C" system header. @@ -1399,10 +1424,9 @@ public: /// specified by Loc. /// /// If FilenameID is -1, it is considered to be unspecified. - void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, bool IsFileEntry, bool IsFileExit, - bool IsSystemHeader, bool IsExternCHeader); + SrcMgr::CharacteristicKind FileKind); /// \brief Determine if the source manager has a line table. bool hasLineTable() const { return LineTable != nullptr; } @@ -1474,6 +1498,17 @@ public: /// \returns true if LHS source location comes before RHS, false otherwise. bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; + /// \brief Determines whether the two decomposed source location is in the + /// same translation unit. As a byproduct, it also calculates the order + /// of the source locations in case they are in the same TU. + /// + /// \returns Pair of bools the first component is true if the two locations + /// are in the same TU. The second bool is true if the first is true + /// and \p LOffs is before \p ROffs. + std::pair<bool, bool> + isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs, + std::pair<FileID, unsigned> &ROffs) const; + /// \brief Determines the order of 2 source locations in the "source location /// address space". bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const { @@ -1494,6 +1529,14 @@ public: return LHSLoaded; } + /// Return true if the Point is within Start and End. + bool isPointWithin(SourceLocation Location, SourceLocation Start, + SourceLocation End) const { + return Location == Start || Location == End || + (isBeforeInTranslationUnit(Start, Location) && + isBeforeInTranslationUnit(Location, End)); + } + // Iterators over FileInfos. typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> ::const_iterator fileinfo_iterator; @@ -1665,7 +1708,7 @@ private: /// \brief Create a new ContentCache for the specified memory buffer. const SrcMgr::ContentCache * - createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf); + createMemBufferContentCache(llvm::MemoryBuffer *Buf, bool DoNotFree); FileID getFileIDSlow(unsigned SLocOffset) const; FileID getFileIDLocal(unsigned SLocOffset) const; diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h index e65c97b003..9403dea888 100644 --- a/include/clang/Basic/SourceManagerInternals.h +++ b/include/clang/Basic/SourceManagerInternals.h @@ -102,8 +102,6 @@ public: unsigned getNumFilenames() const { return FilenamesByID.size(); } void AddLineNote(FileID FID, unsigned Offset, - unsigned LineNo, int FilenameID); - void AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, int FilenameID, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind); diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 33952f83ff..377534baab 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -52,6 +52,7 @@ namespace clang { TST_int, TST_int128, TST_half, // OpenCL half, ARM NEON __fp16 + TST_Float16, // C11 extension ISO/IEC TS 18661-3 TST_float, TST_double, TST_float128, @@ -236,7 +237,7 @@ namespace clang { CC_X86ThisCall, // __attribute__((thiscall)) CC_X86VectorCall, // __attribute__((vectorcall)) CC_X86Pascal, // __attribute__((pascal)) - CC_X86_64Win64, // __attribute__((ms_abi)) + CC_Win64, // __attribute__((ms_abi)) CC_X86_64SysV, // __attribute__((sysv_abi)) CC_X86RegCall, // __attribute__((regcall)) CC_AAPCS, // __attribute__((pcs("aapcs"))) diff --git a/include/clang/Basic/SyncScope.h b/include/clang/Basic/SyncScope.h new file mode 100644 index 0000000000..09ac005218 --- /dev/null +++ b/include/clang/Basic/SyncScope.h @@ -0,0 +1,154 @@ +//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides definitions for the atomic synchronization scopes. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H +#define LLVM_CLANG_BASIC_SYNCSCOPE_H + +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <memory> + +namespace clang { + +/// \brief Defines synch scope values used internally by clang. +/// +/// The enum values start from 0 and are contiguous. They are mainly used for +/// enumerating all supported synch scope values and mapping them to LLVM +/// synch scopes. Their numerical values may be different from the corresponding +/// synch scope enums used in source languages. +/// +/// In atomic builtin and expressions, language-specific synch scope enums are +/// used. Currently only OpenCL memory scope enums are supported and assumed +/// to be used by all languages. However, in the future, other languages may +/// define their own set of synch scope enums. The language-specific synch scope +/// values are represented by class AtomicScopeModel and its derived classes. +/// +/// To add a new enum value: +/// Add the enum value to enum class SyncScope. +/// Update enum value Last if necessary. +/// Update getAsString. +/// +enum class SyncScope { + OpenCLWorkGroup, + OpenCLDevice, + OpenCLAllSVMDevices, + OpenCLSubGroup, + Last = OpenCLSubGroup +}; + +inline llvm::StringRef getAsString(SyncScope S) { + switch (S) { + case SyncScope::OpenCLWorkGroup: + return "opencl_workgroup"; + case SyncScope::OpenCLDevice: + return "opencl_device"; + case SyncScope::OpenCLAllSVMDevices: + return "opencl_allsvmdevices"; + case SyncScope::OpenCLSubGroup: + return "opencl_subgroup"; + } + llvm_unreachable("Invalid synch scope"); +} + +/// \brief Defines the kind of atomic scope models. +enum class AtomicScopeModelKind { None, OpenCL }; + +/// \brief Defines the interface for synch scope model. +class AtomicScopeModel { +public: + virtual ~AtomicScopeModel() {} + /// \brief Maps language specific synch scope values to internal + /// SyncScope enum. + virtual SyncScope map(unsigned S) const = 0; + + /// \brief Check if the compile-time constant synch scope value + /// is valid. + virtual bool isValid(unsigned S) const = 0; + + /// \brief Get all possible synch scope values that might be + /// encountered at runtime for the current language. + virtual ArrayRef<unsigned> getRuntimeValues() const = 0; + + /// \brief If atomic builtin function is called with invalid + /// synch scope value at runtime, it will fall back to a valid + /// synch scope value returned by this function. + virtual unsigned getFallBackValue() const = 0; + + /// \brief Create an atomic scope model by AtomicScopeModelKind. + /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. + static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K); +}; + +/// \brief Defines the synch scope model for OpenCL. +class AtomicScopeOpenCLModel : public AtomicScopeModel { +public: + /// The enum values match the pre-defined macros + /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* + /// enums in opencl-c.h. + enum ID { + WorkGroup = 1, + Device = 2, + AllSVMDevices = 3, + SubGroup = 4, + Last = SubGroup + }; + + AtomicScopeOpenCLModel() {} + + SyncScope map(unsigned S) const override { + switch (static_cast<ID>(S)) { + case WorkGroup: + return SyncScope::OpenCLWorkGroup; + case Device: + return SyncScope::OpenCLDevice; + case AllSVMDevices: + return SyncScope::OpenCLAllSVMDevices; + case SubGroup: + return SyncScope::OpenCLSubGroup; + } + llvm_unreachable("Invalid language synch scope value"); + } + + bool isValid(unsigned S) const override { + return S >= static_cast<unsigned>(WorkGroup) && + S <= static_cast<unsigned>(Last); + } + + ArrayRef<unsigned> getRuntimeValues() const override { + static_assert(Last == SubGroup, "Does not include all synch scopes"); + static const unsigned Scopes[] = { + static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device), + static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)}; + return llvm::makeArrayRef(Scopes); + } + + unsigned getFallBackValue() const override { + return static_cast<unsigned>(AllSVMDevices); + } +}; + +inline std::unique_ptr<AtomicScopeModel> +AtomicScopeModel::create(AtomicScopeModelKind K) { + switch (K) { + case AtomicScopeModelKind::None: + return std::unique_ptr<AtomicScopeModel>{}; + case AtomicScopeModelKind::OpenCL: + return llvm::make_unique<AtomicScopeOpenCLModel>(); + } + llvm_unreachable("Invalid atomic scope model kind"); +} +} + +#endif diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h index 5d45e162d9..8f4f5e9a74 100644 --- a/include/clang/Basic/TargetBuiltins.h +++ b/include/clang/Basic/TargetBuiltins.h @@ -150,6 +150,16 @@ namespace clang { }; } + /// \brief Nios2 builtins + namespace Nios2 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsNios2.def" + LastTSBuiltin + }; + } + /// \brief MIPS builtins namespace Mips { enum { diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 46db895489..f80f6b7a6b 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -23,6 +23,7 @@ #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -45,6 +46,7 @@ class MacroBuilder; class QualType; class SourceLocation; class SourceManager; +class Type; namespace Builtin { struct Info; } @@ -84,7 +86,7 @@ protected: *LongDoubleFormat, *Float128Format; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI TheCXXABI; - const LangAS::Map *AddrSpaceMap; + const LangASMap *AddrSpaceMap; mutable StringRef PlatformName; mutable VersionTuple PlatformMinVersion; @@ -154,7 +156,7 @@ public: /// typedef void* __builtin_va_list; VoidPtrBuiltinVaList, - /// __builtin_va_list as defind by the AArch64 ABI + /// __builtin_va_list as defined by the AArch64 ABI /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf AArch64ABIBuiltinVaList, @@ -168,7 +170,7 @@ public: PowerABIBuiltinVaList, /// __builtin_va_list as defined by the x86-64 ABI: - /// http://www.x86-64.org/documentation/abi.pdf + /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf X86_64ABIBuiltinVaList, /// __builtin_va_list as defined by ARM AAPCS ABI @@ -225,6 +227,20 @@ protected: public: IntType getSizeType() const { return SizeType; } + IntType getSignedSizeType() const { + switch (SizeType) { + case UnsignedShort: + return SignedShort; + case UnsignedInt: + return SignedInt; + case UnsignedLong: + return SignedLong; + case UnsignedLongLong: + return SignedLongLong; + default: + llvm_unreachable("Invalid SizeType"); + } + } IntType getIntMaxType() const { return IntMaxType; } IntType getUIntMaxType() const { return getCorrespondingUnsignedType(IntMaxType); @@ -232,6 +248,9 @@ public: IntType getPtrDiffType(unsigned AddrSpace) const { return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace); } + IntType getUnsignedPtrDiffType(unsigned AddrSpace) const { + return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace)); + } IntType getIntPtrType() const { return IntPtrType; } IntType getUIntPtrType() const { return getCorrespondingUnsignedType(IntPtrType); @@ -303,9 +322,7 @@ public: /// \brief Get integer value for null pointer. /// \param AddrSpace address space of pointee in source language. - virtual uint64_t getNullPointerValue(unsigned AddrSpace) const { - return 0; - } + virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; } /// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } @@ -432,6 +449,9 @@ public: /// \brief Return the maximum width lock-free atomic operation which can be /// inlined given the supported features of the given target. unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } + /// \brief Set the maximum inline or promote width lock-free atomic operation + /// for the given target. + virtual void setMaxAtomicWidth() {} /// \brief Returns true if the given target supports lock-free atomic /// operations at the specified width and alignment. virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, @@ -449,21 +469,6 @@ public: /// types for the given target. unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; } - /// Return the alignment (in bits) of the thrown exception object. This is - /// only meaningful for targets that allocate C++ exceptions in a system - /// runtime, such as those using the Itanium C++ ABI. - virtual unsigned getExnObjectAlignment() const { - // Itanium says that an _Unwind_Exception has to be "double-word" - // aligned (and thus the end of it is also so-aligned), meaning 16 - // bytes. Of course, that was written for the actual Itanium, - // which is a 64-bit platform. Classically, the ABI doesn't really - // specify the alignment on other platforms, but in practice - // libUnwind declares the struct with __attribute__((aligned)), so - // we assume that alignment here. (It's generally 16 bytes, but - // some targets overwrite it.) - return getDefaultAlignForAttributeAligned(); - } - /// \brief Return the size of intmax_t and uintmax_t for this target, in bits. unsigned getIntMaxTWidth() const { return getTypeWidth(IntMaxType); @@ -823,8 +828,9 @@ public: /// \brief Set forced language options. /// /// Apply changes to the target information with respect to certain - /// language options which change the target configuration. - virtual void adjust(const LangOptions &Opts); + /// language options which change the target configuration and adjust + /// the language based on the target options where applicable. + virtual void adjust(LangOptions &Opts); /// \brief Adjust target options based on codegen options. virtual void adjustTargetOptions(const CodeGenOptions &CGOpts, @@ -853,6 +859,11 @@ public: return false; } + /// brief Determine whether this TargetInfo supports the given CPU name. + virtual bool isValidCPUName(StringRef Name) const { + return true; + } + /// \brief Use the specified ABI. /// /// \return False on error (invalid ABI name). @@ -875,6 +886,11 @@ public: Features[Name] = Enabled; } + /// \brief Determine whether this TargetInfo supports the given feature. + virtual bool isValidFeatureName(StringRef Feature) const { + return true; + } + /// \brief Perform initialization based on the user configured /// set of features (e.g., +sse4). /// @@ -900,6 +916,10 @@ public: // argument. virtual bool validateCpuSupports(StringRef Name) const { return false; } + // \brief Validate the contents of the __builtin_cpu_is(const char*) + // argument. + virtual bool validateCpuIs(StringRef Name) const { return false; } + // \brief Returns maximal number of args passed in registers. unsigned getRegParmMax() const { assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); @@ -949,8 +969,14 @@ public: return nullptr; } - const LangAS::Map &getAddressSpaceMap() const { - return *AddrSpaceMap; + const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; } + + /// \brief Return an AST address space which can be used opportunistically + /// for constant global memory. It must be possible to convert pointers into + /// this address space to LangAS::Default. If no such address space exists, + /// this may return None, and such optimizations will be disabled. + virtual llvm::Optional<LangAS> getConstantAddressSpace() const { + return LangAS::Default; } /// \brief Retrieve the name of the platform as it is used in the @@ -1027,10 +1053,8 @@ public: return getTargetOpts().SupportedOpenCLOptions; } - /// \brief Get OpenCL image type address space. - virtual LangAS::ID getOpenCLImageAddrSpace() const { - return LangAS::opencl_global; - } + /// \brief Get address space for OpenCL type. + virtual LangAS getOpenCLTypeAddrSpace(const Type *T) const; /// \returns Target specific vtbl ptr address space. virtual unsigned getVtblPtrAddressSpace() const { diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h index 2889cce596..9bb19c7b79 100644 --- a/include/clang/Basic/TargetOptions.h +++ b/include/clang/Basic/TargetOptions.h @@ -18,14 +18,14 @@ #include <string> #include <vector> #include "clang/Basic/OpenCLOptions.h" +#include "llvm/Target/TargetOptions.h" namespace clang { /// \brief Options for controlling the target. class TargetOptions { public: - /// If given, the name of the target triple to compile for. If not given the - /// target will be selected to match the host. + /// The name of the target triple to compile for. std::string Triple; /// When compiling for the device side, contains the triple used to compile @@ -42,7 +42,7 @@ public: std::string ABI; /// The EABI version to use - std::string EABIVersion; + llvm::EABI EABIVersion; /// If given, the version string of the linker in use. std::string LinkerVersion; diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h index aed287b462..ac99ad185f 100644 --- a/include/clang/Basic/TemplateKinds.h +++ b/include/clang/Basic/TemplateKinds.h @@ -26,13 +26,21 @@ enum TemplateNameKind { TNK_Function_template, /// The name refers to a template whose specialization produces a /// type. The template itself could be a class template, template - /// template parameter, or C++0x template alias. + /// template parameter, or template alias. TNK_Type_template, /// The name refers to a variable template whose specialization produces a /// variable. TNK_Var_template, - /// The name refers to a dependent template name. Whether the - /// template name is assumed to refer to a type template or a + /// The name refers to a dependent template name: + /// \code + /// template<typename MetaFun, typename T1, typename T2> struct apply2 { + /// typedef typename MetaFun::template apply<T1, T2>::type type; + /// }; + /// \endcode + /// + /// Here, "apply" is a dependent template name within the typename + /// specifier in the typedef. "apply" is a nested template, and + /// whether the template name is assumed to refer to a type template or a /// function template depends on the context in which the template /// name occurs. TNK_Dependent_template_name diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 104b053a14..9bb7b6a7d6 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -27,8 +27,11 @@ #ifndef CXX11_KEYWORD #define CXX11_KEYWORD(X,Y) KEYWORD(X,KEYCXX11|(Y)) #endif +#ifndef CXX2A_KEYWORD +#define CXX2A_KEYWORD(X,Y) KEYWORD(X,KEYCXX2A|(Y)) +#endif #ifndef CONCEPTS_KEYWORD -#define CONCEPTS_KEYWORD(X) KEYWORD(X,KEYCONCEPTS) +#define CONCEPTS_KEYWORD(X) CXX2A_KEYWORD(X,KEYCONCEPTS) #endif #ifndef MODULES_KEYWORD #define MODULES_KEYWORD(X) KEYWORD(X,KEYMODULES) @@ -142,7 +145,7 @@ TOK(numeric_constant) // 0x123 TOK(char_constant) // 'a' TOK(wide_char_constant) // L'b' -// C++1z Character Constants +// C++17 Character Constants TOK(utf8_char_constant) // u8'a' // C++11 Character Constants @@ -236,6 +239,7 @@ PUNCTUATOR(caretcaret, "^^") // implementation namespace // KEYNOCXX - This is a keyword in every non-C++ dialect. // KEYCXX11 - This is a C++ keyword introduced to C++ in C++11 +// KEYCXX2A - This is a C++ keyword introduced to C++ in C++2a // KEYCONCEPTS - This is a keyword if the C++ extensions for concepts // are enabled. // KEYMODULES - This is a keyword if the C++ extensions for modules @@ -362,7 +366,7 @@ CXX11_KEYWORD(nullptr , 0) CXX11_KEYWORD(static_assert , 0) CXX11_KEYWORD(thread_local , 0) -// C++ concepts TS keywords +// C++2a / concepts TS keywords CONCEPTS_KEYWORD(concept) CONCEPTS_KEYWORD(requires) @@ -375,6 +379,9 @@ KEYWORD(co_yield , KEYCOROUTINES) MODULES_KEYWORD(module) MODULES_KEYWORD(import) +// C11 Extension +KEYWORD(_Float16 , KEYALL) + // GNU Extensions (in impl-reserved namespace) KEYWORD(_Decimal32 , KEYALL) KEYWORD(_Decimal64 , KEYALL) @@ -411,6 +418,7 @@ TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) // MSVC12.0 / VS2013 Type Traits TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) +TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX) TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS) TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX) TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX) @@ -432,13 +440,13 @@ TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX) TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX) TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX) TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX) +TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX) TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX) TYPE_TRAIT_1(__is_class, IsClass, KEYCXX) TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX) TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX) TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX) TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX) -// Tentative name - there's no implementation of std::is_literal_type yet. TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX) // Name for GCC 4.6 compatibility - people have already written libraries using // this name unfortunately. @@ -447,6 +455,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX) TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX) TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX) TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) +TYPE_TRAIT_1(__has_unique_object_representations, + HasUniqueObjectRepresentations, KEYCXX) // Clang-only C++ Type Traits TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) @@ -787,6 +797,11 @@ ANNOTATION(pragma_openmp_end) // handles #pragma loop ... directives. ANNOTATION(pragma_loop_hint) +ANNOTATION(pragma_fp) + +// Annotation for the attribute pragma directives - #pragma clang attribute ... +ANNOTATION(pragma_attribute) + // Annotations for module import translated from #include etc. ANNOTATION(module_include) ANNOTATION(module_begin) @@ -804,6 +819,7 @@ ANNOTATION(module_end) #undef TYPE_TRAIT_1 #undef TYPE_TRAIT #undef CONCEPTS_KEYWORD +#undef CXX2A_KEYWORD #undef CXX11_KEYWORD #undef KEYWORD #undef PUNCTUATOR diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 730ecba3d4..8ecd63f9c3 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -31,6 +31,7 @@ namespace clang { UTT_HasTrivialDestructor, UTT_HasVirtualDestructor, UTT_IsAbstract, + UTT_IsAggregate, UTT_IsArithmetic, UTT_IsArray, UTT_IsClass, @@ -64,11 +65,13 @@ namespace clang { UTT_IsStandardLayout, UTT_IsTrivial, UTT_IsTriviallyCopyable, + UTT_IsTriviallyDestructible, UTT_IsUnion, UTT_IsUnsigned, UTT_IsVoid, UTT_IsVolatile, - UTT_Last = UTT_IsVolatile, + UTT_HasUniqueObjectRepresentations, + UTT_Last = UTT_HasUniqueObjectRepresentations, BTT_IsBaseOf, BTT_IsConvertible, BTT_IsConvertibleTo, diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h index 6ac52ed6b5..cc839d789e 100644 --- a/include/clang/Basic/Visibility.h +++ b/include/clang/Basic/Visibility.h @@ -75,6 +75,9 @@ public: static LinkageInfo none() { return LinkageInfo(NoLinkage, DefaultVisibility, false); } + static LinkageInfo visible_none() { + return LinkageInfo(VisibleNoLinkage, DefaultVisibility, false); + } Linkage getLinkage() const { return (Linkage)linkage_; } Visibility getVisibility() const { return (Visibility)visibility_; } diff --git a/include/clang/Basic/XRayLists.h b/include/clang/Basic/XRayLists.h new file mode 100644 index 0000000000..8cfea70e28 --- /dev/null +++ b/include/clang/Basic/XRayLists.h @@ -0,0 +1,55 @@ +//===--- XRayLists.h - XRay automatic attribution ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// User-provided filters for always/never XRay instrumenting certain functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_XRAYLISTS_H +#define LLVM_CLANG_BASIC_XRAYLISTS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SpecialCaseList.h" +#include <memory> + +namespace clang { + +class XRayFunctionFilter { + std::unique_ptr<llvm::SpecialCaseList> AlwaysInstrument; + std::unique_ptr<llvm::SpecialCaseList> NeverInstrument; + SourceManager &SM; + +public: + XRayFunctionFilter(ArrayRef<std::string> AlwaysInstrumentPaths, + ArrayRef<std::string> NeverInstrumentPaths, + SourceManager &SM); + + enum class ImbueAttribute { + NONE, + ALWAYS, + NEVER, + ALWAYS_ARG1, + }; + + ImbueAttribute shouldImbueFunction(StringRef FunctionName) const; + + ImbueAttribute + shouldImbueFunctionsInFile(StringRef Filename, + StringRef Category = StringRef()) const; + + ImbueAttribute shouldImbueLocation(SourceLocation Loc, + StringRef Category = StringRef()) const; +}; + +} // namespace clang + +#endif diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index 2703f299d2..d1f05124d5 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -461,7 +461,7 @@ class CGFunctionInfo final unsigned EffectiveCallingConvention : 8; /// The clang::CallingConv that this was originally created with. - unsigned ASTCallingConvention : 8; + unsigned ASTCallingConvention : 7; /// Whether this is an instance method. unsigned InstanceMethod : 1; @@ -475,6 +475,9 @@ class CGFunctionInfo final /// Whether this function is returns-retained. unsigned ReturnsRetained : 1; + /// Whether this function saved caller registers. + unsigned NoCallerSavedRegs : 1; + /// How many arguments to pass inreg. unsigned HasRegParm : 1; unsigned RegParm : 3; @@ -560,6 +563,9 @@ public: /// is not always reliable for call sites. bool isReturnsRetained() const { return ReturnsRetained; } + /// Whether this function no longer saves caller registers. + bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; } + /// getASTCallingConvention() - Return the AST-specified calling /// convention. CallingConv getASTCallingConvention() const { @@ -583,10 +589,9 @@ public: unsigned getRegParm() const { return RegParm; } FunctionType::ExtInfo getExtInfo() const { - return FunctionType::ExtInfo(isNoReturn(), - getHasRegParm(), getRegParm(), - getASTCallingConvention(), - isReturnsRetained()); + return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), + getASTCallingConvention(), isReturnsRetained(), + isNoCallerSavedRegs()); } CanQualType getReturnType() const { return getArgsBuffer()[0].type; } @@ -623,6 +628,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); + ID.AddBoolean(NoCallerSavedRegs); ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); ID.AddInteger(Required.getOpaqueData()); @@ -648,6 +654,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); + ID.AddBoolean(info.getNoCallerSavedRegs()); ID.AddBoolean(info.getHasRegParm()); ID.AddInteger(info.getRegParm()); ID.AddInteger(required.getOpaqueData()); diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h index e7b7435968..53619fa8ef 100644 --- a/include/clang/CodeGen/CodeGenABITypes.h +++ b/include/clang/CodeGen/CodeGenABITypes.h @@ -16,7 +16,7 @@ // // It allows other clients, like LLDB, to determine the LLVM types that are // actually used in function calls, which makes it possible to then determine -// the acutal ABI locations (e.g. registers, stack locations, etc.) that +// the actual ABI locations (e.g. registers, stack locations, etc.) that // these parameters are stored in. // //===----------------------------------------------------------------------===// @@ -31,6 +31,8 @@ namespace llvm { class DataLayout; class Module; + class FunctionType; + class Type; } namespace clang { @@ -70,6 +72,19 @@ const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM, FunctionType::ExtInfo info, RequiredArgs args); +/// Returns null if the function type is incomplete and can't be lowered. +llvm::FunctionType *convertFreeFunctionType(CodeGenModule &CGM, + const FunctionDecl *FD); + +llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); + +/// Given a non-bitfield struct field, return its index within the elements of +/// the struct's converted type. The returned index refers to a field number in +/// the complete object type which is returned by convertTypeForMemory. FD must +/// be a field in RD directly (i.e. not an inherited field). +unsigned getLLVMFieldNumber(CodeGenModule &CGM, + const RecordDecl *RD, const FieldDecl *FD); + } // end namespace CodeGen } // end namespace clang diff --git a/include/clang/CodeGen/ConstantInitFuture.h b/include/clang/CodeGen/ConstantInitFuture.h index ef1a5d2f49..f1a7e2264f 100644 --- a/include/clang/CodeGen/ConstantInitFuture.h +++ b/include/clang/CodeGen/ConstantInitFuture.h @@ -31,8 +31,7 @@ class ConstantInitBuilderBase; } namespace llvm { template <> -class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> { -public: +struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> { using T = ::clang::CodeGen::ConstantInitBuilderBase*; static inline void *getAsVoidPointer(T p) { return p; } @@ -93,8 +92,7 @@ public: namespace llvm { template <> -class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> { -public: +struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> { using T = ::clang::CodeGen::ConstantInitFuture; static inline void *getAsVoidPointer(T future) { diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h index 6f81ea9d63..e110f6fd30 100644 --- a/include/clang/CodeGen/ModuleBuilder.h +++ b/include/clang/CodeGen/ModuleBuilder.h @@ -84,6 +84,10 @@ public: /// code generator will schedule the entity for emission if a /// definition has been registered with this code generator. llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition); + + /// Create a new \c llvm::Module after calling HandleTranslationUnit. This + /// enable codegen in interactive processing environments. + llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C); }; /// CreateLLVMCodeGen - Create a CodeGenerator instance. diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake index 55f0ca94de..10074aafd8 100644 --- a/include/clang/Config/config.h.cmake +++ b/include/clang/Config/config.h.cmake @@ -20,6 +20,9 @@ /* Default OpenMP runtime used by -fopenmp. */ #define CLANG_DEFAULT_OPENMP_RUNTIME "${CLANG_DEFAULT_OPENMP_RUNTIME}" +/* Default architecture for OpenMP offloading to Nvidia GPUs. */ +#define CLANG_OPENMP_NVPTX_DEFAULT_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}" + /* Multilib suffix for libdir. */ #define CLANG_LIBDIR_SUFFIX "${CLANG_LIBDIR_SUFFIX}" @@ -38,6 +41,9 @@ /* Define if we have libxml2 */ #cmakedefine CLANG_HAVE_LIBXML ${CLANG_HAVE_LIBXML} +/* Define if we have z3 and want to build it */ +#cmakedefine CLANG_ANALYZER_WITH_Z3 ${CLANG_ANALYZER_WITH_Z3} + /* Define if we have sys/resource.h (rlimits) */ #cmakedefine CLANG_HAVE_RLIMITS ${CLANG_HAVE_RLIMITS} @@ -53,4 +59,9 @@ /* enable x86 relax relocations by default */ #cmakedefine01 ENABLE_X86_RELAX_RELOCATIONS +/* Enable each functionality of modules */ +#cmakedefine01 CLANG_ENABLE_ARCMT +#cmakedefine01 CLANG_ENABLE_OBJC_REWRITER +#cmakedefine01 CLANG_ENABLE_STATIC_ANALYZER + #endif diff --git a/include/clang/CrossTU/CrossTUDiagnostic.h b/include/clang/CrossTU/CrossTUDiagnostic.h new file mode 100644 index 0000000000..dad38309fd --- /dev/null +++ b/include/clang/CrossTU/CrossTUDiagnostic.h @@ -0,0 +1,29 @@ +//===--- CrossTUDiagnostic.h - Diagnostics for Cross TU ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CROSSTU_CROSSTUDIAGNOSTIC_H +#define LLVM_CLANG_CROSSTU_CROSSTUDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { +namespace diag { +enum { +#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY) \ + ENUM, +#define CROSSTUSTART +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#undef DIAG + NUM_BUILTIN_CROSSTU_DIAGNOSTICS +}; +} // end namespace diag +} // end namespace clang + +#endif // LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H diff --git a/include/clang/CrossTU/CrossTranslationUnit.h b/include/clang/CrossTU/CrossTranslationUnit.h new file mode 100644 index 0000000000..f2a1690250 --- /dev/null +++ b/include/clang/CrossTU/CrossTranslationUnit.h @@ -0,0 +1,159 @@ +//===--- CrossTranslationUnit.h - -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an interface to load binary AST dumps on demand. This +// feature can be utilized for tools that require cross translation unit +// support. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H +#define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Error.h" + +namespace clang { +class CompilerInstance; +class ASTContext; +class ASTImporter; +class ASTUnit; +class DeclContext; +class FunctionDecl; +class NamedDecl; +class TranslationUnitDecl; + +namespace cross_tu { + +enum class index_error_code { + unspecified = 1, + missing_index_file, + invalid_index_format, + multiple_definitions, + missing_definition, + failed_import, + failed_to_get_external_ast, + failed_to_generate_usr +}; + +class IndexError : public llvm::ErrorInfo<IndexError> { +public: + static char ID; + IndexError(index_error_code C) : Code(C), LineNo(0) {} + IndexError(index_error_code C, std::string FileName, int LineNo = 0) + : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {} + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + index_error_code getCode() const { return Code; } + int getLineNum() const { return LineNo; } + std::string getFileName() const { return FileName; } + +private: + index_error_code Code; + std::string FileName; + int LineNo; +}; + +/// \brief This function parses an index file that determines which +/// translation unit contains which definition. +/// +/// The index file format is the following: +/// each line consists of an USR and a filepath separated by a space. +/// +/// \return Returns a map where the USR is the key and the filepath is the value +/// or an error. +llvm::Expected<llvm::StringMap<std::string>> +parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir); + +std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index); + +/// \brief This class is used for tools that requires cross translation +/// unit capability. +/// +/// This class can load function definitions from external AST files. +/// The loaded definition will be merged back to the original AST using the +/// AST Importer. +/// In order to use this class, an index file is required that describes +/// the locations of the AST files for each function definition. +/// +/// Note that this class also implements caching. +class CrossTranslationUnitContext { +public: + CrossTranslationUnitContext(CompilerInstance &CI); + ~CrossTranslationUnitContext(); + + /// \brief This function loads a function definition from an external AST + /// file and merge it into the original AST. + /// + /// This method should only be used on functions that have no definitions in + /// the current translation unit. A function definition with the same + /// declaration will be looked up in the index file which should be in the + /// \p CrossTUDir directory, called \p IndexName. In case the declaration is + /// found in the index the corresponding AST file will be loaded and the + /// definition of the function will be merged into the original AST using + /// the AST Importer. + /// + /// \return The declaration with the definition will be returned. + /// If no suitable definition is found in the index file or multiple + /// definitions found error will be returned. + /// + /// Note that the AST files should also be in the \p CrossTUDir. + llvm::Expected<const FunctionDecl *> + getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, + StringRef IndexName); + + /// \brief This function loads a function definition from an external AST + /// file. + /// + /// A function definition with the same declaration will be looked up in the + /// index file which should be in the \p CrossTUDir directory, called + /// \p IndexName. In case the declaration is found in the index the + /// corresponding AST file will be loaded. + /// + /// \return Returns an ASTUnit that contains the definition of the looked up + /// function. + /// + /// Note that the AST files should also be in the \p CrossTUDir. + llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName, + StringRef CrossTUDir, + StringRef IndexName); + + /// \brief This function merges a definition from a separate AST Unit into + /// the current one which was created by the compiler instance that + /// was passed to the constructor. + /// + /// \return Returns the resulting definition or an error. + llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD); + + /// \brief Get a name to identify a function. + static std::string getLookupName(const NamedDecl *ND); + + /// \brief Emit diagnostics for the user for potential configuration errors. + void emitCrossTUDiagnostics(const IndexError &IE); + +private: + ASTImporter &getOrCreateASTImporter(ASTContext &From); + const FunctionDecl *findFunctionInDeclContext(const DeclContext *DC, + StringRef LookupFnName); + + llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap; + llvm::StringMap<clang::ASTUnit *> FunctionASTUnitMap; + llvm::StringMap<std::string> FunctionFileMap; + llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>> + ASTUnitImporterMap; + CompilerInstance &CI; + ASTContext &Context; +}; + +} // namespace cross_tu +} // namespace clang + +#endif // LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index acc76f6aa6..bca51b593a 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -70,7 +70,7 @@ def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-neste def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">; def analyze_function : Separate<["-"], "analyze-function">, - HelpText<"Run analysis on specific function">; + HelpText<"Run analysis on specific function (for C++ include parameters in name)">; def analyze_function_EQ : Joined<["-"], "analyze-function=">, Alias<analyze_function>; def analyzer_eagerly_assume : Flag<["-"], "analyzer-eagerly-assume">, HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; @@ -99,7 +99,19 @@ def analyzer_stats : Flag<["-"], "analyzer-stats">, HelpText<"Print internal analyzer statistics.">; def analyzer_checker : Separate<["-"], "analyzer-checker">, - HelpText<"Choose analyzer checkers to enable">; + HelpText<"Choose analyzer checkers to enable">, + ValuesCode<[{ + const char *Values = + #define GET_CHECKERS + #define CHECKER(FULLNAME, CLASS, DESCFILE, HT, G, H) FULLNAME "," + #include "clang/StaticAnalyzer/Checkers/Checkers.inc" + #undef GET_CHECKERS + #define GET_PACKAGES + #define PACKAGE(FULLNAME, G, D) FULLNAME "," + #include "clang/StaticAnalyzer/Checkers/Checkers.inc" + #undef GET_PACKAGES + ; + }]>; def analyzer_checker_EQ : Joined<["-"], "analyzer-checker=">, Alias<analyzer_checker>; @@ -134,7 +146,6 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">, //===----------------------------------------------------------------------===// let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { - def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; def debug_info_macro : Flag<["-"], "debug-info-macro">, HelpText<"Emit macro debug information">; @@ -144,20 +155,22 @@ def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">, HelpText<"The compilation directory to embed in the debug info.">; def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">, HelpText<"The string to embed in the Dwarf debug flags record.">; +def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">, + HelpText<"DWARF debug sections compression">; +def compress_debug_sections_EQ : Joined<["-"], "compress-debug-sections=">, + HelpText<"DWARF debug sections compression type">; def mno_exec_stack : Flag<["-"], "mnoexecstack">, HelpText<"Mark the file as not needing an executable stack">; def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">, HelpText<"Make assembler warnings fatal">; def mrelax_relocations : Flag<["--"], "mrelax-relocations">, HelpText<"Use relaxable elf relocations">; -def compress_debug_sections : Flag<["-"], "compress-debug-sections">, - HelpText<"Compress DWARF debug sections using zlib">; def msave_temp_labels : Flag<["-"], "msave-temp-labels">, HelpText<"Save temporary labels in the symbol table. " "Note this may change .s semantics and shouldn't generally be used " "on compiler-generated code.">; def mrelocation_model : Separate<["-"], "mrelocation-model">, - HelpText<"The relocation model to use">; + HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">; def fno_math_builtin : Flag<["-"], "fno-math-builtin">, HelpText<"Disable implicit builtin knowledge of math functions">; } @@ -172,6 +185,8 @@ def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">, def disable_lifetimemarkers : Flag<["-"], "disable-lifetime-markers">, HelpText<"Disable lifetime-markers emission even when optimizations are " "enabled">; +def disable_O0_optnone : Flag<["-"], "disable-O0-optnone">, + HelpText<"Disable adding the optnone attribute to functions at O0">; def disable_red_zone : Flag<["-"], "disable-red-zone">, HelpText<"Do not emit code that uses the red zone.">; def dwarf_column_info : Flag<["-"], "dwarf-column-info">, @@ -185,6 +200,12 @@ def arange_sections : Flag<["-"], "arange_sections">, def dwarf_ext_refs : Flag<["-"], "dwarf-ext-refs">, HelpText<"Generate debug info with external references to clang modules" " or precompiled headers">; +def dwarf_explicit_import : Flag<["-"], "dwarf-explicit-import">, + HelpText<"Generate explicit import from anonymous namespace to containing" + " scope">; +def debug_forward_template_params : Flag<["-"], "debug-forward-template-params">, + HelpText<"Emit complete descriptions of template parameters in forward" + " declarations">; def fforbid_guard_variables : Flag<["-"], "fforbid-guard-variables">, HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; def no_implicit_float : Flag<["-"], "no-implicit-float">, @@ -226,7 +247,7 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">, def masm_verbose : Flag<["-"], "masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<["-"], "mcode-model">, - HelpText<"The code model to use">; + HelpText<"The code model to use">, Values<"small,kernel,medium,large">; def mdebug_pass : Separate<["-"], "mdebug-pass">, HelpText<"Enable additional debug output">; def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">, @@ -242,6 +263,8 @@ def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, "precision">; def mfloat_abi : Separate<["-"], "mfloat-abi">, HelpText<"The float ABI to use">; +def mtp : Separate<["-"], "mtp">, + HelpText<"Mode for reading thread pointer">; def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">, HelpText<"Limit float precision to the given value">; def split_stacks : Flag<["-"], "split-stacks">, @@ -265,8 +288,6 @@ def vectorize_loops : Flag<["-"], "vectorize-loops">, HelpText<"Run the Loop vectorization passes">; def vectorize_slp : Flag<["-"], "vectorize-slp">, HelpText<"Run the SLP vectorization passes">; -def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">, - HelpText<"Run the BB vectorization passes">; def dependent_lib : Joined<["--"], "dependent-lib=">, HelpText<"Add dependent library">; def linker_option : Joined<["--"], "linker-option=">, @@ -291,15 +312,27 @@ def fsanitize_coverage_trace_gep def fsanitize_coverage_8bit_counters : Flag<["-"], "fsanitize-coverage-8bit-counters">, HelpText<"Enable frequency counters in sanitizer coverage">; +def fsanitize_coverage_inline_8bit_counters + : Flag<["-"], "fsanitize-coverage-inline-8bit-counters">, + HelpText<"Enable inline 8-bit counters in sanitizer coverage">; +def fsanitize_coverage_pc_table + : Flag<["-"], "fsanitize-coverage-pc-table">, + HelpText<"Create a table of coverage-instrumented PCs">; def fsanitize_coverage_trace_pc : Flag<["-"], "fsanitize-coverage-trace-pc">, HelpText<"Enable PC tracing in sanitizer coverage">; def fsanitize_coverage_trace_pc_guard : Flag<["-"], "fsanitize-coverage-trace-pc-guard">, HelpText<"Enable PC tracing with guard in sanitizer coverage">; +def fsanitize_coverage_no_prune + : Flag<["-"], "fsanitize-coverage-no-prune">, + HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">; +def fsanitize_coverage_stack_depth + : Flag<["-"], "fsanitize-coverage-stack-depth">, + HelpText<"Enable max stack depth tracing">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " - "or none">; + "or none">, Values<"none,clang,llvm">; def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">, HelpText<"Generate instrumented code to collect execution counts into " "<file> (overridden by LLVM_PROFILE_FILE env var)">; @@ -312,6 +345,12 @@ def flto_visibility_public_std: def flto_unit: Flag<["-"], "flto-unit">, HelpText<"Emit IR to support LTO unit features (CFI, whole program vtable opt)">; def fno_lto_unit: Flag<["-"], "fno-lto-unit">; +def fthin_link_bitcode_EQ : Joined<["-"], "fthin-link-bitcode=">, + HelpText<"Write minimized bitcode to <file> for the ThinLTO thin link only">; +def fdebug_pass_manager : Flag<["-"], "fdebug-pass-manager">, + HelpText<"Prints debug information for the new pass manager">; +def fno_debug_pass_manager : Flag<["-"], "fno-debug-pass-manager">, + HelpText<"Disables debug printing for the new pass manager">; //===----------------------------------------------------------------------===// // Dependency Output Options @@ -337,9 +376,9 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">, HelpText<"File for serializing diagnostics in a binary format">; def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">, - HelpText<"Change diagnostic formatting to match IDE and command line tools">; + HelpText<"Change diagnostic formatting to match IDE and command line tools">, Values<"clang,msvc,msvc-fallback,vi">; def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">, - HelpText<"Print diagnostic category">; + HelpText<"Print diagnostic category">, Values<"none,id,name">; def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">, HelpText<"Ignore #line directives when displaying diagnostic locations">; def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">, @@ -354,6 +393,9 @@ def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">, HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">; def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">, HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">; +def fcaret_diagnostics_max_lines : + Separate<["-"], "fcaret-diagnostics-max-lines">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of source lines to show in a caret diagnostic">; def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def verify : Flag<["-"], "verify">, @@ -434,10 +476,14 @@ def fmodules_local_submodule_visibility : Flag<["-"], "fmodules-local-submodule-visibility">, HelpText<"Enforce name visibility rules across submodules of the same " "top-level module.">; -def fmodule_codegen : +def fmodules_codegen : Flag<["-"], "fmodules-codegen">, HelpText<"Generate code for uses of this module that assumes an explicit " "object file will be built for the module">; +def fmodules_debuginfo : + Flag<["-"], "fmodules-debuginfo">, + HelpText<"Generate debug info for types in an object file built from this " + "module and do not generate them elsewhere">; def fmodule_format_EQ : Joined<["-"], "fmodule-format=">, HelpText<"Select the container format for clang modules and PCH. " "Supported options are 'raw' and 'obj'.">; @@ -550,6 +596,9 @@ def find_pch_source_EQ : Joined<["-"], "find-pch-source=">, def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">, HelpText<"Disable inclusion of timestamp in precompiled headers">; +def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">, + HelpText<"Aligned allocation/deallocation functions are unavailable">; + //===----------------------------------------------------------------------===// // Language Options //===----------------------------------------------------------------------===// @@ -567,6 +616,8 @@ def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">, HelpText<"Weakly link in the blocks runtime">; def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">, HelpText<"Assume all functions with C linkage do not unwind">; +def enable_split_dwarf : Flag<["-"], "enable-split-dwarf">, + HelpText<"Use split dwarf/Fission">; def split_dwarf_file : Separate<["-"], "split-dwarf-file">, HelpText<"File name to use for split dwarf debug info output">; def fno_wchar : Flag<["-"], "fno-wchar">, @@ -575,11 +626,11 @@ def fconstant_string_class : Separate<["-"], "fconstant-string-class">, MetaVarName<"<class name>">, HelpText<"Specify the class to use for constant Objective-C string objects.">; def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">, - HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; + HelpText<"Objective-C++ Automatic Reference Counting standard library kind">, Values<"libc++,libstdc++,none">; def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">, HelpText<"The target Objective-C runtime supports ARC weak operations">; def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">, - HelpText<"Objective-C dispatch method to use">; + HelpText<"Objective-C dispatch method to use">, Values<"legacy,non-legacy,mixed">; def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">, HelpText<"disable the default synthesis of Objective-C properties">; def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">, @@ -653,9 +704,17 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">, HelpText<"Allow function arguments and returns of type half">; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, - HelpText<"Set default MS calling convention">; + HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">; def finclude_default_header : Flag<["-"], "finclude-default-header">, HelpText<"Include the default header file for OpenCL">; +def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">, + HelpText<"Preserve 3-component vector type">; +def fwchar_type_EQ : Joined<["-"], "fwchar-type=">, + HelpText<"Select underlying type for wchar_t">, Values<"char,short,int">; +def fsigned_wchar : Flag<["-"], "fsigned-wchar">, + HelpText<"Use a signed type for wchar_t">; +def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">, + HelpText<"Use an unsigned type for wchar_t">; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index 9b6ab3a5ef..aebb36ed0e 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -61,6 +61,14 @@ def _SLASH_Brepro_ : CLFlag<"Brepro-">, def _SLASH_C : CLFlag<"C">, HelpText<"Don't discard comments when preprocessing">, Alias<C>; def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>; +def _SLASH_d1reportAllClassLayout : CLFlag<"d1reportAllClassLayout">, + HelpText<"Dump record layout information">, Alias<fdump_record_layouts>; +def _SLASH_diagnostics_caret : CLFlag<"diagnostics:caret">, + HelpText<"Enable caret and column diagnostics (on by default)">; +def _SLASH_diagnostics_column : CLFlag<"diagnostics:column">, + HelpText<"Disable caret diagnostics but keep column info">; +def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">, + HelpText<"Disable column and caret diagnostics">; def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">, MetaVarName<"<macro[=value]>">, Alias<D>; def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>; @@ -172,6 +180,12 @@ def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">, HelpText<"Enable trigraphs">, Alias<ftrigraphs>; def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">, HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>; +def _SLASH_Zc_twoPhase : CLFlag<"Zc:twoPhase">, + HelpText<"Enable two-phase name lookup in templates">, + Alias<fno_delayed_template_parsing>; +def _SLASH_Zc_twoPhase_ : CLFlag<"Zc:twoPhase-">, + HelpText<"Disable two-phase name lookup in templates">, + Alias<fdelayed_template_parsing>; def _SLASH_Z7 : CLFlag<"Z7">, HelpText<"Enable CodeView debug information in object files">; def _SLASH_Zd : CLFlag<"Zd">, @@ -316,6 +330,7 @@ def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">; def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">; def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">; def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">; +def _SLASH_Zc_ternary : CLIgnoredFlag<"Zc:ternary">; def _SLASH_Zm : CLIgnoredJoined<"Zm">; def _SLASH_Zo : CLIgnoredFlag<"Zo">; def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">; diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h index 114e0b33c7..89c0def6c5 100644 --- a/include/clang/Driver/Compilation.h +++ b/include/clang/Driver/Compilation.h @@ -99,16 +99,19 @@ class Compilation { /// only be removed if we crash. ArgStringMap FailureResultFiles; - /// Redirection for stdout, stderr, etc. - const StringRef **Redirects; + /// Optional redirection for stdin, stdout, stderr. + std::vector<Optional<StringRef>> Redirects; /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics; + /// Whether an error during the parsing of the input args. + bool ContainsError; + public: Compilation(const Driver &D, const ToolChain &DefaultToolChain, llvm::opt::InputArgList *Args, - llvm::opt::DerivedArgList *TranslatedArgs); + llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError); ~Compilation(); const Driver &getDriver() const { return TheDriver; } @@ -275,14 +278,15 @@ public: /// Return true if we're compiling for diagnostics. bool isForDiagnostics() const { return ForDiagnostics; } + /// Return whether an error during the parsing of the input args. + bool containsError() const { return ContainsError; } + /// Redirect - Redirect output of this compilation. Can only be done once. /// - /// \param Redirects - array of pointers to paths. The array - /// should have a size of three. The inferior process's - /// stdin(0), stdout(1), and stderr(2) will be redirected to the - /// corresponding paths. This compilation instance becomes - /// the owner of Redirects and will delete the array and StringRef's. - void Redirect(const StringRef** Redirects); + /// \param Redirects - array of optional paths. The array should have a size + /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will + /// be redirected to the corresponding paths, if provided (not llvm::None). + void Redirect(ArrayRef<Optional<StringRef>> Redirects); }; } // end namespace driver diff --git a/include/clang/Driver/Distro.h b/include/clang/Driver/Distro.h index e2fb8b6433..eeb4f25f34 100644 --- a/include/clang/Driver/Distro.h +++ b/include/clang/Driver/Distro.h @@ -32,6 +32,7 @@ public: DebianWheezy, DebianJessie, DebianStretch, + DebianBuster, Exherbo, RHEL5, RHEL6, @@ -57,6 +58,8 @@ public: UbuntuXenial, UbuntuYakkety, UbuntuZesty, + UbuntuArtful, + UbuntuBionic, UnknownDistro }; @@ -106,13 +109,13 @@ public: } bool IsDebian() const { - return DistroVal >= DebianLenny && DistroVal <= DebianStretch; + return DistroVal >= DebianLenny && DistroVal <= DebianBuster; } bool IsUbuntu() const { - return DistroVal >= UbuntuHardy && DistroVal <= UbuntuZesty; + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuBionic; } - + /// @} }; diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index e653c7ca95..a3662872a9 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -129,6 +129,9 @@ public: /// The original path to the clang executable. std::string ClangExecutable; + /// Target and driver mode components extracted from clang executable name. + ParsedClangName ClangNameParts; + /// The path to the installed clang directory, if any. std::string InstalledDir; @@ -148,9 +151,6 @@ public: /// Dynamic loader prefix, if present std::string DyldPrefix; - /// If the standard library is used - bool UseStdLib; - /// Driver title to use with help. std::string DriverTitle; @@ -216,6 +216,11 @@ public: /// Use lazy precompiled headers for PCH support. unsigned CCCUsePCH : 1; + /// Force clang to emit reproducer for driver invocation. This is enabled + /// indirectly by setting FORCE_CLANG_DIAGNOSTICS_CRASH environment variable + /// or when using the -gen-reproducer driver flag. + unsigned GenReproducer : 1; + private: /// Certain options suppress the 'no input files' warning. unsigned SuppressMissingInputWarning : 1; @@ -282,6 +287,8 @@ public: void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; } + const std::string &getTitle() { return DriverTitle; } void setTitle(std::string Value) { DriverTitle = std::move(Value); } @@ -336,7 +343,8 @@ public: /// ParseArgStrings - Parse the given list of strings into an /// ArgList. - llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args); + llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args, + bool &ContainsError); /// BuildInputs - Construct the list of inputs and their types from /// the given arguments. @@ -417,6 +425,10 @@ public: // FIXME: This should be in CompilationInfo. std::string GetProgramPath(StringRef Name, const ToolChain &TC) const; + /// handleAutocompletions - Handle --autocomplete by searching and printing + /// possible flags, descriptions, and its arguments. + void handleAutocompletions(StringRef PassedFlags) const; + /// HandleImmediateArgs - Handle any arguments which should be /// treated before building actions or binding tools. /// diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index 54bed09e0a..b74b3b4b35 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_DRIVER_JOB_H #include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator.h" #include "llvm/Option/Option.h" @@ -69,6 +70,9 @@ class Command { /// file std::string ResponseFileFlag; + /// See Command::setEnvironment + std::vector<const char *> Environment; + /// When a response file is needed, we try to put most arguments in an /// exclusive file, while others remains as regular command line arguments. /// This functions fills a vector with the regular command line arguments, @@ -93,8 +97,8 @@ public: virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const; - virtual int Execute(const StringRef **Redirects, std::string *ErrMsg, - bool *ExecutionFailed) const; + virtual int Execute(ArrayRef<Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const; /// getSource - Return the Action which caused the creation of this job. const Action &getSource() const { return Source; } @@ -111,6 +115,12 @@ public: InputFileList = std::move(List); } + /// \brief Sets the environment to be used by the new process. + /// \param NewEnvironment An array of environment variables. + /// \remark If the environment remains unset, then the environment + /// from the parent process will be used. + void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment); + const char *getExecutable() const { return Executable; } const llvm::opt::ArgStringList &getArguments() const { return Arguments; } @@ -131,7 +141,7 @@ public: void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; - int Execute(const StringRef **Redirects, std::string *ErrMsg, + int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override; private: @@ -148,7 +158,7 @@ public: void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; - int Execute(const StringRef **Redirects, std::string *ErrMsg, + int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override; }; diff --git a/include/clang/Driver/Multilib.h b/include/clang/Driver/Multilib.h index 0419186b74..36d2493b1a 100644 --- a/include/clang/Driver/Multilib.h +++ b/include/clang/Driver/Multilib.h @@ -70,13 +70,21 @@ public: /// All elements begin with either '+' or '-' const flags_list &flags() const { return Flags; } flags_list &flags() { return Flags; } + /// Add a flag to the flags list + /// \p Flag must be a flag accepted by the driver with its leading '-' removed, + /// and replaced with either: + /// '-' which contraindicates using this multilib with that flag + /// or: + /// '+' which promotes using this multilib in the presence of that flag + /// otherwise '-print-multi-lib' will not emit them correctly. Multilib &flag(StringRef F) { assert(F.front() == '+' || F.front() == '-'); Flags.push_back(F); return *this; } + LLVM_DUMP_METHOD void dump() const; /// \brief print summary of the Multilib void print(raw_ostream &OS) const; @@ -150,6 +158,7 @@ public: unsigned size() const { return Multilibs.size(); } + LLVM_DUMP_METHOD void dump() const; void print(raw_ostream &OS) const; MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) { diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h index 57e4452f3e..2da3cb4828 100644 --- a/include/clang/Driver/Options.h +++ b/include/clang/Driver/Options.h @@ -39,8 +39,9 @@ enum ClangFlags { enum ID { OPT_INVALID = 0, // This is not an option ID. -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, #include "clang/Driver/Options.inc" LastOption #undef OPTION diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 7952b33fd5..e3476c721a 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -139,6 +139,10 @@ def m_arm_Features_Group : OptionGroup<"<arm features group>">, Group<m_Group>, DocName<"ARM">; def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">, Group<m_Group>, DocName<"Hexagon">; +// The features added by this group will not be added to target features. +// These are explicitly handled. +def m_hexagon_Features_HVX_Group : OptionGroup<"<hexagon features group>">, + Group<m_Group>, DocName<"Hexagon">; def m_ppc_Features_Group : OptionGroup<"<ppc features group>">, Group<m_Group>, DocName<"PowerPC">; def m_wasm_Features_Group : OptionGroup<"<wasm features group>">, @@ -194,6 +198,16 @@ def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">, def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">, Group<m_Group>, Flags<[Ignored]>; +// Group for clang options in the process of deprecation. +// Please include the version that deprecated the flag as comment to allow +// easier garbage collection. +def clang_ignored_legacy_options_Group : OptionGroup<"<clang legacy flags>">, + Group<f_Group>, Flags<[Ignored]>; + +// Retired with clang-5.0 +def : Flag<["-"], "fslp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>; +def : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>; + // Group that ignores all gcc optimizations that won't be implemented def clang_ignored_gcc_optimization_f_Group : OptionGroup< "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>; @@ -265,6 +279,8 @@ def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output"> def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">, HelpText<"Emit ARC errors even if the migrator can fix them">, Flags<[CC1Option]>; +def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt, + HelpText<"Auto-generates preprocessed source files and a reproduction script">; def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>, HelpText<"Run the migrator">; @@ -400,11 +416,11 @@ def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption] def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>, HelpText<"Only run preprocess and compilation steps">; def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>, - MetaVarName<"<addr">, HelpText<"Set starting address of BSS to <addr>">; + MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>, - MetaVarName<"<addr">, HelpText<"Set starting address of BSS to <addr>">; + MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>, - MetaVarName<"<addr">, HelpText<"Set starting address of BSS to <addr>">; + MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>, MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">; def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>, @@ -447,6 +463,10 @@ def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">, HelpText<"Pass <arg> to fatbinary invocation">, MetaVarName<"<arg>">; def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">, HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">; +def Xopenmp_target : Separate<["-"], "Xopenmp-target">, + HelpText<"Pass <arg> to the target offloading toolchain.">, MetaVarName<"<arg>">; +def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">, + HelpText<"Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.">, MetaVarName<"<arg>">; def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>, HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">, Group<Link_Group>; @@ -467,6 +487,7 @@ def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">; def arch : Separate<["-"], "arch">, Flags<[DriverOption]>; def arch__only : Separate<["-"], "arch_only">; def a : Joined<["-"], "a">; +def autocomplete : Joined<["--"], "autocomplete=">; def bind__at__load : Flag<["-"], "bind_at_load">; def bundle__loader : Separate<["-"], "bundle_loader">; def bundle : Flag<["-"], "bundle">; @@ -490,7 +511,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">; def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>, - HelpText<"OpenCL language standard to compile for.">; + HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>, @@ -575,7 +596,9 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]> HelpText<"Use Apple's kernel extensions ABI">; def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable Apple gcc-compatible #pragma pack handling">; -def shared_libasan : Flag<["-"], "shared-libasan">; +def shared_libsan : Flag<["-"], "shared-libsan">; +def static_libsan : Flag<["-"], "static-libsan">; +def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>; def fasm : Flag<["-"], "fasm">, Group<f_Group>; def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>, Flags<[CC1Option]>; @@ -587,6 +610,13 @@ def fastf : Flag<["-"], "fastf">, Group<f_Group>; def fast : Flag<["-"], "fast">, Group<f_Group>; def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>; +def fdouble_square_bracket_attributes : Flag<[ "-" ], "fdouble-square-bracket-attributes">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Enable '[[]]' attributes in all C and C++ language modes">; +def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-double-square-bracket-attributes">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Disable '[[]]' attributes in all C and C++ language modes">; + def fautolink : Flag <["-"], "fautolink">, Group<f_Group>; def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, @@ -613,11 +643,32 @@ def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, HelpText<"Disable GNU style inline asm">; +def fprofile_sample_use : Flag<["-"], "fprofile-sample-use">, Group<f_Group>, + Flags<[CoreOption]>; +def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Group>, + Flags<[CoreOption]>; def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, HelpText<"Enable sample-based profile guided optimizations">; +def fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Specifies that the sample profile is accurate">, + DocBrief<[{Specifies that the sample profile is accurate. If the sample + profile is accurate, callsites without profile samples are marked + as cold. Otherwise, treat callsites without profile samples as if + we have no profile}]>; +def fno_profile_sample_accurate : Flag<["-"], "fno-profile-sample-accurate">, + Group<f_Group>, Flags<[DriverOption]>; +def fauto_profile : Flag<["-"], "fauto-profile">, Group<f_Group>, + Alias<fprofile_sample_use>; +def fno_auto_profile : Flag<["-"], "fno-auto-profile">, Group<f_Group>, + Alias<fno_profile_sample_use>; def fauto_profile_EQ : Joined<["-"], "fauto-profile=">, Alias<fprofile_sample_use_EQ>; +def fauto_profile_accurate : Flag<["-"], "fauto-profile-accurate">, + Group<f_Group>, Alias<fprofile_sample_accurate>; +def fno_auto_profile_accurate : Flag<["-"], "fno-auto-profile-accurate">, + Group<f_Group>, Alias<fno_profile_sample_accurate>; def fdebug_info_for_profiling : Flag<["-"], "fdebug-info-for-profiling">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Emit extra debug info to make sample profile more accurate.">; @@ -673,6 +724,9 @@ def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>; def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>, Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">; def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>; +def fclang_abi_compat_EQ : Joined<["-"], "fclang-abi-compat=">, Group<f_clang_Group>, + Flags<[CC1Option]>, MetaVarName<"<version>">, Values<"<major>.<minor>,latest">, + HelpText<"Attempt to match the ABI of Clang <version>">; def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>; def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">; @@ -693,7 +747,8 @@ def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>; def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>; def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">, Group<f_Group>; -def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>; +def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>, + HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">; def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>; def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>, HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; @@ -711,6 +766,9 @@ def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-sourc HelpText<"Print source range spans in numeric form">; def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">; +def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-threshold=">, + Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">, + HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">; def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">; def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">, @@ -767,106 +825,133 @@ def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>; def fjump_tables : Flag<["-"], "fjump-tables">, Group<f_Group>; def fno_jump_tables : Flag<["-"], "fno-jump-tables">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Do not use jump tables for lowering switches">; + +// Begin sanitizer flags. These should all be core options exposed in all driver +// modes. +let Flags = [CC1Option, CoreOption] in { + def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>, - Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">, + MetaVarName<"<check>">, HelpText<"Turn on runtime checks for various forms of undefined " "or suspicious behavior. See user manual for available checks">; def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>, - Flags<[CoreOption]>; + Flags<[CoreOption, DriverOption]>; def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">, - Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>, + Group<f_clang_Group>, HelpText<"Path to blacklist file for sanitizers">; def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">, Group<f_clang_Group>, HelpText<"Don't use blacklist file for sanitizers">; def fsanitize_coverage : CommaJoined<["-"], "fsanitize-coverage=">, - Group<f_clang_Group>, Flags<[CoreOption]>, + Group<f_clang_Group>, HelpText<"Specify the type of coverage instrumentation for Sanitizers">; def fno_sanitize_coverage : CommaJoined<["-"], "fno-sanitize-coverage=">, - Group<f_clang_Group>, Flags<[CoreOption]>, + Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>, HelpText<"Disable specified features of coverage instrumentation for " - "Sanitizers">; + "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">; def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable origins tracking in MemorySanitizer">; def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable origins tracking in MemorySanitizer">; def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable origins tracking in MemorySanitizer">; def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable use-after-destroy detection in MemorySanitizer">; +def fno_sanitize_memory_use_after_dtor : Flag<["-"], "fno-sanitize-memory-use-after-dtor">, + Group<f_clang_Group>, + HelpText<"Disable use-after-destroy detection in MemorySanitizer">; def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Level of field padding for AddressSanitizer">; def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable use-after-scope detection in AddressSanitizer">; def fno_sanitize_address_use_after_scope : Flag<["-"], "fno-sanitize-address-use-after-scope">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable use-after-scope detection in AddressSanitizer">; -def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>, - Flags<[CoreOption]>; +def fsanitize_address_globals_dead_stripping : Flag<["-"], "fsanitize-address-globals-dead-stripping">, + Group<f_clang_Group>, + HelpText<"Enable linker dead stripping of globals in AddressSanitizer">; +def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>; def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, - Group<f_clang_Group>, Flags<[CoreOption]>; + Flags<[CoreOption, DriverOption]>, + Group<f_clang_Group>; def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">, Group<f_clang_Group>, - Flags<[CC1Option, CoreOption]>, HelpText<"Enable recovery for specified sanitizers">; def fno_sanitize_recover_EQ : CommaJoined<["-"], "fno-sanitize-recover=">, - Group<f_clang_Group>, Flags<[CoreOption]>, + Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable recovery for specified sanitizers">; def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>, - Flags<[CC1Option, CoreOption]>, HelpText<"Enable trapping for specified sanitizers">; def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>, - Flags<[CoreOption]>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable trapping for specified sanitizers">; def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, Group<f_clang_Group>; def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group<f_clang_Group>; +def fsanitize_minimal_runtime : Flag<["-"], "fsanitize-minimal-runtime">, + Group<f_clang_Group>; +def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">, + Group<f_clang_Group>; def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">, Group<f_clang_Group>; def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">; def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Flags<[CoreOption, DriverOption]>, + Group<f_clang_Group>, HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">; +def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-generalize-pointers">, + Group<f_clang_Group>, + HelpText<"Generalize pointers in CFI indirect call type signature checks">; def fsanitize_stats : Flag<["-"], "fsanitize-stats">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, HelpText<"Enable sanitizer statistics gathering.">; def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">, - Group<f_clang_Group>, Flags<[CC1Option]>, + Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable sanitizer statistics gathering.">; def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">, Group<f_clang_Group>, HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">; def fno_sanitize_thread_memory_access : Flag<["-"], "fno-sanitize-thread-memory-access">, Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable memory access instrumentation in ThreadSanitizer">; def fsanitize_thread_func_entry_exit : Flag<["-"], "fsanitize-thread-func-entry-exit">, Group<f_clang_Group>, HelpText<"Enable function entry/exit instrumentation in ThreadSanitizer (default)">; def fno_sanitize_thread_func_entry_exit : Flag<["-"], "fno-sanitize-thread-func-entry-exit">, Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable function entry/exit instrumentation in ThreadSanitizer">; def fsanitize_thread_atomics : Flag<["-"], "fsanitize-thread-atomics">, Group<f_clang_Group>, HelpText<"Enable atomic operations instrumentation in ThreadSanitizer (default)">; def fno_sanitize_thread_atomics : Flag<["-"], "fno-sanitize-thread-atomics">, Group<f_clang_Group>, + Flags<[CoreOption, DriverOption]>, HelpText<"Disable atomic operations instrumentation in ThreadSanitizer">; def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-undefined-strip-path-components=">, - Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">, + Group<f_clang_Group>, MetaVarName<"<number>">, HelpText<"Strip (or keep only, if negative) a given number of path components " "when emitting check metadata.">; + +} // end -f[no-]sanitize* flags + def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">, Group<f_Group>; def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">, @@ -894,7 +979,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>, Flags<[CC1Op def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>, Flags<[CC1Option]>; def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)" - " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">; + " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">; def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>; def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>; @@ -903,6 +988,10 @@ def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>, Flags<[CC1Option]>; def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>; +def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>, + Flags<[CC1Option]>; +def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>; + def frewrite_map_file : Separate<["-"], "frewrite-map-file">, Group<f_Group>, Flags<[ DriverOption, CC1Option ]>; @@ -954,11 +1043,27 @@ def fxray_instruction_threshold_ : JoinedOrSeparate<["-"], "fxray-instruction-threshold">, Group<f_Group>, Flags<[CC1Option]>; +def fxray_always_instrument : + JoinedOrSeparate<["-"], "fxray-always-instrument=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">; +def fxray_never_instrument : + JoinedOrSeparate<["-"], "fxray-never-instrument=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">; + +def ffine_grained_bitfield_accesses : Flag<["-"], + "ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Use separate accesses for bitfields with legal widths and alignments.">; +def fno_fine_grained_bitfield_accesses : Flag<["-"], + "fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Use large-integer access for consecutive bitfield runs.">; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group<f_Group>, - HelpText<"Set LTO mode to either 'full' or 'thin'">; + HelpText<"Set LTO mode to either 'full' or 'thin'">, Values<"thin,full">; def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>, HelpText<"Enable LTO in 'full' mode">; def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>, @@ -1046,8 +1151,8 @@ def fmodule_map_file : Joined<["-"], "fmodule-map-file=">, Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">, HelpText<"Load this module map file">; def fmodule_file : Joined<["-"], "fmodule-file=">, - Group<f_Group>, Flags<[DriverOption,CC1Option]>, - HelpText<"Load this precompiled module file">, MetaVarName<"<file>">; + Group<i_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"[<name>=]<file>">, + HelpText<"Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.">; def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Ignore the definition of the given macro when building and loading modules">; def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>, @@ -1116,7 +1221,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m Group<f_clang_Group>, Flags<[CC1Option]>, HelpText<"Disables an experimental new pass manager in LLVM.">; def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Use the given vector functions library">; + HelpText<"Use the given vector functions library">, Values<"Accelerate,SVML,none">; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>, HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>, @@ -1252,6 +1357,10 @@ def fopenmp_targets_EQ : CommaJoined<["-"], "fopenmp-targets=">, Flags<[DriverOp HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">; def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, + HelpText<"OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.">; +def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, + HelpText<"Do not compile OpenMP target code as relocatable.">; def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>; def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>; def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">; @@ -1294,13 +1403,13 @@ def frtti : Flag<["-"], "frtti">, Group<f_Group>; def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>; def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; -def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>, +def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, HelpText<"Force wchar_t to be a short unsigned int">; -def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1Option]>, +def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, HelpText<"Force wchar_t to be an unsigned int">; def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Which overload candidates to show when overload resolution fails: " - "best|all; defaults to all">; + "best|all; defaults to all">, Values<"best,all">; def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>; def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>; def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>; @@ -1363,9 +1472,6 @@ def : Flag<["-"], "fno-tree-vectorize">, Alias<fno_vectorize>; def fslp_vectorize : Flag<["-"], "fslp-vectorize">, Group<f_Group>, HelpText<"Enable the superword-level parallelism vectorization passes">; def fno_slp_vectorize : Flag<["-"], "fno-slp-vectorize">, Group<f_Group>; -def fslp_vectorize_aggressive : Flag<["-"], "fslp-vectorize-aggressive">, Group<f_Group>, - HelpText<"Enable the BB vectorization passes">; -def fno_slp_vectorize_aggressive : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<f_Group>; def : Flag<["-"], "ftree-slp-vectorize">, Alias<fslp_vectorize>; def : Flag<["-"], "fno-tree-slp-vectorize">, Alias<fno_slp_vectorize>; def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">, @@ -1414,7 +1520,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1 def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>; def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>; def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>, - HelpText<"Set the default symbol visibility for all global declarations">; + HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">; def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>, HelpText<"Give inline C++ member functions default visibility by default">, Flags<[CC1Option]>; @@ -1422,9 +1528,10 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group> HelpText<"Give global types 'default' visibility and global functions and " "variables 'hidden' visibility by default">; def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Group>, - Flags<[CC1Option]>, + Flags<[CoreOption, CC1Option]>, HelpText<"Enables whole-program vtable optimization. Requires -flto">; -def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>; +def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>, + Flags<[CoreOption]>; def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Treat signed integer overflow as two's complement">; def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>, @@ -1453,6 +1560,12 @@ def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>, def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>, Flags<[CC1Option]>; +def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Treat editor placeholders as valid source code">; +def fno_allow_editor_placeholders : Flag<["-"], + "fno-allow-editor-placeholders">, Group<f_Group>; + def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">; def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>, @@ -1510,11 +1623,15 @@ def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>; def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[CoreOption]>; def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>, Flags<[CoreOption]>; def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>; -def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>; +def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>; def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>; def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>, HelpText<"Generate debug info with external references to clang modules" " or precompiled headers">; +def gz : Flag<["-"], "gz">, Group<g_flags_Group>, + HelpText<"DWARF debug sections compression type">; +def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>, + HelpText<"DWARF debug sections compression type">; def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">; def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>, HelpText<"Display available options">; @@ -1579,8 +1696,6 @@ def m16 : Flag<["-"], "m16">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>, HelpText<"Enable hexagon-qdsp6 backward compatibility">; -def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; -def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>; @@ -1599,19 +1714,23 @@ def mexecute_only : Flag<["-"], "mexecute-only">, Group<m_arm_Features_Group>, HelpText<"Disallow generation of data access to code sections (ARM only)">; def mno_execute_only : Flag<["-"], "mno-execute-only">, Group<m_arm_Features_Group>, HelpText<"Allow generation of data access to code sections (ARM only)">; +def mtp_mode_EQ : Joined<["-"], "mtp=">, Group<m_arm_Features_Group>, Values<"soft, cp15">, + HelpText<"Read thread pointer from coprocessor register (ARM only)">; def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for GCC compatibility def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>; def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>; def mappletvos_version_min_EQ : Joined<["-"], "mappletvos-version-min=">, Alias<mtvos_version_min_EQ>; -def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">, Alias<mtvos_version_min_EQ>; -def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_version_min_EQ>; +def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">; +def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_simulator_version_min_EQ>; def mwatchos_version_min_EQ : Joined<["-"], "mwatchos-version-min=">, Group<m_Group>; -def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">, Alias<mwatchos_version_min_EQ>; -def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_version_min_EQ>; +def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">; +def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_simulator_version_min_EQ>; def march_EQ : Joined<["-"], "march=">, Group<m_Group>; def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>; def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>; def mimplicit_it_EQ : Joined<["-"], "mimplicit-it=">, Group<m_Group>; +def mdefault_build_attributes : Joined<["-"], "mdefault-build-attributes">, Group<m_Group>; +def mno_default_build_attributes : Joined<["-"], "mno-default-build-attributes">, Group<m_Group>; def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>; def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>; def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>; @@ -1619,6 +1738,7 @@ def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>; def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>; def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>; def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>; +def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>; def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>; def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>; def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>; @@ -1626,7 +1746,7 @@ def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ig def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>; def malign_double : Flag<["-"], "malign-double">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Align doubles to two words in structs (x86 only)">; -def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>; +def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>, Values<"soft,softfp,hard">; def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>; def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>; def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>; @@ -1636,8 +1756,8 @@ def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>; def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>; def mios_version_min_EQ : Joined<["-"], "mios-version-min=">, Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">; -def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Alias<miphoneos_version_min_EQ>; -def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<miphoneos_version_min_EQ>; +def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">; +def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>; def mkernel : Flag<["-"], "mkernel">, Group<m_Group>; def mlinker_version_EQ : Joined<["-"], "mlinker-version=">, Flags<[DriverOption]>; @@ -1645,6 +1765,8 @@ def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option,CC1AsOption,CoreOption]>, HelpText<"Additional arguments to forward to LLVM's option processing">; def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">, Group<m_Group>, HelpText<"Set Mac OS X deployment target">; +def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, + Group<m_Group>, Alias<mmacosx_version_min_EQ>; def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">; def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>, @@ -1656,17 +1778,13 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set the stack probe size">; def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>, - HelpText<"The thread model to use, e.g. posix, single (posix by default)">; + HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">; def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>, - HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">; + HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">; -def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>; -def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>; -def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>; def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>; def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Disable merging of globals">; -def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>; def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">, Alias<fno_pascal_strings>; def mno_red_zone : Flag<["-"], "mno-red-zone">, Group<m_Group>; @@ -1674,63 +1792,6 @@ def mno_relax_all : Flag<["-"], "mno-relax-all">, Group<m_Group>; def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>; def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>; def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>; -def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>; -def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>; -def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>; -def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>; -def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>; -def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>; -def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>; -// -mno-sse4 turns off sse4.1 which has the effect of turning off everything -// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on -// everything earlier than 4.2. -def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>; -def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>; -def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>; -def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>; -def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>; -def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>; -def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>; -def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>; -def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>; -def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>; -def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>; -def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>; -def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>; -def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>; -def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>; -def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; -def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; -def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; -def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; -def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; -def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; -def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; -def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>; -def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>; -def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>; -def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; -def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>; -def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; -def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; -def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; -def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>; -def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>; -def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>; -def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; -def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>; -def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>; -def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>; -def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; -def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>; -def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>; -def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; -def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>; -def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>; -def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>; -def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>; -def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>; -def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>; def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>, HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">; @@ -1752,6 +1813,8 @@ def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>, HelpText<"Allow use of CRC instructions (ARM only)">; def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>, HelpText<"Disallow use of CRC instructions (ARM only)">; +def mno_neg_immediates: Flag<["-"], "mno-neg-immediates">, Group<m_arm_Features_Group>, + HelpText<"Disallow converting instructions with negative immediates to their negation or inversion.">; def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>, HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">; @@ -1774,6 +1837,10 @@ def mamdgpu_debugger_abi : Joined<["-"], "mamdgpu-debugger-abi=">, HelpText<"Generate additional code for specified <version> of debugger ABI (AMDGPU only)">, MetaVarName<"<version>">; +def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[DriverOption]>; +def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[DriverOption]>; +def maltivec : Flag<["-"], "maltivec">, Group<m_ppc_Features_Group>; +def mno_altivec : Flag<["-"], "mno-altivec">, Group<m_ppc_Features_Group>; def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>; def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>; def mpower8_vector : Flag<["-"], "mpower8-vector">, @@ -1824,12 +1891,6 @@ def mlongcall: Flag<["-"], "mlongcall">, def mno_longcall : Flag<["-"], "mno-longcall">, Group<m_ppc_Features_Group>; -def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Enable AltiVec vector initializer syntax">; -def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>; -def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>; -def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>; - def mvx : Flag<["-"], "mvx">, Group<m_Group>; def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>; @@ -1874,62 +1935,8 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group> Flags<[CC1Option]>, HelpText<"Use copy relocations support for PIE builds">; def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>; -def mfentry : Flag<["-"], "mfentry">, HelpText<"insert calls to fentry at function entry (x86 only)">, +def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">, Flags<[CC1Option]>, Group<m_Group>; -def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>; -def m80387 : Flag<["-"], "m80387">, Alias<mx87>; -def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>; -def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>; -def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>; -def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>; -def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>; -def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>; -def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>; -def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>; -def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>; -def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>; -def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>; -def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>; -def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>; -def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>; -def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>; -def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>; -def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>; -def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>; -def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>; -def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>; -def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; -def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; -def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; -def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; -def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; -def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; -def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; -def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>; -def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>; -def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>; -def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; -def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>; -def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; -def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; -def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; -def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; -def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>; -def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; -def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; -def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; -def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; -def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>; -def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>; -def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; -def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>; -def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>; -def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>; -def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>; -def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>; -def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>; -def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>; -def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>; def mips16 : Flag<["-"], "mips16">, Group<m_Group>; def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>; def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>; @@ -1942,21 +1949,56 @@ def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_Group>; def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, Group<m_Group>; def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_Group>; +def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>, + IgnoredGCCCompat; +def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group<m_Group>, + IgnoredGCCCompat; def mdsp : Flag<["-"], "mdsp">, Group<m_Group>; def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>; def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>; def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_Group>; def msingle_float : Flag<["-"], "msingle-float">, Group<m_Group>; def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_Group>; +def mmadd4 : Flag<["-"], "mmadd4">, Group<m_Group>, + HelpText<"Enable the generation of 4-operand madd.s, madd.d and related instructions.">; +def mno_madd4 : Flag<["-"], "mno-madd4">, Group<m_Group>, + HelpText<"Disable the generation of 4-operand madd.s, madd.d and related instructions.">; def mmsa : Flag<["-"], "mmsa">, Group<m_Group>, HelpText<"Enable MSA ASE (MIPS only)">; def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>, HelpText<"Disable MSA ASE (MIPS only)">; +def mmt : Flag<["-"], "mmt">, Group<m_Group>, + HelpText<"Enable MT ASE (MIPS only)">; +def mno_mt : Flag<["-"], "mno-mt">, Group<m_Group>, + HelpText<"Disable MT ASE (MIPS only)">; def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>, HelpText<"Use 64-bit floating point registers (MIPS only)">; def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>, HelpText<"Use 32-bit floating point registers (MIPS only)">; +def mgpopt : Flag<["-"], "mgpopt">, Group<m_Group>, + HelpText<"Use GP relative accesses for symbols known to be in a small" + " data section (MIPS)">; +def mno_gpopt : Flag<["-"], "mno-gpopt">, Group<m_Group>, + HelpText<"Do not use GP relative accesses for symbols known to be in a small" + " data section (MIPS)">; +def mlocal_sdata : Flag<["-"], "mlocal-sdata">, Group<m_Group>, + HelpText<"Extend the -G behaviour to object local data (MIPS)">; +def mno_local_sdata : Flag<["-"], "mno-local-sdata">, Group<m_Group>, + HelpText<"Do not extend the -G behaviour to object local data (MIPS)">; +def mextern_sdata : Flag<["-"], "mextern-sdata">, Group<m_Group>, + HelpText<"Assume that externally defined data is in the small data if it" + " meets the -G <size> threshold (MIPS)">; +def mno_extern_sdata : Flag<["-"], "mno-extern-sdata">, Group<m_Group>, + HelpText<"Do not assume that externally defined data is in the small data if" + " it meets the -G <size> threshold (MIPS)">; +def membedded_data : Flag<["-"], "membedded-data">, Group<m_Group>, + HelpText<"Place constants in the .rodata section instead of the .sdata " + "section even if they meet the -G <size> threshold (MIPS)">; +def mno_embedded_data : Flag<["-"], "mno-embedded-data">, Group<m_Group>, + HelpText<"Do not place constants in the .rodata section instead of the " + ".sdata if they meet the -G <size> threshold (MIPS)">; def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>; +def mabs_EQ : Joined<["-"], "mabs=">, Group<m_Group>; def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>, HelpText<"Enable SVR4-style position-independent code (Mips only)">; def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>, @@ -2031,7 +2073,7 @@ def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group> def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>; def no_pedantic : Flag<["-", "--"], "no-pedantic">, Group<pedantic_Group>; def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">; -def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>, +def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option, CoreOption]>, HelpText<"Disable builtin #include directories">; def nocudainc : Flag<["-"], "nocudainc">; def nocudalib : Flag<["-"], "nocudalib">; @@ -2040,14 +2082,16 @@ def nofixprebinding : Flag<["-"], "nofixprebinding">; def nolibc : Flag<["-"], "nolibc">; def nomultidefs : Flag<["-"], "nomultidefs">; def nopie : Flag<["-"], "nopie">; +def no_pie : Flag<["-"], "no-pie">, Alias<nopie>; def noprebind : Flag<["-"], "noprebind">; def noseglinkedit : Flag<["-"], "noseglinkedit">; def nostartfiles : Flag<["-"], "nostartfiles">; -def nostdinc : Flag<["-"], "nostdinc">; +def nostdinc : Flag<["-"], "nostdinc">, Flags<[CoreOption]>; def nostdlibinc : Flag<["-"], "nostdlibinc">; def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>, HelpText<"Disable standard #include directories for the C++ standard library">; def nostdlib : Flag<["-"], "nostdlib">; +def nostdlibxx : Flag<["-"], "nostdlib++">; def object : Flag<["-"], "object">; def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>, HelpText<"Write output to <file>">, MetaVarName<"<file>">; @@ -2074,6 +2118,8 @@ def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">, Flags<[Unsupported]>; def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">, HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">; +def print_resource_dir : Flag<["-", "--"], "print-resource-dir">, + HelpText<"Print the resource directory pathname">; def print_search_dirs : Flag<["-", "--"], "print-search-dirs">, HelpText<"Print the paths used for finding libraries and programs">; def private__bundle : Flag<["-"], "private_bundle">; @@ -2098,6 +2144,10 @@ def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption, CoreO def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group<Link_Group>; def rtlib_EQ : Joined<["-", "--"], "rtlib=">, HelpText<"Compiler runtime library to use">; +def frtlib_add_rpath: Flag<["-"], "frtlib-add-rpath">, Flags<[NoArgumentUnused]>, + HelpText<"Add -rpath with architecture-specific resource directory to the linker flags">; +def fno_rtlib_add_rpath: Flag<["-"], "fno-rtlib-add-rpath">, Flags<[NoArgumentUnused]>, + HelpText<"Do not add -rpath with architecture-specific resource directory to the linker flags">; def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>, Group<Link_Group>; def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>, @@ -2136,9 +2186,16 @@ def static_libstdcxx : Flag<["-"], "static-libstdc++">; def static : Flag<["-", "--"], "static">, Flags<[NoArgumentUnused]>; def std_default_EQ : Joined<["-"], "std-default=">; def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>, - Group<CompileOnly_Group>, HelpText<"Language standard to compile for">; + Group<CompileOnly_Group>, HelpText<"Language standard to compile for">, + ValuesCode<[{ + const char *Values = + #define LANGSTANDARD(id, name, lang, desc, features) name "," + #define LANGSTANDARD_ALIAS(id, alias) alias "," + #include "clang/Frontend/LangStandards.def" + ; + }]>; def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>, - HelpText<"C++ standard library to use">; + HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">; def sub__library : JoinedOrSeparate<["-"], "sub_library">; def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">; def system_header_prefix : Joined<["--"], "system-header-prefix=">, @@ -2294,7 +2351,8 @@ def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>; def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>, HelpText<"Serialize compiler diagnostics to a file">; // We give --version different semantics from -version. -def _version : Flag<["--"], "version">, Flags<[CC1Option]>; +def _version : Flag<["--"], "version">, Flags<[CoreOption, CC1Option]>, + HelpText<"Print version information">; def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>; def _std : Separate<["--"], "std">, Alias<std_EQ>; def _stdlib : Separate<["--"], "stdlib">, Alias<stdlib_EQ>; @@ -2322,14 +2380,153 @@ def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>; def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>; -def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">; -def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Disable Hexagon Vector eXtensions">; -def mhexagon_hvx_double : Flag<["-"], "mhvx-double">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Enable Hexagon Double Vector eXtensions">; -def mno_hexagon_hvx_double : Flag<["-"], "mno-hvx-double">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Disable Hexagon Double Vector eXtensions">; +def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>, + Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>; +def mhexagon_hvx : Flag<[ "-" ], "mhvx">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mhexagon_hvx_EQ : Joined<[ "-" ], "mhvx=">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mno_hexagon_hvx : Flag<[ "-" ], "mno-hvx">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Disable Hexagon Vector eXtensions">; +def mhexagon_hvx_length_EQ : Joined<[ "-" ], "mhvx-length=">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Set Hexagon Vector Length">, Values<"64B,128B">; +// hvx-double deprecrated flag. +def mhexagon_hvx_double : Flag<[ "-" ], "mhvx-double">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Double Vector eXtensions">; +def mno_hexagon_hvx_double + : Flag<[ "-" ], "mno-hvx-double">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Disable Hexagon Double Vector eXtensions">; + + +// X86 feature flags +def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>; +def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>; +def m80387 : Flag<["-"], "m80387">, Alias<mx87>; +def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>; +def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>; +def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>; +def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; +def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>; +def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; +def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>; +def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>; +def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>; +def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>; +def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>; +def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>; +def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>; +def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>; +def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>; +def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>; +def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>; +def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>; +def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>; +def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>; +// -mno-sse4 turns off sse4.1 which has the effect of turning off everything +// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on +// everything earlier than 4.2. +def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>; +def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>; +def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>; +def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>; +def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>; +def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>; +def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>; +def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>; +def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>; +def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>; +def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>; +def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>; +def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>; +def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>; +def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>; +def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>; +def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>; +def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>; +def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>; +def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>; +def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>; +def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>; +def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>; +def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>; +def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>; +def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>; +def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>; +def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>; +def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>; +def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>; +def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>; +def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; +def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; +def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; +def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; +def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>; +def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>; +def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>; +def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>; +def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>; +def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>; +def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; +def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>; +def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>; +def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>; +def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>; +def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>; +def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>; +def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>; +def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; +def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; +def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; +def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; +def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>; +def mno_lwp : Flag<["-"], "mno-lwp">, Group<m_x86_Features_Group>; +def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; +def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; +def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>; +def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>; +def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>; +def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>; +def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>; +def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>; +def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; +def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; +def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; +def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; +def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; +def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; +def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>; +def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>; +def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; +def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; +def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; +def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; +def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; +def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; +def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; +def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; +def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>; +def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>; +def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; +def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>; +def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>; +def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>; +def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; +def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; +def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; +def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>; +def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>; +def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>; +def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>; +def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>; +def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; +def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; + // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h index 6206680118..19309c3f3b 100644 --- a/include/clang/Driver/SanitizerArgs.h +++ b/include/clang/Driver/SanitizerArgs.h @@ -32,33 +32,40 @@ class SanitizerArgs { int MsanTrackOrigins = 0; bool MsanUseAfterDtor = false; bool CfiCrossDso = false; + bool CfiICallGeneralizePointers = false; int AsanFieldPadding = 0; - bool AsanSharedRuntime = false; - bool AsanUseAfterScope = false; + bool SharedRuntime = false; + bool AsanUseAfterScope = true; + bool AsanGlobalsDeadStripping = false; bool LinkCXXRuntimes = false; bool NeedPIE = false; + bool SafeStackRuntime = false; bool Stats = false; bool TsanMemoryAccess = true; bool TsanFuncEntryExit = true; bool TsanAtomics = true; + bool MinimalRuntime = false; + // True if cross-dso CFI support if provided by the system (i.e. Android). + bool ImplicitCfiRuntime = false; public: /// Parses the sanitizer arguments from an argument list. SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); + bool needsSharedRt() const { return SharedRuntime; } + bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); } - bool needsSharedAsanRt() const { return AsanSharedRuntime; } bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } + bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); } bool needsLsanRt() const { return Sanitizers.has(SanitizerKind::Leak) && !Sanitizers.has(SanitizerKind::Address); } bool needsUbsanRt() const; + bool requiresMinimalRuntime() const { return MinimalRuntime; } bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); } - bool needsSafeStackRt() const { - return Sanitizers.has(SanitizerKind::SafeStack); - } + bool needsSafeStackRt() const { return SafeStackRuntime; } bool needsCfiRt() const; bool needsCfiDiagRt() const; bool needsStatsRt() const { return Stats; } diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h index 5012cc8966..8f76e17c48 100644 --- a/include/clang/Driver/Tool.h +++ b/include/clang/Driver/Tool.h @@ -35,7 +35,7 @@ class Tool { public: // Documents the level of support for response files in this tool. // Response files are necessary if the command line gets too large, - // requiring the arguments to be transfered to a file. + // requiring the arguments to be transferred to a file. enum ResponseFileSupport { // Provides full support for response files, which means we can transfer // all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 7dbe7a96dd..51ff2b2827 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -44,6 +44,29 @@ namespace driver { class RegisterEffectiveTriple; class SanitizerArgs; class Tool; + class XRayArgs; + +/// Helper structure used to pass information extracted from clang executable +/// name such as `i686-linux-android-g++`. +/// +struct ParsedClangName { + /// Target part of the executable name, as `i686-linux-android`. + std::string TargetPrefix; + /// Driver mode part of the executable name, as `g++`. + std::string ModeSuffix; + /// Corresponding driver mode argument, as '--driver-mode=g++' + const char *DriverMode; + /// True if TargetPrefix is recognized as a registered target name. + bool TargetIsValid; + + ParsedClangName() : DriverMode(nullptr), TargetIsValid(false) {} + ParsedClangName(std::string Suffix, const char *Mode) + : ModeSuffix(Suffix), DriverMode(Mode), TargetIsValid(false) {} + ParsedClangName(std::string Target, std::string Suffix, const char *Mode, + bool IsRegistered) + : TargetPrefix(Target), ModeSuffix(Suffix), DriverMode(Mode), + TargetIsValid(IsRegistered) {} +}; /// ToolChain - Access to tools for a single platform. class ToolChain { @@ -94,12 +117,15 @@ private: Tool *getOffloadBundler() const; mutable std::unique_ptr<SanitizerArgs> SanitizerArguments; + mutable std::unique_ptr<XRayArgs> XRayArguments; /// The effective clang triple for the current Job. mutable llvm::Triple EffectiveTriple; /// Set the toolchain's effective clang triple. - void setEffectiveTriple(llvm::Triple ET) const { EffectiveTriple = ET; } + void setEffectiveTriple(llvm::Triple ET) const { + EffectiveTriple = std::move(ET); + } friend class RegisterEffectiveTriple; @@ -175,6 +201,8 @@ public: const SanitizerArgs& getSanitizerArgs() const; + const XRayArgs& getXRayArgs() const; + // Returns the Arg * that explicitly turned on/off rtti, or nullptr. const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; } @@ -187,13 +215,16 @@ public: /// For example, when called with i686-linux-android-g++, the first element /// of the return value will be set to `"i686-linux-android"` and the second /// will be set to "--driver-mode=g++"`. + /// It is OK if the target name is not registered. In this case the return + /// value contains false in the field TargetIsValid. /// /// \pre `llvm::InitializeAllTargets()` has been called. /// \param ProgName The name the Clang driver was invoked with (from, - /// e.g., argv[0]) - /// \return A pair of (`target`, `mode-flag`), where one or both may be empty. - static std::pair<std::string, std::string> - getTargetAndModeFromProgramName(StringRef ProgName); + /// e.g., argv[0]). + /// \return A structure of type ParsedClangName that contains the executable + /// name parts. + /// + static ParsedClangName getTargetAndModeFromProgramName(StringRef ProgName); // Tool access. @@ -211,6 +242,13 @@ public: return nullptr; } + /// TranslateOpenMPTargetArgs - Create a new derived argument list for + /// that contains the OpenMP target specific flags passed via + /// -Xopenmp-target -opt=val OR -Xopenmp-target=<triple> -opt=val + virtual llvm::opt::DerivedArgList *TranslateOpenMPTargetArgs( + const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, + SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const; + /// Choose a tool to use to handle the action \p JA. /// /// This can be overridden when a particular ToolChain needs to use @@ -292,6 +330,8 @@ public: return ToolChain::CST_Libstdcxx; } + virtual std::string getCompilerRTPath() const; + virtual std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, bool Shared = false) const; @@ -309,7 +349,7 @@ public: /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables /// by default. - virtual bool IsUnwindTablesDefault() const; + virtual bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const; /// \brief Test whether this toolchain defaults to PIC. virtual bool isPICDefault() const = 0; @@ -405,7 +445,8 @@ public: /// \brief Add options that need to be passed to cc1 for this target. virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const; /// \brief Add warning options that need to be passed to cc1 for this target. virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const; @@ -425,6 +466,10 @@ public: AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + /// Returns if the C++ standard library should be linked in. + /// Note that e.g. -lm should still be linked even if this returns false. + bool ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const; + /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use /// for the given C++ standard library type. virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, @@ -476,7 +521,7 @@ class RegisterEffectiveTriple { public: RegisterEffectiveTriple(const ToolChain &TC, llvm::Triple T) : TC(TC) { - TC.setEffectiveTriple(T); + TC.setEffectiveTriple(std::move(T)); } ~RegisterEffectiveTriple() { TC.setEffectiveTriple(llvm::Triple()); } diff --git a/include/clang/Driver/XRayArgs.h b/include/clang/Driver/XRayArgs.h new file mode 100644 index 0000000000..83210d100a --- /dev/null +++ b/include/clang/Driver/XRayArgs.h @@ -0,0 +1,38 @@ +//===--- XRayArgs.h - Arguments for XRay ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_DRIVER_XRAYARGS_H +#define LLVM_CLANG_DRIVER_XRAYARGS_H + +#include "clang/Driver/Types.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" + +namespace clang { +namespace driver { + +class ToolChain; + +class XRayArgs { + std::vector<std::string> AlwaysInstrumentFiles; + std::vector<std::string> NeverInstrumentFiles; + std::vector<std::string> ExtraDeps; + bool XRayInstrument = false; + int InstructionThreshold = 200; + +public: + /// Parses the XRay arguments from an argument list. + XRayArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); + void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const; +}; + +} // namespace driver +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_XRAYARGS_H diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h index b6ec8b8f06..d95a0c2be8 100644 --- a/include/clang/Edit/EditedSource.h +++ b/include/clang/Edit/EditedSource.h @@ -17,6 +17,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Allocator.h" #include <map> +#include <tuple> namespace clang { class LangOptions; @@ -41,9 +42,21 @@ class EditedSource { typedef std::map<FileOffset, FileEdit> FileEditsTy; FileEditsTy FileEdits; - llvm::DenseMap<unsigned, llvm::TinyPtrVector<IdentifierInfo*>> - ExpansionToArgMap; - SmallVector<std::pair<SourceLocation, IdentifierInfo*>, 2> + struct MacroArgUse { + IdentifierInfo *Identifier; + SourceLocation ImmediateExpansionLoc; + // Location of argument use inside the top-level macro + SourceLocation UseLoc; + + bool operator==(const MacroArgUse &Other) const { + return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) == + std::tie(Other.Identifier, Other.ImmediateExpansionLoc, + Other.UseLoc); + } + }; + + llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap; + SmallVector<std::pair<SourceLocation, MacroArgUse>, 2> CurrCommitMacroArgExps; IdentifierTable IdentTable; @@ -65,7 +78,7 @@ public: bool commit(const Commit &commit); - void applyRewrites(EditsReceiver &receiver); + void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true); void clearRewrites(); StringRef copyString(StringRef str) { return str.copy(StrAlloc); } @@ -84,7 +97,7 @@ private: FileEditsTy::iterator getActionForOffset(FileOffset Offs); void deconstructMacroArgLoc(SourceLocation Loc, SourceLocation &ExpansionLoc, - IdentifierInfo *&II); + MacroArgUse &ArgUse); void startingCommit(); void finishedCommit(); diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index b856bfd31a..a0e42f4e30 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -98,22 +98,39 @@ struct FormatStyle { /// \endcode bool AlignConsecutiveDeclarations; - /// \brief If ``true``, aligns escaped newlines as far left as possible. - /// Otherwise puts them into the right-most column. - /// \code - /// true: - /// #define A \ - /// int aaaa; \ - /// int b; \ - /// int dddddddddd; - /// - /// false: - /// #define A \ - /// int aaaa; \ - /// int b; \ - /// int dddddddddd; - /// \endcode - bool AlignEscapedNewlinesLeft; + /// \brief Different styles for aligning escaped newlines. + enum EscapedNewlineAlignmentStyle { + /// \brief Don't align escaped newlines. + /// \code + /// #define A \ + /// int aaaa; \ + /// int b; \ + /// int dddddddddd; + /// \endcode + ENAS_DontAlign, + /// \brief Align escaped newlines as far left as possible. + /// \code + /// true: + /// #define A \ + /// int aaaa; \ + /// int b; \ + /// int dddddddddd; + /// + /// false: + /// \endcode + ENAS_Left, + /// \brief Align escaped newlines in the right-most column. + /// \code + /// #define A \ + /// int aaaa; \ + /// int b; \ + /// int dddddddddd; + /// \endcode + ENAS_Right, + }; + + /// \brief Options for aligning backslashes in escaped newlines. + EscapedNewlineAlignmentStyle AlignEscapedNewlines; /// \brief If ``true``, horizontally align operands of binary and ternary /// expressions. @@ -134,13 +151,20 @@ struct FormatStyle { /// \endcode bool AlignTrailingComments; - /// \brief Allow putting all parameters of a function declaration onto + /// \brief If the function declaration doesn't fit on a line, + /// allow putting all parameters of a function declaration onto /// the next line even if ``BinPackParameters`` is ``false``. /// \code - /// true: false: - /// myFunction(foo, vs. myFunction(foo, bar, plop); - /// bar, - /// plop); + /// true: + /// void myFunction( + /// int a, int b, int c, int d, int e); + /// + /// false: + /// void myFunction(int a, + /// int b, + /// int c, + /// int d, + /// int e); /// \endcode bool AllowAllParametersOfDeclarationOnNextLine; @@ -167,9 +191,23 @@ struct FormatStyle { enum ShortFunctionStyle { /// \brief Never merge functions into a single line. SFS_None, + /// \brief Only merge functions defined inside a class. Same as "inline", + /// except it does not implies "empty": i.e. top level empty functions + /// are not merged either. + /// \code + /// class Foo { + /// void f() { foo(); } + /// }; + /// void f() { + /// foo(); + /// } + /// void f() { + /// } + /// \endcode + SFS_InlineOnly, /// \brief Only merge empty functions. /// \code - /// void f() { bar(); } + /// void f() {} /// void f2() { /// bar2(); /// } @@ -177,14 +215,18 @@ struct FormatStyle { SFS_Empty, /// \brief Only merge functions defined inside a class. Implies "empty". /// \code - /// class { + /// class Foo { /// void f() { foo(); } /// }; + /// void f() { + /// foo(); + /// } + /// void f() {} /// \endcode SFS_Inline, /// \brief Merge all functions fitting on a single line. /// \code - /// class { + /// class Foo { /// void f() { foo(); } /// }; /// void f() { bar(); } @@ -204,7 +246,7 @@ struct FormatStyle { bool AllowShortLoopsOnASingleLine; /// \brief Different ways to break after the function definition return type. - /// This option is deprecated and is retained for backwards compatibility. + /// This option is **deprecated** and is retained for backwards compatibility. enum DefinitionReturnTypeBreakingStyle { /// Break after return type automatically. /// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account. @@ -287,7 +329,7 @@ struct FormatStyle { }; /// \brief The function definition return type breaking style to use. This - /// option is deprecated and is retained for backwards compatibility. + /// option is **deprecated** and is retained for backwards compatibility. DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType; /// \brief The function declaration return type breaking style to use. @@ -318,19 +360,73 @@ struct FormatStyle { /// \brief If ``false``, a function call's arguments will either be all on the /// same line or will have one line each. + /// \code + /// true: + /// void f() { + /// f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa, + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); + /// } + /// + /// false: + /// void f() { + /// f(aaaaaaaaaaaaaaaaaaaa, + /// aaaaaaaaaaaaaaaaaaaa, + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); + /// } + /// \endcode bool BinPackArguments; /// \brief If ``false``, a function declaration's or function definition's /// parameters will either all be on the same line or will have one line each. + /// \code + /// true: + /// void f(int aaaaaaaaaaaaaaaaaaaa, int aaaaaaaaaaaaaaaaaaaa, + /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {} + /// + /// false: + /// void f(int aaaaaaaaaaaaaaaaaaaa, + /// int aaaaaaaaaaaaaaaaaaaa, + /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {} + /// \endcode bool BinPackParameters; /// \brief The style of breaking before or after binary operators. enum BinaryOperatorStyle { /// Break after operators. + /// \code + /// LooooooooooongType loooooooooooooooooooooongVariable = + /// someLooooooooooooooooongFunction(); + /// + /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > + /// ccccccccccccccccccccccccccccccccccccccccc; + /// \endcode BOS_None, /// Break before operators that aren't assignments. + /// \code + /// LooooooooooongType loooooooooooooooooooooongVariable = + /// someLooooooooooooooooongFunction(); + /// + /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// > ccccccccccccccccccccccccccccccccccccccccc; + /// \endcode BOS_NonAssignment, /// Break before operators. + /// \code + /// LooooooooooongType loooooooooooooooooooooongVariable + /// = someLooooooooooooooooongFunction(); + /// + /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// > ccccccccccccccccccccccccccccccccccccccccc; + /// \endcode BOS_All, }; @@ -563,12 +659,12 @@ struct FormatStyle { /// struct foo /// { /// int x; - /// } + /// }; /// /// false: /// struct foo { /// int x; - /// } + /// }; /// \endcode bool AfterStruct; /// \brief Wrap union definitions. @@ -585,6 +681,20 @@ struct FormatStyle { /// } /// \endcode bool AfterUnion; + /// \brief Wrap extern blocks. + /// \code + /// true: + /// extern "C" + /// { + /// int foo(); + /// } + /// + /// false: + /// extern "C" { + /// int foo(); + /// } + /// \endcode + bool AfterExternBlock; /// \brief Wrap before ``catch``. /// \code /// true: @@ -617,12 +727,54 @@ struct FormatStyle { bool BeforeElse; /// \brief Indent the wrapped braces themselves. bool IndentBraces; + /// \brief If ``false``, empty function body can be put on a single line. + /// This option is used only if the opening brace of the function has + /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is + /// set, and the function could/should not be put on a single line (as per + /// `AllowShortFunctionsOnASingleLine` and constructor formatting options). + /// \code + /// int f() vs. inf f() + /// {} { + /// } + /// \endcode + /// + bool SplitEmptyFunction; + /// \brief If ``false``, empty record (e.g. class, struct or union) body + /// can be put on a single line. This option is used only if the opening + /// brace of the record has already been wrapped, i.e. the `AfterClass` + /// (for classes) brace wrapping mode is set. + /// \code + /// class Foo vs. class Foo + /// {} { + /// } + /// \endcode + /// + bool SplitEmptyRecord; + /// \brief If ``false``, empty namespace body can be put on a single line. + /// This option is used only if the opening brace of the namespace has + /// already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is + /// set. + /// \code + /// namespace Foo vs. namespace Foo + /// {} { + /// } + /// \endcode + /// + bool SplitEmptyNamespace; }; /// \brief Control of individual brace wrapping cases. /// /// If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how /// each individual brace case should be handled. Otherwise, this is ignored. + /// \code{.yaml} + /// # Example of usage: + /// BreakBeforeBraces: Custom + /// BraceWrapping: + /// AfterEnum: true + /// AfterStruct: false + /// SplitEmptyFunction: false + /// \endcode BraceWrappingFlags BraceWrapping; /// \brief If ``true``, ternary operators will be placed after line breaks. @@ -632,25 +784,49 @@ struct FormatStyle { /// ? firstValue /// : SecondValueVeryVeryVeryVeryLong; /// - /// true: + /// false: /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? /// firstValue : /// SecondValueVeryVeryVeryVeryLong; /// \endcode bool BreakBeforeTernaryOperators; - /// \brief Always break constructor initializers before commas and align - /// the commas with the colon. - /// \code - /// true: false: - /// SomeClass::Constructor() vs. SomeClass::Constructor() : a(a), - /// : a(a) b(b), - /// , b(b) c(c) {} - /// , c(c) {} - /// \endcode - bool BreakConstructorInitializersBeforeComma; + /// \brief Different ways to break initializers. + enum BreakConstructorInitializersStyle { + /// Break constructor initializers before the colon and after the commas. + /// \code + /// Constructor() + /// : initializer1(), + /// initializer2() + /// \endcode + BCIS_BeforeColon, + /// Break constructor initializers before the colon and commas, and align + /// the commas with the colon. + /// \code + /// Constructor() + /// : initializer1() + /// , initializer2() + /// \endcode + BCIS_BeforeComma, + /// Break constructor initializers after the colon and commas. + /// \code + /// Constructor() : + /// initializer1(), + /// initializer2() + /// \endcode + BCIS_AfterColon + }; + + /// \brief The constructor initializers style to use. + BreakConstructorInitializersStyle BreakConstructorInitializers; /// \brief Break after each annotation on a field in Java files. + /// \code{.java} + /// true: false: + /// @Partial vs. @Partial @Mock DataLoad loader; + /// @Mock + /// DataLoad loader; + /// \endcode bool BreakAfterJavaFieldAnnotations; /// \brief Allow breaking string literals when formatting. @@ -665,6 +841,11 @@ struct FormatStyle { /// \brief A regular expression that describes comments with special meaning, /// which should not be split into lines or otherwise changed. + /// \code + /// // CommentPragmas: '^ FOOBAR pragma:' + /// // Will leave the following line unaffected + /// #include <vector> // FOOBAR pragma: keep + /// \endcode std::string CommentPragmas; /// \brief If ``true``, in the class inheritance expression clang-format will @@ -678,6 +859,29 @@ struct FormatStyle { /// \endcode bool BreakBeforeInheritanceComma; + /// \brief If ``true``, consecutive namespace declarations will be on the same + /// line. If ``false``, each namespace is declared on a new line. + /// \code + /// true: + /// namespace Foo { namespace Bar { + /// }} + /// + /// false: + /// namespace Foo { + /// namespace Bar { + /// } + /// } + /// \endcode + /// + /// If it does not fit on a single line, the overflowing namespaces get + /// wrapped: + /// \code + /// namespace Foo { namespace Bar { + /// namespace Extra { + /// }}} + /// \endcode + bool CompactNamespaces; + /// \brief If the constructor initializers don't fit on a line, put each /// initializer on its own line. /// \code @@ -701,6 +905,13 @@ struct FormatStyle { unsigned ConstructorInitializerIndentWidth; /// \brief Indent width for line continuations. + /// \code + /// ContinuationIndentWidth: 2 + /// + /// int i = // VeryVeryVeryVeryVeryLongComment + /// longFunction( // Again a long comment + /// arg); + /// \endcode unsigned ContinuationIndentWidth; /// \brief If ``true``, format braced lists as best suited for C++11 braced @@ -716,11 +927,20 @@ struct FormatStyle { /// (e.g. a type or variable name), clang-format formats as if the ``{}`` were /// the parentheses of a function call with that name. If there is no name, /// a zero-length name is assumed. + /// \code + /// true: false: + /// vector<int> x{1, 2, 3, 4}; vs. vector<int> x{ 1, 2, 3, 4 }; + /// vector<T> x{{}, {}, {}, {}}; vector<T> x{ {}, {}, {}, {} }; + /// f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]); + /// new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 }; + /// \endcode bool Cpp11BracedListStyle; /// \brief If ``true``, analyze the formatted file for the most common - /// alignment of ``&`` and ``*``. ``PointerAlignment`` is then used only as - /// fallback. + /// alignment of ``&`` and ``*``. + /// Pointer and reference alignment styles are going to be updated according + /// to the preferences found in the file. + /// ``PointerAlignment`` is then used only as fallback. bool DerivePointerAlignment; /// \brief Disables formatting completely. @@ -797,7 +1017,7 @@ struct FormatStyle { /// IncludeCategories: /// - Regex: '^"(llvm|llvm-c|clang|clang-c)/' /// Priority: 2 - /// - Regex: '^(<|"(gtest|isl|json)/)' + /// - Regex: '^(<|"(gtest|gmock|isl|json)/)' /// Priority: 3 /// - Regex: '.*' /// Priority: 1 @@ -821,23 +1041,89 @@ struct FormatStyle { /// /// When ``false``, use the same indentation level as for the switch statement. /// Switch statement body is always indented one level more than case labels. + /// \code + /// false: true: + /// switch (fool) { vs. switch (fool) { + /// case 1: case 1: + /// bar(); bar(); + /// break; break; + /// default: default: + /// plop(); plop(); + /// } } + /// \endcode bool IndentCaseLabels; + /// \brief Options for indenting preprocessor directives. + enum PPDirectiveIndentStyle { + /// Does not indent any directives. + /// \code + /// #if FOO + /// #if BAR + /// #include <foo> + /// #endif + /// #endif + /// \endcode + PPDIS_None, + /// Indents directives after the hash. + /// \code + /// #if FOO + /// # if BAR + /// # include <foo> + /// # endif + /// #endif + /// \endcode + PPDIS_AfterHash + }; + + /// \brief The preprocessor directive indenting style to use. + PPDirectiveIndentStyle IndentPPDirectives; + /// \brief The number of columns to use for indentation. + /// \code + /// IndentWidth: 3 + /// + /// void f() { + /// someFunction(); + /// if (true, false) { + /// f(); + /// } + /// } + /// \endcode unsigned IndentWidth; /// \brief Indent if a function definition or declaration is wrapped after the /// type. + /// \code + /// true: + /// LoooooooooooooooooooooooooooooooooooooooongReturnType + /// LoooooooooooooooooooooooooooooooongFunctionDeclaration(); + /// + /// false: + /// LoooooooooooooooooooooooooooooooooooooooongReturnType + /// LoooooooooooooooooooooooooooooooongFunctionDeclaration(); + /// \endcode bool IndentWrappedFunctionNames; /// \brief Quotation styles for JavaScript strings. Does not affect template /// strings. enum JavaScriptQuoteStyle { /// Leave string quotes as they are. + /// \code{.js} + /// string1 = "foo"; + /// string2 = 'bar'; + /// \endcode JSQS_Leave, /// Always use single quotes. + /// \code{.js} + /// string1 = 'foo'; + /// string2 = 'bar'; + /// \endcode JSQS_Single, /// Always use double quotes. + /// \code{.js} + /// string1 = "foo"; + /// string2 = "bar"; + /// \endcode JSQS_Double }; @@ -845,9 +1131,27 @@ struct FormatStyle { JavaScriptQuoteStyle JavaScriptQuotes; /// \brief Whether to wrap JavaScript import/export statements. + /// \code{.js} + /// true: + /// import { + /// VeryLongImportsAreAnnoying, + /// VeryLongImportsAreAnnoying, + /// VeryLongImportsAreAnnoying, + /// } from 'some/module.js' + /// + /// false: + /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" + /// \endcode bool JavaScriptWrapImports; - /// \brief If true, empty lines at the start of blocks are kept. + /// \brief If true, the empty line at the start of blocks is kept. + /// \code + /// true: false: + /// if (foo) { vs. if (foo) { + /// bar(); + /// bar(); } + /// } + /// \endcode bool KeepEmptyLinesAtTheStartOfBlocks; /// \brief Supported languages. @@ -870,29 +1174,91 @@ struct FormatStyle { /// (https://developers.google.com/protocol-buffers/). LK_Proto, /// Should be used for TableGen code. - LK_TableGen + LK_TableGen, + /// Should be used for Protocol Buffer messages in text format + /// (https://developers.google.com/protocol-buffers/). + LK_TextProto }; - bool IsCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } + bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } /// \brief Language, this format style is targeted at. LanguageKind Language; /// \brief A regular expression matching macros that start a block. + /// \code + /// # With: + /// MacroBlockBegin: "^NS_MAP_BEGIN|\ + /// NS_TABLE_HEAD$" + /// MacroBlockEnd: "^\ + /// NS_MAP_END|\ + /// NS_TABLE_.*_END$" + /// + /// NS_MAP_BEGIN + /// foo(); + /// NS_MAP_END + /// + /// NS_TABLE_HEAD + /// bar(); + /// NS_TABLE_FOO_END + /// + /// # Without: + /// NS_MAP_BEGIN + /// foo(); + /// NS_MAP_END + /// + /// NS_TABLE_HEAD + /// bar(); + /// NS_TABLE_FOO_END + /// \endcode std::string MacroBlockBegin; /// \brief A regular expression matching macros that end a block. std::string MacroBlockEnd; /// \brief The maximum number of consecutive empty lines to keep. + /// \code + /// MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0 + /// int f() { int f() { + /// int = 1; int i = 1; + /// i = foo(); + /// i = foo(); return i; + /// } + /// return i; + /// } + /// \endcode unsigned MaxEmptyLinesToKeep; /// \brief Different ways to indent namespace contents. enum NamespaceIndentationKind { /// Don't indent in namespaces. + /// \code + /// namespace out { + /// int i; + /// namespace in { + /// int i; + /// } + /// } + /// \endcode NI_None, /// Indent only in inner namespaces (nested in other namespaces). + /// \code + /// namespace out { + /// int i; + /// namespace in { + /// int i; + /// } + /// } + /// \endcode NI_Inner, /// Indent in all namespaces. + /// \code + /// namespace out { + /// int i; + /// namespace in { + /// int i; + /// } + /// } + /// \endcode NI_All }; @@ -900,6 +1266,13 @@ struct FormatStyle { NamespaceIndentationKind NamespaceIndentation; /// \brief The number of characters to use for indentation of ObjC blocks. + /// \code{.objc} + /// ObjCBlockIndentWidth: 4 + /// + /// [operation setCompletionBlock:^{ + /// [self onOperationDone]; + /// }]; + /// \endcode unsigned ObjCBlockIndentWidth; /// \brief Add a space after ``@property`` in Objective-C, i.e. use @@ -910,6 +1283,9 @@ struct FormatStyle { /// ``Foo <Protocol>`` instead of ``Foo<Protocol>``. bool ObjCSpaceBeforeProtocolList; + /// \brief The penalty for breaking around an assignment operator. + unsigned PenaltyBreakAssignment; + /// \brief The penalty for breaking a function call after ``call(``. unsigned PenaltyBreakBeforeFirstCallParameter; @@ -951,7 +1327,53 @@ struct FormatStyle { /// \brief Pointer and reference alignment style. PointerAlignmentStyle PointerAlignment; + /// See documentation of ``RawStringFormats``. + struct RawStringFormat { + /// \brief The delimiter that this raw string format matches. + std::string Delimiter; + /// \brief The language of this raw string. + LanguageKind Language; + /// \brief The style name on which this raw string format is based on. + /// If not specified, the raw string format is based on the style that this + /// format is based on. + std::string BasedOnStyle; + bool operator==(const RawStringFormat &Other) const { + return Delimiter == Other.Delimiter && Language == Other.Language && + BasedOnStyle == Other.BasedOnStyle; + } + }; + + /// \brief Raw string delimiters denoting that the raw string contents are + /// code in a particular language and can be reformatted. + /// + /// A raw string with a matching delimiter will be reformatted assuming the + /// specified language based on a predefined style given by 'BasedOnStyle'. + /// If 'BasedOnStyle' is not found, the formatting is based on llvm style. + /// + /// To configure this in the .clang-format file, use: + /// \code{.yaml} + /// RawStringFormats: + /// - Delimiter: 'pb' + /// Language: TextProto + /// BasedOnStyle: llvm + /// - Delimiter: 'proto' + /// Language: TextProto + /// BasedOnStyle: google + /// \endcode + std::vector<RawStringFormat> RawStringFormats; + /// \brief If ``true``, clang-format will attempt to re-flow comments. + /// \code + /// false: + /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /// + /// true: + /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + /// // information + /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + /// * information */ + /// \endcode bool ReflowComments; /// \brief If ``true``, clang-format will sort ``#includes``. @@ -962,6 +1384,14 @@ struct FormatStyle { /// \endcode bool SortIncludes; + /// \brief If ``true``, clang-format will sort using declarations. + /// \code + /// false: true: + /// using std::cout; vs. using std::cin; + /// using std::cin; using std::cout; + /// \endcode + bool SortUsingDeclarations; + /// \brief If ``true``, a space is inserted after C style casts. /// \code /// true: false: @@ -987,14 +1417,35 @@ struct FormatStyle { /// \brief Different ways to put a space before opening parentheses. enum SpaceBeforeParensOptions { /// Never put a space before opening parentheses. + /// \code + /// void f() { + /// if(true) { + /// f(); + /// } + /// } + /// \endcode SBPO_Never, /// Put a space before opening parentheses only after control statement /// keywords (``for/if/while...``). + /// \code + /// void f() { + /// if (true) { + /// f(); + /// } + /// } + /// \endcode SBPO_ControlStatements, /// Always put a space before opening parentheses, except when it's /// prohibited by the syntax rules (in function-like macro definitions) or /// when determined by other style rules (after unary operators, opening /// parentheses, etc.) + /// \code + /// void f () { + /// if (true) { + /// f (); + /// } + /// } + /// \endcode SBPO_Always }; @@ -1002,6 +1453,15 @@ struct FormatStyle { SpaceBeforeParensOptions SpaceBeforeParens; /// \brief If ``true``, spaces may be inserted into ``()``. + /// \code + /// true: false: + /// void f( ) { vs. void f() { + /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + /// if (true) { if (true) { + /// f( ); f(); + /// } } + /// } } + /// \endcode bool SpaceInEmptyParentheses; /// \brief The number of spaces before trailing line comments @@ -1010,6 +1470,14 @@ struct FormatStyle { /// This does not affect trailing block comments (``/*`` - comments) as /// those commonly have different usage patterns and a number of special /// cases. + /// \code + /// SpacesBeforeTrailingComments: 3 + /// void f() { + /// if (true) { // foo1 + /// f(); // bar + /// } // foo + /// } + /// \endcode unsigned SpacesBeforeTrailingComments; /// \brief If ``true``, spaces will be inserted after ``<`` and before ``>`` @@ -1023,6 +1491,11 @@ struct FormatStyle { /// \brief If ``true``, spaces are inserted inside container literals (e.g. /// ObjC and Javascript array and dict literals). + /// \code{.js} + /// true: false: + /// var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; + /// f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3}); + /// \endcode bool SpacesInContainerLiterals; /// \brief If ``true``, spaces may be inserted into C style casts. @@ -1052,7 +1525,8 @@ struct FormatStyle { enum LanguageStandard { /// Use C++03-compatible syntax. LS_Cpp03, - /// Use features of C++11 (e.g. ``A<A<int>>`` instead of ``A<A<int> >``). + /// Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of + /// ``A<A<int> >``). LS_Cpp11, /// Automatic detection based on the input. LS_Auto @@ -1086,7 +1560,7 @@ struct FormatStyle { AlignAfterOpenBracket == R.AlignAfterOpenBracket && AlignConsecutiveAssignments == R.AlignConsecutiveAssignments && AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations && - AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft && + AlignEscapedNewlines == R.AlignEscapedNewlines && AlignOperands == R.AlignOperands && AlignTrailingComments == R.AlignTrailingComments && AllowAllParametersOfDeclarationOnNextLine == @@ -1109,8 +1583,8 @@ struct FormatStyle { BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && - BreakConstructorInitializersBeforeComma == - R.BreakConstructorInitializersBeforeComma && + BreakConstructorInitializers == R.BreakConstructorInitializers && + CompactNamespaces == R.CompactNamespaces && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && @@ -1129,6 +1603,7 @@ struct FormatStyle { ForEachMacros == R.ForEachMacros && IncludeCategories == R.IncludeCategories && IndentCaseLabels == R.IndentCaseLabels && + IndentPPDirectives == R.IndentPPDirectives && IndentWidth == R.IndentWidth && Language == R.Language && IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && JavaScriptQuotes == R.JavaScriptQuotes && @@ -1142,6 +1617,8 @@ struct FormatStyle { ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && + PenaltyBreakAssignment == + R.PenaltyBreakAssignment && PenaltyBreakBeforeFirstCallParameter == R.PenaltyBreakBeforeFirstCallParameter && PenaltyBreakComment == R.PenaltyBreakComment && @@ -1150,6 +1627,7 @@ struct FormatStyle { PenaltyExcessCharacter == R.PenaltyExcessCharacter && PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine && PointerAlignment == R.PointerAlignment && + RawStringFormats == R.RawStringFormats && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword && SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && @@ -1251,6 +1729,18 @@ llvm::Expected<tooling::Replacements> cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, const FormatStyle &Style); +/// \brief Represents the status of a formatting attempt. +struct FormattingAttemptStatus { + /// \brief A value of ``false`` means that any of the affected ranges were not + /// formatted due to a non-recoverable syntax error. + bool FormatComplete = true; + + /// \brief If ``FormatComplete`` is false, ``Line`` records a one-based + /// original line number at which a syntax error might have occurred. This is + /// based on a best-effort analysis and could be imprecise. + unsigned Line = 0; +}; + /// \brief Reformats the given \p Ranges in \p Code. /// /// Each range is extended on either end to its next bigger logic unit, i.e. @@ -1260,13 +1750,20 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, /// Returns the ``Replacements`` necessary to make all \p Ranges comply with /// \p Style. /// -/// If ``IncompleteFormat`` is non-null, its value will be set to true if any -/// of the affected ranges were not formatted due to a non-recoverable syntax -/// error. +/// If ``Status`` is non-null, its value will be populated with the status of +/// this formatting attempt. See \c FormattingAttemptStatus. tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, ArrayRef<tooling::Range> Ranges, StringRef FileName = "<stdin>", - bool *IncompleteFormat = nullptr); + FormattingAttemptStatus *Status = nullptr); + +/// \brief Same as above, except if ``IncompleteFormat`` is non-null, its value +/// will be set to true if any of the affected ranges were not formatted due to +/// a non-recoverable syntax error. +tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName, + bool *IncompleteFormat); /// \brief Clean up any erroneous/redundant code in the given \p Ranges in \p /// Code. @@ -1285,6 +1782,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, ArrayRef<tooling::Range> Ranges, StringRef FileName = "<stdin>"); +/// \brief Sort consecutive using declarations in the given \p Ranges in +/// \p Code. +/// +/// Returns the ``Replacements`` that sort the using declarations in all +/// \p Ranges in \p Code. +tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, + StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName = "<stdin>"); + /// \brief Returns the ``LangOpts`` that the formatter expects you to set. /// /// \param Style determines specific settings for lexing mode. @@ -1337,6 +1844,8 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) { return "JavaScript"; case FormatStyle::LK_Proto: return "Proto"; + case FormatStyle::LK_TextProto: + return "TextProto"; default: return "Unknown"; } diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 03961f1a3c..5d04dcd191 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -25,6 +25,7 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" +#include "clang/Frontend/PrecompiledPreamble.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" @@ -51,16 +52,23 @@ class DiagnosticsEngine; class FileEntry; class FileManager; class HeaderSearch; +class InputKind; +class MemoryBufferCache; class Preprocessor; +class PreprocessorOptions; class PCHContainerOperations; class PCHContainerReader; class TargetInfo; class FrontendAction; class ASTDeserializationListener; +namespace vfs { +class FileSystem; +} + /// \brief Utility class for loading a ASTContext from an AST file. /// -class ASTUnit : public ModuleLoader { +class ASTUnit { public: struct StandaloneFixIt { std::pair<unsigned, unsigned> RemoveRange; @@ -84,12 +92,14 @@ private: IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; IntrusiveRefCntPtr<FileManager> FileMgr; IntrusiveRefCntPtr<SourceManager> SourceMgr; + IntrusiveRefCntPtr<MemoryBufferCache> PCMCache; std::unique_ptr<HeaderSearch> HeaderInfo; IntrusiveRefCntPtr<TargetInfo> Target; std::shared_ptr<Preprocessor> PP; IntrusiveRefCntPtr<ASTContext> Ctx; std::shared_ptr<TargetOptions> TargetOpts; std::shared_ptr<HeaderSearchOptions> HSOpts; + std::shared_ptr<PreprocessorOptions> PPOpts; IntrusiveRefCntPtr<ASTReader> Reader; bool HadModuleLoaderFatalFailure; @@ -110,10 +120,13 @@ private: /// LoadFromCommandLine available. std::shared_ptr<CompilerInvocation> Invocation; + /// Fake module loader: the AST unit doesn't need to load any modules. + TrivialModuleLoader ModuleLoader; + // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. - bool OnlyLocalDecls; + bool OnlyLocalDecls; /// \brief Whether to capture any diagnostics produced. bool CaptureDiagnostics; @@ -179,103 +192,23 @@ private: /// some number of calls. unsigned PreambleRebuildCounter; -public: - class PreambleData { - const FileEntry *File; - std::vector<char> Buffer; - mutable unsigned NumLines; - - public: - PreambleData() : File(nullptr), NumLines(0) { } - - void assign(const FileEntry *F, const char *begin, const char *end) { - File = F; - Buffer.assign(begin, end); - NumLines = 0; - } - - void clear() { Buffer.clear(); File = nullptr; NumLines = 0; } - - size_t size() const { return Buffer.size(); } - bool empty() const { return Buffer.empty(); } - - const char *getBufferStart() const { return &Buffer[0]; } - - unsigned getNumLines() const { - if (NumLines) - return NumLines; - countLines(); - return NumLines; - } - - SourceRange getSourceRange(const SourceManager &SM) const { - SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); - return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1)); - } - - private: - void countLines() const; - }; - - const PreambleData &getPreambleData() const { - return Preamble; - } - - /// Data used to determine if a file used in the preamble has been changed. - struct PreambleFileHash { - /// All files have size set. - off_t Size; - - /// Modification time is set for files that are on disk. For memory - /// buffers it is zero. - time_t ModTime; - - /// Memory buffers have MD5 instead of modification time. We don't - /// compute MD5 for on-disk files because we hope that modification time is - /// enough to tell if the file was changed. - llvm::MD5::MD5Result MD5; - - static PreambleFileHash createForFile(off_t Size, time_t ModTime); - static PreambleFileHash - createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); - - friend bool operator==(const PreambleFileHash &LHS, - const PreambleFileHash &RHS); - - friend bool operator!=(const PreambleFileHash &LHS, - const PreambleFileHash &RHS) { - return !(LHS == RHS); - } - }; + /// \brief Cache pairs "filename - source location" + /// + /// Cache contains only source locations from preamble so it is + /// guaranteed that they stay valid when the SourceManager is recreated. + /// This cache is used when loading preambule to increase performance + /// of that loading. It must be cleared when preamble is recreated. + llvm::StringMap<SourceLocation> PreambleSrcLocCache; private: - /// \brief The contents of the preamble that has been precompiled to - /// \c PreambleFile. - PreambleData Preamble; - - /// \brief Whether the preamble ends at the start of a new line. - /// - /// Used to inform the lexer as to whether it's starting at the beginning of - /// a line after skipping the preamble. - bool PreambleEndsAtStartOfLine; - - /// \brief Keeps track of the files that were used when computing the - /// preamble, with both their buffer size and their modification time. - /// - /// If any of the files have changed from one compile to the next, - /// the preamble must be thrown away. - llvm::StringMap<PreambleFileHash> FilesInPreamble; + /// The contents of the preamble. + llvm::Optional<PrecompiledPreamble> Preamble; /// \brief When non-NULL, this is the buffer used to store the contents of /// the main file when it has been padded for use with the precompiled /// preamble. std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer; - /// \brief When non-NULL, this is the buffer used to store the - /// contents of the preamble when it has been padded to build the - /// precompiled preamble. - std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer; - /// \brief The number of warnings that occurred while parsing the preamble. /// /// This value will be used to restore the state of the \c DiagnosticsEngine @@ -299,9 +232,6 @@ private: /// (likely to change while trying to use them). bool UserFilesAreVolatile : 1; - /// \brief The language options used when we load an AST file. - LangOptions ASTFileLangOpts; - static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTUnit &AST, bool CaptureDiagnostics); @@ -417,27 +347,14 @@ private: explicit ASTUnit(bool MainFileIsAST); - void CleanTemporaryFiles(); bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer); - - struct ComputedPreamble { - llvm::MemoryBuffer *Buffer; - std::unique_ptr<llvm::MemoryBuffer> Owner; - unsigned Size; - bool PreambleEndsAtStartOfLine; - ComputedPreamble(llvm::MemoryBuffer *Buffer, - std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size, - bool PreambleEndsAtStartOfLine) - : Buffer(Buffer), Owner(std::move(Owner)), Size(Size), - PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} - }; - ComputedPreamble ComputePreamble(CompilerInvocation &Invocation, - unsigned MaxLines); + std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer, + IntrusiveRefCntPtr<vfs::FileSystem> VFS); std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true, + const CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); @@ -480,7 +397,7 @@ public: }; friend class ConcurrencyCheck; - ~ASTUnit() override; + ~ASTUnit(); bool isMainFileAST() const { return MainFileIsAST; } @@ -510,9 +427,19 @@ public: } const LangOptions &getLangOpts() const { - assert(LangOpts && " ASTUnit does not have language options"); + assert(LangOpts && "ASTUnit does not have language options"); return *LangOpts; } + + const HeaderSearchOptions &getHeaderSearchOpts() const { + assert(HSOpts && "ASTUnit does not have header search options"); + return *HSOpts; + } + + const PreprocessorOptions &getPreprocessorOpts() const { + assert(PPOpts && "ASTUnit does not have preprocessor options"); + return *PPOpts; + } const FileManager &getFileManager() const { return *FileMgr; } FileManager &getFileManager() { return *FileMgr; } @@ -521,18 +448,13 @@ public: IntrusiveRefCntPtr<ASTReader> getASTReader() const; - StringRef getOriginalSourceFileName() { + StringRef getOriginalSourceFileName() const { return OriginalSourceFile; } ASTMutationListener *getASTMutationListener(); ASTDeserializationListener *getDeserializationListener(); - /// \brief Add a temporary file that the ASTUnit depends on. - /// - /// This file will be erased when the ASTUnit is destroyed. - void addTemporaryFile(StringRef TempFile); - bool getOnlyLocalDecls() const { return OnlyLocalDecls; } bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; } @@ -583,12 +505,6 @@ public: void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl<Decl *> &Decls); - /// \brief Add a new top-level declaration, identified by its ID in - /// the precompiled preamble. - void addTopLevelDeclFromPreamble(serialization::DeclID D) { - TopLevelDeclsInPreamble.push_back(D); - } - /// \brief Retrieve a reference to the current top-level name hash value. /// /// Note: This is used internally by the top-level tracking action @@ -608,26 +524,26 @@ public: /// \brief If \p Loc is a loaded location from the preamble, returns /// the corresponding local location of the main file, otherwise it returns /// \p Loc. - SourceLocation mapLocationFromPreamble(SourceLocation Loc); + SourceLocation mapLocationFromPreamble(SourceLocation Loc) const; /// \brief If \p Loc is a local location of the main file but inside the /// preamble chunk, returns the corresponding loaded location from the /// preamble, otherwise it returns \p Loc. - SourceLocation mapLocationToPreamble(SourceLocation Loc); + SourceLocation mapLocationToPreamble(SourceLocation Loc) const; - bool isInPreambleFileID(SourceLocation Loc); - bool isInMainFileID(SourceLocation Loc); - SourceLocation getStartOfMainFileID(); - SourceLocation getEndOfPreambleFileID(); + bool isInPreambleFileID(SourceLocation Loc) const; + bool isInMainFileID(SourceLocation Loc) const; + SourceLocation getStartOfMainFileID() const; + SourceLocation getEndOfPreambleFileID() const; /// \see mapLocationFromPreamble. - SourceRange mapRangeFromPreamble(SourceRange R) { + SourceRange mapRangeFromPreamble(SourceRange R) const { return SourceRange(mapLocationFromPreamble(R.getBegin()), mapLocationFromPreamble(R.getEnd())); } /// \see mapLocationToPreamble. - SourceRange mapRangeToPreamble(SourceRange R) { + SourceRange mapRangeToPreamble(SourceRange R) const { return SourceRange(mapLocationToPreamble(R.getBegin()), mapLocationToPreamble(R.getEnd())); } @@ -691,7 +607,7 @@ public: /// \brief Returns true if the ASTUnit was constructed from a serialized /// module file. - bool isModuleFile(); + bool isModuleFile() const; std::unique_ptr<llvm::MemoryBuffer> getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr); @@ -699,6 +615,9 @@ public: /// \brief Determine what kind of translation unit this AST represents. TranslationUnitKind getTranslationUnitKind() const { return TUKind; } + /// \brief Determine the input kind this AST unit represents. + InputKind getInputKind() const; + /// \brief A mapping from a file name to the memory buffer that stores the /// remapped contents of that file. typedef std::pair<std::string, llvm::MemoryBuffer *> RemappedFile; @@ -709,6 +628,15 @@ public: IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool CaptureDiagnostics, bool UserFilesAreVolatile); + enum WhatToLoad { + /// Load options and the preprocessor state. + LoadPreprocessorOnly, + /// Load the AST, but do not restore Sema state. + LoadASTOnly, + /// Load everything, including Sema. + LoadEverything + }; + /// \brief Create a ASTUnit from an AST file. /// /// \param Filename - The AST file to load. @@ -721,7 +649,7 @@ public: /// \returns - The initialized ASTUnit or null if the AST failed to load. static std::unique_ptr<ASTUnit> LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, bool OnlyLocalDecls = false, ArrayRef<RemappedFile> RemappedFiles = None, bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false, @@ -735,11 +663,17 @@ private: /// of this translation unit should be precompiled, to improve the performance /// of reparsing. Set to zero to disable preambles. /// + /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that + /// preamble is saved to a temporary directory on a RealFileSystem, so in order + /// for it to be loaded correctly, VFS should have access to it(i.e., be an + /// overlay over RealFileSystem). + /// /// \returns \c true if a catastrophic failure occurred (which means that the /// \c ASTUnit itself is invalid), or \c false otherwise. bool LoadFromCompilerInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - unsigned PrecompilePreambleAfterNParses); + unsigned PrecompilePreambleAfterNParses, + IntrusiveRefCntPtr<vfs::FileSystem> VFS); public: @@ -830,6 +764,11 @@ public: /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit /// mainly to allow the caller to see the diagnostics. /// + /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that + /// preamble is saved to a temporary directory on a RealFileSystem, so in order + /// for it to be loaded correctly, VFS should have access to it(i.e., be an + /// overlay over RealFileSystem). RealFileSystem will be used if \p VFS is nullptr. + /// // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. static ASTUnit *LoadFromCommandLine( @@ -844,17 +783,31 @@ public: bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, bool ForSerialization = false, llvm::Optional<StringRef> ModuleFormat = llvm::None, - std::unique_ptr<ASTUnit> *ErrAST = nullptr); + std::unique_ptr<ASTUnit> *ErrAST = nullptr, + IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. /// + /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that + /// preamble is saved to a temporary directory on a RealFileSystem, so in order + /// for it to be loaded correctly, VFS should give an access to this(i.e. be an + /// overlay over RealFileSystem). FileMgr->getVirtualFileSystem() will be used if + /// \p VFS is nullptr. + /// /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, - ArrayRef<RemappedFile> RemappedFiles = None); + ArrayRef<RemappedFile> RemappedFiles = None, + IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr); + + /// \brief Free data that will be re-generated on the next parse. + /// + /// Preamble-related data is not affected. + void ResetForParse(); /// \brief Perform code completion at the given file, line, and /// column within this translation unit. @@ -896,21 +849,6 @@ public: /// /// \returns True if an error occurred, false otherwise. bool serialize(raw_ostream &OS); - - ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, - Module::NameVisibilityKind Visibility, - bool IsInclusionDirective) override { - // ASTUnit doesn't know how to load modules (not that this matters). - return ModuleLoadResult(); - } - - void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, - SourceLocation ImportLoc) override {} - - GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override - { return nullptr; } - bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override - { return 0; } }; } // namespace clang diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index 172380c00e..8f2aae2f14 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -29,7 +29,8 @@ CODEGENOPT(Name, Bits, Default) #endif CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as -CODEGENOPT(CompressDebugSections, 1, 0) ///< -Wa,-compress-debug-sections +ENUM_CODEGENOPT(CompressDebugSections, llvm::DebugCompressionType, 2, + llvm::DebugCompressionType::None) CODEGENOPT(RelaxELFRelocations, 1, 0) ///< -Wa,--mrelax-relocations CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm. CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments. @@ -53,8 +54,11 @@ CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get ///< the pristine IR generated by the ///< frontend. CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers +CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with optnone at O0 CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental ///< pass manager. +CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new + ///< pass manager. CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled. CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls. CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what @@ -65,8 +69,6 @@ CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA. CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO. CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata. CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled. -/// \brief FP_CONTRACT mode (on/off/fast). -ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On) /// \brief Embed Bitcode mode (off/all/bitcode/marker). ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off) CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables @@ -118,6 +120,10 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss. ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is ///< enabled. + +/// A version of Clang that we should attempt to be ABI-compatible with. +ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest) + VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. @@ -139,11 +145,17 @@ CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection ///< in AddressSanitizer +CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping + ///< of globals in AddressSanitizer CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in ///< MemorySanitizer CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection ///< in MemorySanitizer CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. +CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime for + ///< diagnostics. +CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in + ///< CFI icall function signatures CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage ///< instrumentation. CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage @@ -162,9 +174,14 @@ CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing ///< in sanitizer coverage. CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard ///< in sanitizer coverage. +CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters. +CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table. +CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning. +CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers. CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. +CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. @@ -173,9 +190,9 @@ CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled. CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns. CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. -CODEGENOPT(VectorizeBB , 1, 0) ///< Run basic block vectorizer. CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. +CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate. /// Attempt to use register sized accesses to bit-fields in structures, when /// possible. @@ -201,9 +218,14 @@ CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should ///< contain explicit imports for ///< anonymous namespaces +CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the ///< skeleton CU to allow for symbolication ///< of inline stack frames without .dwo files. +CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete + ///< template parameter descriptions in + ///< forward declarations (versus just + ///< including them in the name). CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists. @@ -255,6 +277,10 @@ VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0) /// Whether to report the hotness of the code region for optimization remarks. CODEGENOPT(DiagnosticsWithHotness, 1, 0) +/// The minimum hotness value a diagnostic needs in order to be included in +/// optimization diagnostics. +VALUE_CODEGENOPT(DiagnosticsHotnessThreshold, 32, 0) + /// Whether copy relocations support is available when building as PIE. CODEGENOPT(PIECopyRelocations, 1, 0) @@ -265,6 +291,12 @@ CODEGENOPT(StrictReturn, 1, 1) /// Whether emit extra debug info for sample pgo profile collection. CODEGENOPT(DebugInfoForProfiling, 1, 0) +/// Whether 3-component vector type is preserved. +CODEGENOPT(PreserveVec3Type, 1, 0) + +/// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames. +CODEGENOPT(GnuPubnames, 1, 0) + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index f8f32666c5..71730a21db 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -69,10 +69,21 @@ public: LocalExecTLSModel }; - enum FPContractModeKind { - FPC_Off, // Form fused FP ops only where result will not be affected. - FPC_On, // Form fused FP ops according to FP_CONTRACT rules. - FPC_Fast // Aggressively fuse FP ops (E.g. FMA). + /// Clang versions with different platform ABI conformance. + enum class ClangABI { + /// Attempt to be ABI-compatible with code generated by Clang 3.8.x + /// (SVN r257626). This causes <1 x long long> to be passed in an + /// integer register instead of an SSE register on x64_64. + Ver3_8, + + /// Attempt to be ABI-compatible with code generated by Clang 4.0.x + /// (SVN r291814). This causes move operations to be ignored when + /// determining whether a class type can be passed or returned directly. + Ver4, + + /// Conform to the underlying platform's C and C++ ABIs as closely + /// as we can. + Latest }; enum StructReturnConventionKind { @@ -188,6 +199,11 @@ public: /// importing. std::string ThinLTOIndexFile; + /// Name of a file that can optionally be written with minimized bitcode + /// to be used as input for the ThinLTO thin link step, which only needs + /// the summary and module symbol table (and not, e.g. any debug metadata). + std::string ThinLinkBitcodeFile; + /// A list of file names passed with -fcuda-include-gpubinary options to /// forward to CUDA runtime back-end for incorporating them into host-side /// object file. @@ -219,7 +235,7 @@ public: /// flag. std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern; - /// Set of files definining the rules for the symbol rewriting. + /// Set of files defining the rules for the symbol rewriting. std::vector<std::string> RewriteMapFiles; /// Set of sanitizer checks that are non-fatal (i.e. execution should be diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h index a78c96d23a..f5c1e1a8a6 100644 --- a/include/clang/Frontend/CommandLineSourceLoc.h +++ b/include/clang/Frontend/CommandLineSourceLoc.h @@ -51,6 +51,52 @@ public: } }; +/// A source range that has been parsed on the command line. +struct ParsedSourceRange { + std::string FileName; + /// The starting location of the range. The first element is the line and + /// the second element is the column. + std::pair<unsigned, unsigned> Begin; + /// The ending location of the range. The first element is the line and the + /// second element is the column. + std::pair<unsigned, unsigned> End; + + /// Returns a parsed source range from a string or None if the string is + /// invalid. + /// + /// These source string has the following format: + /// + /// file:start_line:start_column[-end_line:end_column] + /// + /// If the end line and column are omitted, the starting line and columns + /// are used as the end values. + static Optional<ParsedSourceRange> fromString(StringRef Str) { + std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-'); + unsigned EndLine, EndColumn; + bool HasEndLoc = false; + if (!RangeSplit.second.empty()) { + std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':'); + if (Split.first.getAsInteger(10, EndLine) || + Split.second.getAsInteger(10, EndColumn)) { + // The string does not end in end_line:end_column, so the '-' + // probably belongs to the filename which menas the whole + // string should be parsed. + RangeSplit.first = Str; + } else + HasEndLoc = true; + } + auto Begin = ParsedSourceLocation::FromString(RangeSplit.first); + if (Begin.FileName.empty()) + return None; + if (!HasEndLoc) { + EndLine = Begin.Line; + EndColumn = Begin.Column; + } + return ParsedSourceRange{std::move(Begin.FileName), + {Begin.Line, Begin.Column}, + {EndLine, EndColumn}}; + } +}; } namespace llvm { diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 91d9198ddf..90a9501475 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -44,6 +44,7 @@ class ExternalASTSource; class FileEntry; class FileManager; class FrontendAction; +class MemoryBufferCache; class Module; class Preprocessor; class Sema; @@ -90,6 +91,9 @@ class CompilerInstance : public ModuleLoader { /// The source manager. IntrusiveRefCntPtr<SourceManager> SourceMgr; + /// The cache of PCM files. + IntrusiveRefCntPtr<MemoryBufferCache> PCMCache; + /// The preprocessor. std::shared_ptr<Preprocessor> PP; @@ -132,6 +136,13 @@ class CompilerInstance : public ModuleLoader { /// along with the module map llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules; + /// \brief The set of top-level modules that has already been built on the + /// fly as part of this overall compilation action. + std::map<std::string, std::string> BuiltModules; + + /// Should we delete the BuiltModules when we're done? + bool DeleteBuiltModules = true; + /// \brief The location of the module-import keyword for the last module /// import. SourceLocation LastModuleImportLoc; @@ -178,7 +189,7 @@ public: explicit CompilerInstance( std::shared_ptr<PCHContainerOperations> PCHContainerOps = std::make_shared<PCHContainerOperations>(), - bool BuildingModule = false); + MemoryBufferCache *SharedPCMCache = nullptr); ~CompilerInstance() override; /// @name High-Level Operations @@ -629,7 +640,9 @@ public: const CodeGenOptions *CodeGenOpts = nullptr); /// Create the file manager and replace any existing one with it. - void createFileManager(); + /// + /// \return The new file manager on success, or null on failure. + FileManager *createFileManager(); /// Create the source manager and replace any existing one with it. void createSourceManager(FileManager &FileMgr); @@ -658,6 +671,8 @@ public: bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerReader &PCHContainerRdr, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, + DependencyFileGenerator *DependencyFile, + ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex); @@ -767,6 +782,9 @@ public: Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override; + void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, + StringRef Source) override; + void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) override; @@ -783,6 +801,8 @@ public: } void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS); + + MemoryBufferCache &getPCMCache() const { return *PCMCache; } }; } // end namespace clang diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index cef7f73eca..8c4c932190 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -225,6 +225,11 @@ IntrusiveRefCntPtr<vfs::FileSystem> createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags); +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<vfs::FileSystem> BaseFS); + } // end namespace clang #endif diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h index 2588feb2b8..e453d7db62 100644 --- a/include/clang/Frontend/DiagnosticRenderer.h +++ b/include/clang/Frontend/DiagnosticRenderer.h @@ -70,33 +70,27 @@ protected: DiagnosticOptions *DiagOpts); virtual ~DiagnosticRenderer(); - - virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, + + virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, - const SourceManager *SM, DiagOrStoredDiag Info) = 0; - - virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + + virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) = 0; + ArrayRef<CharSourceRange> Ranges) = 0; - virtual void emitCodeContext(SourceLocation Loc, + virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) = 0; - - virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, - const SourceManager &SM) = 0; - virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) = 0; - virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) = 0; + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints) = 0; + + virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) = 0; + virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) = 0; + virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) = 0; virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) {} @@ -106,25 +100,21 @@ protected: private: void emitBasicNote(StringRef Message); - void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc, - DiagnosticsEngine::Level Level, const SourceManager &SM); - void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM); - void emitImportStack(SourceLocation Loc, const SourceManager &SM); - void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName, - const SourceManager &SM); + void emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level); + void emitIncludeStackRecursively(FullSourceLoc Loc); + void emitImportStack(FullSourceLoc Loc); + void emitImportStackRecursively(FullSourceLoc Loc, StringRef ModuleName); void emitModuleBuildStack(const SourceManager &SM); - void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints, - const SourceManager &SM); - void emitSingleMacroExpansion(SourceLocation Loc, + void emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints); + void emitSingleMacroExpansion(FullSourceLoc Loc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM); - void emitMacroExpansions(SourceLocation Loc, - DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges); + void emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM); + ArrayRef<FixItHint> Hints); + public: /// \brief Emit a diagnostic. /// @@ -138,12 +128,9 @@ public: /// \param Message The diagnostic message to emit. /// \param Ranges The underlined ranges for this code snippet. /// \param FixItHints The FixIt hints active for this diagnostic. - /// \param SM The SourceManager; will be null if the diagnostic came from the - /// frontend, thus \p Loc will be invalid. - void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, + void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints, - const SourceManager *SM, DiagOrStoredDiag D = (Diagnostic *)nullptr); void emitStoredDiagnostic(StoredDiagnostic &Diag); @@ -159,19 +146,15 @@ public: ~DiagnosticNoteRenderer() override; - void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, - const SourceManager &SM) override; + void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override; - void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) override; + void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) override; - void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) override; + void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) override; - virtual void emitNote(SourceLocation Loc, StringRef Message, - const SourceManager *SM) = 0; + virtual void emitNote(FullSourceLoc Loc, StringRef Message) = 0; }; } // end clang namespace #endif diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index 384499a3d8..7ae6173512 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -76,8 +76,7 @@ protected: /// /// \return True on success; on failure ExecutionAction() and /// EndSourceFileAction() will not be called. - virtual bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { + virtual bool BeginSourceFileAction(CompilerInstance &CI) { return true; } @@ -146,6 +145,8 @@ public: return *CurrentASTUnit; } + Module *getCurrentModule() const; + std::unique_ptr<ASTUnit> takeCurrentASTUnit() { return std::move(CurrentASTUnit); } @@ -174,10 +175,10 @@ public: virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; } /// \brief Does this action support use with PCH? - virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); } + virtual bool hasPCHSupport() const { return true; } /// \brief Does this action support use with AST files? - virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); } + virtual bool hasASTFileSupport() const { return true; } /// \brief Does this action support use with IR files? virtual bool hasIRSupport() const { return false; } @@ -289,7 +290,7 @@ protected: std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; bool BeginInvocation(CompilerInstance &CI) override; - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; void EndSourceFileAction() override; diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 778b40b15d..c45aeaa208 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -91,7 +91,7 @@ public: ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile, std::string &Sysroot, std::string &OutputFile); - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; }; class GenerateModuleAction : public ASTFrontendAction { @@ -99,8 +99,6 @@ class GenerateModuleAction : public ASTFrontendAction { CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0; protected: - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; - std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; @@ -112,25 +110,16 @@ protected: }; class GenerateModuleFromModuleMapAction : public GenerateModuleAction { - clang::Module *Module = nullptr; - const FileEntry *ModuleMapForUniquing = nullptr; - bool IsSystem = false; - private: - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; std::unique_ptr<raw_pwrite_stream> CreateOutputFile(CompilerInstance &CI, StringRef InFile) override; - -public: - GenerateModuleFromModuleMapAction() {} - GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem) - : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {} }; class GenerateModuleInterfaceAction : public GenerateModuleAction { private: - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; std::unique_ptr<raw_pwrite_stream> CreateOutputFile(CompilerInstance &CI, StringRef InFile) override; @@ -192,8 +181,7 @@ protected: std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; - bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; void EndSourceFileAction() override; diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 4fd0f82a3a..5192a3774c 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -23,6 +23,7 @@ class MemoryBuffer; } namespace clang { +class FileEntry; namespace frontend { enum ActionKind { @@ -62,46 +63,89 @@ namespace frontend { }; } -enum InputKind { - IK_None, - IK_Asm, - IK_C, - IK_CXX, - IK_ObjC, - IK_ObjCXX, - IK_PreprocessedC, - IK_PreprocessedCXX, - IK_PreprocessedObjC, - IK_PreprocessedObjCXX, - IK_OpenCL, - IK_CUDA, - IK_PreprocessedCuda, - IK_RenderScript, - IK_AST, - IK_LLVM_IR -}; +/// The kind of a file that we've been handed as an input. +class InputKind { +private: + unsigned Lang : 4; + unsigned Fmt : 3; + unsigned Preprocessed : 1; + +public: + /// The language for the input, used to select and validate the language + /// standard and possible actions. + enum Language { + Unknown, + + /// Assembly: we accept this only so that we can preprocess it. + Asm, + + /// LLVM IR: we accept this so that we can run the optimizer on it, + /// and compile it to assembly or object code. + LLVM_IR, + + ///@{ Languages that the frontend can parse and compile. + C, + CXX, + ObjC, + ObjCXX, + OpenCL, + CUDA, + RenderScript, + ///@} + }; + + /// The input file format. + enum Format { + Source, + ModuleMap, + Precompiled + }; + + constexpr InputKind(Language L = Unknown, Format F = Source, + bool PP = false) + : Lang(L), Fmt(F), Preprocessed(PP) {} + + Language getLanguage() const { return static_cast<Language>(Lang); } + Format getFormat() const { return static_cast<Format>(Fmt); } + bool isPreprocessed() const { return Preprocessed; } + /// Is the input kind fully-unknown? + bool isUnknown() const { return Lang == Unknown && Fmt == Source; } + + /// Is the language of the input some dialect of Objective-C? + bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; } + + InputKind getPreprocessed() const { + return InputKind(getLanguage(), getFormat(), true); + } + InputKind withFormat(Format F) const { + return InputKind(getLanguage(), F, isPreprocessed()); + } +}; /// \brief An input file for the front end. class FrontendInputFile { /// \brief The file name, or "-" to read from standard input. std::string File; - llvm::MemoryBuffer *Buffer; + /// The input, if it comes from a buffer rather than a file. This object + /// does not own the buffer, and the caller is responsible for ensuring + /// that it outlives any users. + llvm::MemoryBuffer *Buffer = nullptr; /// \brief The kind of input, e.g., C source, AST file, LLVM IR. InputKind Kind; /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input). - bool IsSystem; + bool IsSystem = false; public: - FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } + FrontendInputFile() { } FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) - : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } - FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, + : File(File.str()), Kind(Kind), IsSystem(IsSystem) { } + FrontendInputFile(llvm::MemoryBuffer *Buffer, InputKind Kind, bool IsSystem = false) - : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { } + : Buffer(Buffer), Kind(Kind), IsSystem(IsSystem) { } InputKind getKind() const { return Kind; } bool isSystem() const { return IsSystem; } @@ -109,13 +153,7 @@ public: bool isEmpty() const { return File.empty() && Buffer == nullptr; } bool isFile() const { return !isBuffer(); } bool isBuffer() const { return Buffer != nullptr; } - bool isPreprocessed() const { - return Kind == IK_PreprocessedC || - Kind == IK_PreprocessedCXX || - Kind == IK_PreprocessedObjC || - Kind == IK_PreprocessedObjCXX || - Kind == IK_PreprocessedCuda; - } + bool isPreprocessed() const { return Kind.isPreprocessed(); } StringRef getFile() const { assert(isFile()); @@ -224,6 +262,10 @@ public: /// The input files and their types. std::vector<FrontendInputFile> Inputs; + /// When the input is a module map, the original module map file from which + /// that map was inferred, if any (for umbrella modules). + std::string OriginalModuleMap; + /// The output file, if any. std::string OutputFile; @@ -278,8 +320,8 @@ public: /// \brief Auxiliary triple for CUDA compilation. std::string AuxTriple; - /// \brief If non-empty, search the pch input file as it was a header - // included by this file. + /// \brief If non-empty, search the pch input file as if it was a header + /// included by this file. std::string FindPchSource; /// Filename to write statistics to. @@ -299,10 +341,10 @@ public: {} /// getInputKindForExtension - Return the appropriate input kind for a file - /// extension. For example, "c" would return IK_C. + /// extension. For example, "c" would return InputKind::C. /// - /// \return The input kind for the extension, or IK_None if the extension is - /// not recognized. + /// \return The input kind for the extension, or InputKind::Unknown if the + /// extension is not recognized. static InputKind getInputKindForExtension(StringRef Extension); }; diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h index 5ead90f007..6731e08bca 100644 --- a/include/clang/Frontend/LangStandard.h +++ b/include/clang/Frontend/LangStandard.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_FRONTEND_LANGSTANDARD_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/FrontendOptions.h" #include "llvm/ADT/StringRef.h" namespace clang { @@ -19,13 +20,13 @@ namespace frontend { enum LangFeatures { LineComment = (1 << 0), - C89 = (1 << 1), - C99 = (1 << 2), - C11 = (1 << 3), - CPlusPlus = (1 << 4), - CPlusPlus11 = (1 << 5), - CPlusPlus14 = (1 << 6), - CPlusPlus1z = (1 << 7), + C99 = (1 << 1), + C11 = (1 << 2), + CPlusPlus = (1 << 3), + CPlusPlus11 = (1 << 4), + CPlusPlus14 = (1 << 5), + CPlusPlus1z = (1 << 6), + CPlusPlus2a = (1 << 7), Digraphs = (1 << 8), GNUMode = (1 << 9), HexFloat = (1 << 10), @@ -39,7 +40,7 @@ enum LangFeatures { /// standard. struct LangStandard { enum Kind { -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ lang_##id, #include "clang/Frontend/LangStandards.def" lang_unspecified @@ -48,6 +49,7 @@ struct LangStandard { const char *ShortName; const char *Description; unsigned Flags; + InputKind::Language Language; public: /// getName - Get the name of this standard. @@ -56,12 +58,12 @@ public: /// getDescription - Get the description of this standard. const char *getDescription() const { return Description; } + /// Get the language that this standard describes. + InputKind::Language getLanguage() const { return Language; } + /// Language supports '//' comments. bool hasLineComments() const { return Flags & frontend::LineComment; } - /// isC89 - Language is a superset of C89. - bool isC89() const { return Flags & frontend::C89; } - /// isC99 - Language is a superset of C99. bool isC99() const { return Flags & frontend::C99; } @@ -80,6 +82,10 @@ public: /// isCPlusPlus1z - Language is a C++17 variant (or later). bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; } + /// isCPlusPlus2a - Language is a post-C++17 variant (or later). + bool isCPlusPlus2a() const { return Flags & frontend::CPlusPlus2a; } + + /// hasDigraphs - Language supports digraphs. bool hasDigraphs() const { return Flags & frontend::Digraphs; } diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def index 425ac84bf6..a019d63922 100644 --- a/include/clang/Frontend/LangStandards.def +++ b/include/clang/Frontend/LangStandards.def @@ -11,10 +11,11 @@ #error "LANGSTANDARD must be defined before including this file" #endif -/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES) /// /// \param IDENT - The name of the standard as a C++ identifier. /// \param NAME - The name of the standard. +/// \param LANG - The InputKind::Language for which this is a standard. /// \param DESC - A short description of the standard. /// \param FEATURES - The standard features as flags, these are enums from the /// clang::frontend namespace, which is assumed to be be available. @@ -23,146 +24,138 @@ /// \param IDENT - The name of the standard as a C++ identifier. /// \param ALIAS - The alias of the standard. +/// LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) +/// Same as LANGSTANDARD_ALIAS, but for a deprecated alias. + #ifndef LANGSTANDARD_ALIAS #define LANGSTANDARD_ALIAS(IDENT, ALIAS) #endif +#ifndef LANGSTANDARD_ALIAS_DEPR +#define LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) LANGSTANDARD_ALIAS(IDENT, ALIAS) +#endif + // C89-ish modes. LANGSTANDARD(c89, "c89", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(c90, "c90", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(iso9899_1990, "iso9899:1990", - "ISO C 1990", - C89 | ImplicitInt) + C, "ISO C 1990", + ImplicitInt) +LANGSTANDARD_ALIAS(c89, "c90") +LANGSTANDARD_ALIAS(c89, "iso9899:1990") LANGSTANDARD(c94, "iso9899:199409", - "ISO C 1990 with amendment 1", - C89 | Digraphs | ImplicitInt) + C, "ISO C 1990 with amendment 1", + Digraphs | ImplicitInt) LANGSTANDARD(gnu89, "gnu89", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) -LANGSTANDARD(gnu90, "gnu90", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) + C, "ISO C 1990 with GNU extensions", + LineComment | Digraphs | GNUMode | ImplicitInt) +LANGSTANDARD_ALIAS(gnu89, "gnu90") // C99-ish modes LANGSTANDARD(c99, "c99", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(c9x, "c9x", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_1999, - "iso9899:1999", "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_199x, - "iso9899:199x", "ISO C 1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c99, "iso9899:1999") +LANGSTANDARD_ALIAS_DEPR(c99, "c9x") +LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x") LANGSTANDARD(gnu99, "gnu99", - "ISO C 1999 with GNU extensions", - LineComment | C99 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu9x, "gnu9x", - "ISO C 1999 with GNU extensions", + C, "ISO C 1999 with GNU extensions", LineComment | C99 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x") // C11 modes LANGSTANDARD(c11, "c11", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(c1x, "c1x", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_2011, - "iso9899:2011", "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_201x, - "iso9899:201x", "ISO C 2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c11, "iso9899:2011") +LANGSTANDARD_ALIAS_DEPR(c11, "c1x") +LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x") LANGSTANDARD(gnu11, "gnu11", - "ISO C 2011 with GNU extensions", - LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu1x, "gnu1x", - "ISO C 2011 with GNU extensions", + C, "ISO C 2011 with GNU extensions", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") // C++ modes LANGSTANDARD(cxx98, "c++98", - "ISO C++ 1998 with amendments", - LineComment | CPlusPlus | Digraphs) -LANGSTANDARD(cxx03, "c++03", - "ISO C++ 1998 with amendments", + CXX, "ISO C++ 1998 with amendments", LineComment | CPlusPlus | Digraphs) +LANGSTANDARD_ALIAS(cxx98, "c++03") + LANGSTANDARD(gnucxx98, "gnu++98", - "ISO C++ 1998 with amendments and GNU extensions", + CXX, "ISO C++ 1998 with amendments and GNU extensions", LineComment | CPlusPlus | Digraphs | GNUMode) +LANGSTANDARD_ALIAS(gnucxx98, "gnu++03") -LANGSTANDARD(cxx0x, "c++0x", - "ISO C++ 2011 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs) LANGSTANDARD(cxx11, "c++11", - "ISO C++ 2011 with amendments", + CXX, "ISO C++ 2011 with amendments", LineComment | CPlusPlus | CPlusPlus11 | Digraphs) -LANGSTANDARD(gnucxx0x, "gnu++0x", - "ISO C++ 2011 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) -LANGSTANDARD(gnucxx11, "gnu++11", +LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x") + +LANGSTANDARD(gnucxx11, "gnu++11", CXX, "ISO C++ 2011 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x") -LANGSTANDARD(cxx1y, "c++1y", - "ISO C++ 2014 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) LANGSTANDARD(cxx14, "c++14", - "ISO C++ 2014 with amendments", + CXX, "ISO C++ 2014 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) -LANGSTANDARD(gnucxx1y, "gnu++1y", - "ISO C++ 2014 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | - GNUMode) +LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y") + LANGSTANDARD(gnucxx14, "gnu++14", - "ISO C++ 2014 with amendments and GNU extensions", + CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y") -LANGSTANDARD(cxx1z, "c++1z", - "Working draft for ISO C++ 2017", +LANGSTANDARD(cxx17, "c++17", + CXX, "ISO C++ 2017 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat) -LANGSTANDARD(gnucxx1z, "gnu++1z", - "Working draft for ISO C++ 2017 with GNU extensions", +LANGSTANDARD_ALIAS_DEPR(cxx17, "c++1z") + +LANGSTANDARD(gnucxx17, "gnu++17", + CXX, "ISO C++ 2017 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z") + +LANGSTANDARD(cxx2a, "c++2a", + CXX, "Working draft for ISO C++ 2020", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + CPlusPlus2a | Digraphs | HexFloat) + +LANGSTANDARD(gnucxx2a, "gnu++2a", + CXX, "Working draft for ISO C++ 2020 with GNU extensions", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + CPlusPlus2a | Digraphs | HexFloat | GNUMode) // OpenCL -LANGSTANDARD(opencl, "cl", - "OpenCL 1.0", +LANGSTANDARD(opencl10, "cl1.0", + OpenCL, "OpenCL 1.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) +LANGSTANDARD_ALIAS_DEPR(opencl10, "cl") + LANGSTANDARD(opencl11, "cl1.1", - "OpenCL 1.1", + OpenCL, "OpenCL 1.1", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl12, "cl1.2", - "OpenCL 1.2", + OpenCL, "OpenCL 1.2", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl20, "cl2.0", - "OpenCL 2.0", + OpenCL, "OpenCL 2.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) -LANGSTANDARD_ALIAS(opencl, "CL") -LANGSTANDARD_ALIAS(opencl11, "CL1.1") -LANGSTANDARD_ALIAS(opencl12, "CL1.2") -LANGSTANDARD_ALIAS(opencl20, "CL2.0") +LANGSTANDARD_ALIAS_DEPR(opencl10, "CL") +LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") +LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2") +LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0") // CUDA -LANGSTANDARD(cuda, "cuda", - "NVIDIA CUDA(tm)", +LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", LineComment | CPlusPlus | Digraphs) #undef LANGSTANDARD #undef LANGSTANDARD_ALIAS - +#undef LANGSTANDARD_ALIAS_DEPR diff --git a/include/clang/Frontend/PrecompiledPreamble.h b/include/clang/Frontend/PrecompiledPreamble.h new file mode 100644 index 0000000000..6b0b6261e4 --- /dev/null +++ b/include/clang/Frontend/PrecompiledPreamble.h @@ -0,0 +1,236 @@ +//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper class to build precompiled preamble. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H +#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H + +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/MD5.h" +#include <memory> +#include <system_error> +#include <type_traits> + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { +namespace vfs { +class FileSystem; +} + +class CompilerInstance; +class CompilerInvocation; +class DeclGroupRef; +class PCHContainerOperations; + +/// \brief Runs lexer to compute suggested preamble bounds. +PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, + llvm::MemoryBuffer *Buffer, + unsigned MaxLines); + +class PreambleCallbacks; + +/// A class holding a PCH and all information to check whether it is valid to +/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and +/// CanReusePreamble + AddImplicitPreamble to make use of it. +class PrecompiledPreamble { + class TempPCHFile; + struct PreambleFileHash; + +public: + /// \brief Try to build PrecompiledPreamble for \p Invocation. See + /// BuildPreambleError for possible error codes. + /// + /// \param Invocation Original CompilerInvocation with options to compile the + /// file. + /// + /// \param MainFileBuffer Buffer with the contents of the main file. + /// + /// \param Bounds Bounds of the preamble, result of calling + /// ComputePreambleBounds. + /// + /// \param Diagnostics Diagnostics engine to be used while building the + /// preamble. + /// + /// \param VFS An instance of vfs::FileSystem to be used for file + /// accesses. + /// + /// \param PCHContainerOps An instance of PCHContainerOperations. + /// + /// \param Callbacks A set of callbacks to be executed when building + /// the preamble. + static llvm::ErrorOr<PrecompiledPreamble> + Build(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + PreambleCallbacks &Callbacks); + + PrecompiledPreamble(PrecompiledPreamble &&) = default; + PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; + + /// PreambleBounds used to build the preamble. + PreambleBounds getBounds() const; + + /// The temporary file path at which the preamble PCH was placed. + StringRef GetPCHPath() const { return PCHFile.getFilePath(); } + + /// Check whether PrecompiledPreamble can be reused for the new contents(\p + /// MainFileBuffer) of the main file. + bool CanReuse(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + vfs::FileSystem *VFS) const; + + /// Changes options inside \p CI to use PCH from this preamble. Also remaps + /// main file to \p MainFileBuffer. + void AddImplicitPreamble(CompilerInvocation &CI, + llvm::MemoryBuffer *MainFileBuffer) const; + +private: + PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes, + bool PreambleEndsAtStartOfLine, + llvm::StringMap<PreambleFileHash> FilesInPreamble); + + /// A temp file that would be deleted on destructor call. If destructor is not + /// called for any reason, the file will be deleted at static objects' + /// destruction. + /// An assertion will fire if two TempPCHFiles are created with the same name, + /// so it's not intended to be used outside preamble-handling. + class TempPCHFile { + public: + // A main method used to construct TempPCHFile. + static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile(); + + /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file. + static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix, + StringRef Suffix); + /// Create a new instance of TemporaryFile for file at \p Path. Use with + /// extreme caution, there's an assertion checking that there's only a + /// single instance of TempPCHFile alive for each path. + static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path); + + private: + TempPCHFile(std::string FilePath); + + public: + TempPCHFile(TempPCHFile &&Other); + TempPCHFile &operator=(TempPCHFile &&Other); + + TempPCHFile(const TempPCHFile &) = delete; + ~TempPCHFile(); + + /// A path where temporary file is stored. + llvm::StringRef getFilePath() const; + + private: + void RemoveFileIfPresent(); + + private: + llvm::Optional<std::string> FilePath; + }; + + /// Data used to determine if a file used in the preamble has been changed. + struct PreambleFileHash { + /// All files have size set. + off_t Size = 0; + + /// Modification time is set for files that are on disk. For memory + /// buffers it is zero. + time_t ModTime = 0; + + /// Memory buffers have MD5 instead of modification time. We don't + /// compute MD5 for on-disk files because we hope that modification time is + /// enough to tell if the file was changed. + llvm::MD5::MD5Result MD5 = {}; + + static PreambleFileHash createForFile(off_t Size, time_t ModTime); + static PreambleFileHash + createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); + + friend bool operator==(const PreambleFileHash &LHS, + const PreambleFileHash &RHS) { + return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && + LHS.MD5 == RHS.MD5; + } + friend bool operator!=(const PreambleFileHash &LHS, + const PreambleFileHash &RHS) { + return !(LHS == RHS); + } + }; + + /// Manages the lifetime of temporary file that stores a PCH. + TempPCHFile PCHFile; + /// Keeps track of the files that were used when computing the + /// preamble, with both their buffer size and their modification time. + /// + /// If any of the files have changed from one compile to the next, + /// the preamble must be thrown away. + llvm::StringMap<PreambleFileHash> FilesInPreamble; + /// The contents of the file that was used to precompile the preamble. Only + /// contains first PreambleBounds::Size bytes. Used to compare if the relevant + /// part of the file has not changed, so that preamble can be reused. + std::vector<char> PreambleBytes; + /// See PreambleBounds::PreambleEndsAtStartOfLine + bool PreambleEndsAtStartOfLine; +}; + +/// A set of callbacks to gather useful information while building a preamble. +class PreambleCallbacks { +public: + virtual ~PreambleCallbacks() = default; + + /// Called after FrontendAction::Execute(), but before + /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of + /// various CompilerInstance fields before they are destroyed. + virtual void AfterExecute(CompilerInstance &CI); + /// Called after PCH has been emitted. \p Writer may be used to retrieve + /// information about AST, serialized in PCH. + virtual void AfterPCHEmitted(ASTWriter &Writer); + /// Called for each TopLevelDecl. + /// NOTE: To allow more flexibility a custom ASTConsumer could probably be + /// used instead, but having only this method allows a simpler API. + virtual void HandleTopLevelDecl(DeclGroupRef DG); + /// Called for each macro defined in the Preamble. + /// NOTE: To allow more flexibility a custom PPCallbacks could probably be + /// used instead, but having only this method allows a simpler API. + virtual void HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD); +}; + +enum class BuildPreambleError { + PreambleIsEmpty = 1, + CouldntCreateTempFile, + CouldntCreateTargetInfo, + CouldntCreateVFSOverlay, + BeginSourceFileFailed, + CouldntEmitPCH +}; + +class BuildPreambleErrorCategory final : public std::error_category { +public: + const char *name() const noexcept override; + std::string message(int condition) const override; +}; + +std::error_code make_error_code(BuildPreambleError Error); +} // namespace clang + +namespace std { +template <> +struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {}; +} // namespace std + +#endif diff --git a/include/clang/Frontend/PreprocessorOutputOptions.h b/include/clang/Frontend/PreprocessorOutputOptions.h index 3261b66538..94afcd06a3 100644 --- a/include/clang/Frontend/PreprocessorOutputOptions.h +++ b/include/clang/Frontend/PreprocessorOutputOptions.h @@ -24,6 +24,7 @@ public: unsigned ShowMacros : 1; ///< Print macro definitions. unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output. unsigned RewriteIncludes : 1; ///< Preprocess include directives only. + unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules. public: PreprocessorOutputOptions() { @@ -35,6 +36,7 @@ public: ShowMacros = 0; ShowIncludeDirectives = 0; RewriteIncludes = 0; + RewriteImports = 0; } }; diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h index 9b108c28bd..1bbfe9fa02 100644 --- a/include/clang/Frontend/TextDiagnostic.h +++ b/include/clang/Frontend/TextDiagnostic.h @@ -75,44 +75,35 @@ public: unsigned Columns, bool ShowColors); protected: - void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc, - DiagnosticsEngine::Level Level, - StringRef Message, + void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, - const SourceManager *SM, DiagOrStoredDiag D) override; - void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges, - const SourceManager &SM) override; - - void emitCodeContext(SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) override { - emitSnippetAndCaret(Loc, Level, Ranges, Hints, SM); + ArrayRef<CharSourceRange> Ranges) override; + + void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints) override { + emitSnippetAndCaret(Loc, Level, Ranges, Hints); } - void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, - const SourceManager &SM) override; + void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override; - void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) override; + void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) override; - void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, - StringRef ModuleName, - const SourceManager &SM) override; + void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, + StringRef ModuleName) override; private: void emitFilename(StringRef Filename, const SourceManager &SM); - void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM); + void emitSnippetAndCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints); void emitSnippet(StringRef SourceLine); diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index 0ee46846c8..8ccc31982d 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -184,10 +184,11 @@ createChainedIncludesSource(CompilerInstance &CI, /// /// \return A CompilerInvocation, or 0 if none was built for the given /// argument vector. -std::unique_ptr<CompilerInvocation> -createInvocationFromCommandLine(ArrayRef<const char *> Args, - IntrusiveRefCntPtr<DiagnosticsEngine> Diags = - IntrusiveRefCntPtr<DiagnosticsEngine>()); +std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine( + ArrayRef<const char *> Args, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + IntrusiveRefCntPtr<DiagnosticsEngine>(), + IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr); /// Return the value of the last argument as an integer, or a default. If Diags /// is non-null, emits an error if the argument is given, but non-integral. diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h index 475f07f9dc..8d71fb98b0 100644 --- a/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -176,7 +176,8 @@ public: : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); - assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); + assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) && + "DiagnosticLoc is invalid!"); } private: diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h index eb718d782d..ae591364f2 100644 --- a/include/clang/Index/IndexSymbol.h +++ b/include/clang/Index/IndexSymbol.h @@ -53,12 +53,14 @@ enum class SymbolKind : uint8_t { ConversionFunction, Parameter, + Using, }; enum class SymbolLanguage { C, ObjC, CXX, + Swift, }; /// Language specific sub-kinds. @@ -68,6 +70,8 @@ enum class SymbolSubKind { CXXMoveConstructor, AccessorGetter, AccessorSetter, + UsingTypename, + UsingValue, }; /// Set of properties that provide additional info about a symbol. @@ -106,8 +110,9 @@ enum class SymbolRole : uint32_t { RelationAccessorOf = 1 << 15, RelationContainedBy = 1 << 16, RelationIBTypeOf = 1 << 17, + RelationSpecializationOf = 1 << 18, }; -static const unsigned SymbolRoleBitNum = 18; +static const unsigned SymbolRoleBitNum = 19; typedef unsigned SymbolRoleSet; /// Represents a relation to another symbol for a symbol occurrence. @@ -132,6 +137,8 @@ bool isFunctionLocalSymbol(const Decl *D); void applyForEachSymbolRole(SymbolRoleSet Roles, llvm::function_ref<void(SymbolRole)> Fn); +bool applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, + llvm::function_ref<bool(SymbolRole)> Fn); void printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS); /// \returns true if no name was printed, false otherwise. diff --git a/include/clang/Index/IndexingAction.h b/include/clang/Index/IndexingAction.h index 8eed33c612..fb703be4e5 100644 --- a/include/clang/Index/IndexingAction.h +++ b/include/clang/Index/IndexingAction.h @@ -11,11 +11,14 @@ #define LLVM_CLANG_INDEX_INDEXINGACTION_H #include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include <memory> namespace clang { + class ASTContext; class ASTReader; class ASTUnit; + class Decl; class FrontendAction; namespace serialization { @@ -47,8 +50,11 @@ void indexASTUnit(ASTUnit &Unit, std::shared_ptr<IndexDataConsumer> DataConsumer, IndexingOptions Opts); -void indexModuleFile(serialization::ModuleFile &Mod, - ASTReader &Reader, +void indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts); + +void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, std::shared_ptr<IndexDataConsumer> DataConsumer, IndexingOptions Opts); diff --git a/include/clang/Index/USRGeneration.h b/include/clang/Index/USRGeneration.h index 61f2c9d1ff..8c661bd63c 100644 --- a/include/clang/Index/USRGeneration.h +++ b/include/clang/Index/USRGeneration.h @@ -30,10 +30,14 @@ static inline StringRef getUSRSpacePrefix() { bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf); /// \brief Generate a USR fragment for an Objective-C class. -void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS); +void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS, + StringRef ExtSymbolDefinedIn = "", + StringRef CategoryContextExtSymbolDefinedIn = ""); /// \brief Generate a USR fragment for an Objective-C class category. -void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS); +void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS, + StringRef ClsExtSymbolDefinedIn = "", + StringRef CatExtSymbolDefinedIn = ""); /// \brief Generate a USR fragment for an Objective-C instance variable. The /// complete USR can be created by concatenating the USR for the @@ -48,7 +52,15 @@ void generateUSRForObjCMethod(StringRef Sel, bool IsInstanceMethod, void generateUSRForObjCProperty(StringRef Prop, bool isClassProp, raw_ostream &OS); /// \brief Generate a USR fragment for an Objective-C protocol. -void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS); +void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS, + StringRef ExtSymbolDefinedIn = ""); + +/// Generate USR fragment for a global (non-nested) enum. +void generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS, + StringRef ExtSymbolDefinedIn = ""); + +/// Generate a USR fragment for an enum constant. +void generateUSRForEnumConstant(StringRef EnumConstantName, raw_ostream &OS); /// \brief Generate a USR for a macro, including the USR prefix. /// diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index 51983b9ab5..126bbdfc13 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -47,7 +47,7 @@ struct HeaderFileInfo { /// whether it is C++ clean or not. This can be set by the include paths or /// by \#pragma gcc system_header. This is an instance of /// SrcMgr::CharacteristicKind. - unsigned DirInfo : 2; + unsigned DirInfo : 3; /// \brief Whether this header file info was supplied by an external source, /// and has not changed since. @@ -375,13 +375,16 @@ public: /// \param SuggestedModule If non-null, and the file found is semantically /// part of a known module, this will be set to the module that should /// be imported instead of preprocessing/parsing the file found. + /// + /// \param IsMapped If non-null, and the search involved header maps, set to + /// true. const FileEntry *LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false, bool BuildSystemModule = false); + bool *IsMapped, bool SkipCache = false, bool BuildSystemModule = false); /// \brief Look up a subframework for the specified \#include file. /// @@ -468,29 +471,41 @@ public: /// \brief Get filenames for all registered header maps. void getHeaderMapFileNames(SmallVectorImpl<std::string> &Names) const; - /// \brief Retrieve the name of the module file that should be used to - /// load the given module. + /// \brief Retrieve the name of the cached module file that should be used + /// to load the given module. /// /// \param Module The module whose module file name will be returned. /// /// \returns The name of the module file that corresponds to this module, /// or an empty string if this module does not correspond to any module file. - std::string getModuleFileName(Module *Module); + std::string getCachedModuleFileName(Module *Module); - /// \brief Retrieve the name of the module file that should be used to - /// load a module with the given name. + /// \brief Retrieve the name of the prebuilt module file that should be used + /// to load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param FileMapOnly If true, then only look in the explicit module name + // to file name map and skip the directory search. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getPrebuiltModuleFileName(StringRef ModuleName, + bool FileMapOnly = false); + + + /// \brief Retrieve the name of the (to-be-)cached module file that should + /// be used to load a module with the given name. /// /// \param ModuleName The module whose module file name will be returned. /// /// \param ModuleMapPath A path that when combined with \c ModuleName /// uniquely identifies this module. See Module::ModuleMap. /// - /// \param UsePrebuiltPath Whether we should use the prebuilt module path. - /// /// \returns The name of the module file that corresponds to this module, /// or an empty string if this module does not correspond to any module file. - std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath, - bool UsePrebuiltPath); + std::string getCachedModuleFileName(StringRef ModuleName, + StringRef ModuleMapPath); /// \brief Lookup a module Search for a module with the given name. /// @@ -535,9 +550,18 @@ public: /// /// \param File The module map file. /// \param IsSystem Whether this file is in a system header directory. - /// + /// \param ID If the module map file is already mapped (perhaps as part of + /// processing a preprocessed module), the ID of the file. + /// \param Offset [inout] An offset within ID to start parsing. On exit, + /// filled by the end of the parsed contents (either EOF or the + /// location of an end-of-module-map pragma). + /// \param OriginalModuleMapFile The original path to the module map file, + /// used to resolve paths within the module (this is required when + /// building the module from preprocessed source). /// \returns true if an error occurred, false otherwise. - bool loadModuleMapFile(const FileEntry *File, bool IsSystem); + bool loadModuleMapFile(const FileEntry *File, bool IsSystem, + FileID ID = FileID(), unsigned *Offset = nullptr, + StringRef OriginalModuleMapFile = StringRef()); /// \brief Collect the set of all known, top-level modules. /// @@ -683,7 +707,9 @@ private: LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File, bool IsSystem, - const DirectoryEntry *Dir); + const DirectoryEntry *Dir, + FileID ID = FileID(), + unsigned *Offset = nullptr); /// \brief Try to load the module map file in the given directory. /// diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h index ca3a84e75e..356f500335 100644 --- a/include/clang/Lex/HeaderSearchOptions.h +++ b/include/clang/Lex/HeaderSearchOptions.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringRef.h" #include <string> #include <vector> +#include <map> namespace clang { @@ -94,6 +95,9 @@ public: /// \brief The directory used for a user build. std::string ModuleUserBuildPath; + /// \brief The mapping of module names to prebuilt module files. + std::map<std::string, std::string> PrebuiltModuleFiles; + /// \brief The directories used to load prebuilt module files. std::vector<std::string> PrebuiltModulePaths; diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 830c25a2e4..603ce10f64 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -39,6 +39,23 @@ enum ConflictMarkerKind { CMK_Perforce }; +/// Describes the bounds (start, size) of the preamble and a flag required by +/// PreprocessorOptions::PrecompiledPreambleBytes. +/// The preamble includes the BOM, if any. +struct PreambleBounds { + PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine) + : Size(Size), + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + + /// \brief Size of the preamble in bytes. + unsigned Size; + /// \brief Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; +}; + /// Lexer - This provides a simple interface that turns a text buffer into a /// stream of tokens. This provides no support for file reading or buffering, /// or buffering/seeking of tokens, only forward lexing is supported. It relies @@ -443,11 +460,11 @@ public: /// to fewer than this number of lines. /// /// \returns The offset into the file where the preamble ends and the rest - /// of the file begins along with a boolean value indicating whether + /// of the file begins along with a boolean value indicating whether /// the preamble ends at the beginning of a new line. - static std::pair<unsigned, bool> ComputePreamble(StringRef Buffer, - const LangOptions &LangOpts, - unsigned MaxLines = 0); + static PreambleBounds ComputePreamble(StringRef Buffer, + const LangOptions &LangOpts, + unsigned MaxLines = 0); /// \brief Checks that the given token is the first token that occurs after /// the given location (this excludes comments and whitespace). Returns the @@ -463,6 +480,10 @@ public: /// \brief Returns true if the given character could appear in an identifier. static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts); + /// \brief Checks whether new line pointed by Str is preceded by escape + /// sequence. + static bool isNewLineEscaped(const char *BufferStart, const char *Str); + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever /// emit a warning. static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, @@ -478,6 +499,11 @@ public: return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); } + /// Returns the leading whitespace for line that corresponds to the given + /// location \p Loc. + static StringRef getIndentationForLine(SourceLocation Loc, + const SourceManager &SM); + //===--------------------------------------------------------------------===// // Internal implementation interfaces. private: @@ -609,7 +635,7 @@ private: //===--------------------------------------------------------------------===// // Other lexer functions. - void SkipBytes(unsigned Bytes, bool StartOfLine); + void SetByteOffset(unsigned Offset, bool StartOfLine); void PropagateLineStartLeadingSpaceInfo(Token &Result); @@ -638,6 +664,8 @@ private: bool IsStartOfConflictMarker(const char *CurPtr); bool HandleEndOfConflictMarker(const char *CurPtr); + bool lexEditorPlaceholder(Token &Result, const char *CurPtr); + bool isCodeCompletionPoint(const char *CurPtr) const; void cutOffLexing() { BufferPtr = BufferEnd; } diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index b66581b428..cc9223eb7d 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -65,6 +65,7 @@ public: bool isHalf : 1; // 1.0h bool isFloat : 1; // 1.0f bool isImaginary : 1; // 1.0i + bool isFloat16 : 1; // 1.0f16 bool isFloat128 : 1; // 1.0q uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h index 7b2a48561f..a202550da3 100644 --- a/include/clang/Lex/MacroArgs.h +++ b/include/clang/Lex/MacroArgs.h @@ -17,6 +17,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/TrailingObjects.h" #include <vector> namespace clang { @@ -26,7 +27,10 @@ namespace clang { /// MacroArgs - An instance of this class captures information about /// the formal arguments specified to a function-like macro invocation. -class MacroArgs { +class MacroArgs final + : private llvm::TrailingObjects<MacroArgs, Token> { + + friend TrailingObjects; /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the /// arguments. All of the actual argument tokens are allocated immediately /// after the MacroArgs object in memory. This is all of the arguments @@ -53,9 +57,12 @@ class MacroArgs { /// Preprocessor owns which we use to avoid thrashing malloc/free. MacroArgs *ArgCache; - MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), - ArgCache(nullptr) {} + /// MacroArgs - The number of arguments the invoked macro expects. + unsigned NumMacroArgs; + + MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), + ArgCache(nullptr), NumMacroArgs(MacroArgs) {} ~MacroArgs() = default; public: @@ -86,7 +93,7 @@ public: /// getPreExpArgument - Return the pre-expanded form of the specified /// argument. const std::vector<Token> & - getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP); + getPreExpArgument(unsigned Arg, Preprocessor &PP); /// getStringifiedArgument - Compute, cache, and return the specified argument /// that has been 'stringified' as required by the # operator. @@ -94,10 +101,9 @@ public: SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd); - /// getNumArguments - Return the number of arguments passed into this macro - /// invocation. - unsigned getNumArguments() const { return NumUnexpArgTokens; } - + /// getNumMacroArguments - Return the number of arguments the invoked macro + /// expects. + unsigned getNumMacroArguments() const { return NumMacroArgs; } /// isVarargsElidedUse - Return true if this is a C99 style varargs macro /// invocation and there was no argument specified for the "..." argument. If @@ -106,6 +112,20 @@ public: /// argument, this returns false. bool isVarargsElidedUse() const { return VarargsElided; } + /// Returns true if the macro was defined with a variadic (ellipsis) parameter + /// AND was invoked with at least one token supplied as a variadic argument. + /// + /// \code + /// #define F(a) a + /// #define V(a, ...) __VA_OPT__(a) + /// F() <-- returns false on this invocation. + /// V(,a) <-- returns true on this invocation. + /// V(,) <-- returns false on this invocation. + /// \endcode + /// + + bool invokedWithVariadicArgument(const MacroInfo *const MI) const; + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of /// tokens into the literal string token that should be produced by the C # /// preprocessor operator. If Charify is true, then it should be turned into diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 6cc3b0bb26..47f10d6e76 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -42,14 +42,14 @@ class MacroInfo { /// \brief The list of arguments for a function-like macro. /// - /// ArgumentList points to the first of NumArguments pointers. + /// ParameterList points to the first of NumParameters pointers. /// /// This can be empty, for, e.g. "#define X()". In a C99-style variadic /// macro, this includes the \c __VA_ARGS__ identifier on the list. - IdentifierInfo **ArgumentList; + IdentifierInfo **ParameterList; - /// \see ArgumentList - unsigned NumArguments; + /// \see ParameterList + unsigned NumParameters; /// \brief This is the list of tokens that the macro is defined to. SmallVector<Token, 8> ReplacementTokens; @@ -105,9 +105,6 @@ class MacroInfo { /// \brief Must warn if the macro is unused at the end of translation unit. bool IsWarnIfUnused : 1; - /// \brief Whether this macro info was loaded from an AST file. - bool FromASTFile : 1; - /// \brief Whether this macro was used as header guard. bool UsedForHeaderGuard : 1; @@ -126,7 +123,7 @@ public: SourceLocation getDefinitionEndLoc() const { return EndLocation; } /// \brief Get length in characters of the macro definition. - unsigned getDefinitionLength(SourceManager &SM) const { + unsigned getDefinitionLength(const SourceManager &SM) const { if (IsDefinitionLengthCached) return DefinitionLength; return getDefinitionLengthSlow(SM); @@ -156,37 +153,37 @@ public: /// \brief Set the value of the IsWarnIfUnused flag. void setIsWarnIfUnused(bool val) { IsWarnIfUnused = val; } - /// \brief Set the specified list of identifiers as the argument list for + /// \brief Set the specified list of identifiers as the parameter list for /// this macro. - void setArgumentList(ArrayRef<IdentifierInfo *> List, + void setParameterList(ArrayRef<IdentifierInfo *> List, llvm::BumpPtrAllocator &PPAllocator) { - assert(ArgumentList == nullptr && NumArguments == 0 && - "Argument list already set!"); + assert(ParameterList == nullptr && NumParameters == 0 && + "Parameter list already set!"); if (List.empty()) return; - NumArguments = List.size(); - ArgumentList = PPAllocator.Allocate<IdentifierInfo *>(List.size()); - std::copy(List.begin(), List.end(), ArgumentList); + NumParameters = List.size(); + ParameterList = PPAllocator.Allocate<IdentifierInfo *>(List.size()); + std::copy(List.begin(), List.end(), ParameterList); } - /// Arguments - The list of arguments for a function-like macro. This can be - /// empty, for, e.g. "#define X()". - typedef IdentifierInfo *const *arg_iterator; - bool arg_empty() const { return NumArguments == 0; } - arg_iterator arg_begin() const { return ArgumentList; } - arg_iterator arg_end() const { return ArgumentList + NumArguments; } - unsigned getNumArgs() const { return NumArguments; } - ArrayRef<const IdentifierInfo *> args() const { - return ArrayRef<const IdentifierInfo *>(ArgumentList, NumArguments); + /// Parameters - The list of parameters for a function-like macro. This can + /// be empty, for, e.g. "#define X()". + typedef IdentifierInfo *const *param_iterator; + bool param_empty() const { return NumParameters == 0; } + param_iterator param_begin() const { return ParameterList; } + param_iterator param_end() const { return ParameterList + NumParameters; } + unsigned getNumParams() const { return NumParameters; } + ArrayRef<const IdentifierInfo *> params() const { + return ArrayRef<const IdentifierInfo *>(ParameterList, NumParameters); } - /// \brief Return the argument number of the specified identifier, - /// or -1 if the identifier is not a formal argument identifier. - int getArgumentNum(const IdentifierInfo *Arg) const { - for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I) + /// \brief Return the parameter number of the specified identifier, + /// or -1 if the identifier is not a formal parameter identifier. + int getParameterNum(const IdentifierInfo *Arg) const { + for (param_iterator I = param_begin(), E = param_end(); I != E; ++I) if (*I == Arg) - return I - arg_begin(); + return I - param_begin(); return -1; } @@ -264,33 +261,15 @@ public: IsDisabled = true; } - /// \brief Determine whether this macro info came from an AST file (such as - /// a precompiled header or module) rather than having been parsed. - bool isFromASTFile() const { return FromASTFile; } - /// \brief Determine whether this macro was used for a header guard. bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; } - /// \brief Retrieve the global ID of the module that owns this particular - /// macro info. - unsigned getOwningModuleID() const { - if (isFromASTFile()) - return *(const unsigned *)(this + 1); - - return 0; - } - void dump() const; private: - unsigned getDefinitionLengthSlow(SourceManager &SM) const; - - void setOwningModuleID(unsigned ID) { - assert(isFromASTFile()); - *(unsigned *)(this + 1) = ID; - } + unsigned getDefinitionLengthSlow(const SourceManager &SM) const; friend class Preprocessor; }; @@ -531,6 +510,9 @@ public: ID.AddPointer(II); } + /// Get the name of the macro. + IdentifierInfo *getName() const { return II; } + /// Get the ID of the module that exports this macro. Module *getOwningModule() const { return OwningModule; } diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h index 70770d17e9..ee0638b57f 100644 --- a/include/clang/Lex/ModuleLoader.h +++ b/include/clang/Lex/ModuleLoader.h @@ -109,6 +109,16 @@ public: Module::NameVisibilityKind Visibility, bool IsInclusionDirective) = 0; + /// Attempt to load the given module from the specified source buffer. Does + /// not make any submodule visible; for that, use loadModule or + /// makeModuleVisible. + /// + /// \param Loc The location at which the module was loaded. + /// \param ModuleName The name of the module to build. + /// \param Source The source of the module: a (preprocessed) module map. + virtual void loadModuleFromSource(SourceLocation Loc, StringRef ModuleName, + StringRef Source) = 0; + /// \brief Make the given module visible. virtual void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, @@ -136,6 +146,30 @@ public: bool HadFatalFailure; }; + +/// A module loader that doesn't know how to load modules. +class TrivialModuleLoader : public ModuleLoader { +public: + ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) override { + return ModuleLoadResult(); + } + + void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, + StringRef Source) override {} + + void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc) override {} + + GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { + return nullptr; + } + bool lookupMissingImports(StringRef Name, + SourceLocation TriggerLoc) override { + return 0; + } +}; } diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 46136725d8..4e600ce855 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/Twine.h" #include <algorithm> #include <memory> @@ -81,22 +82,26 @@ class ModuleMap { /// \brief The directory used for Clang-supplied, builtin include headers, /// such as "stdint.h". - const DirectoryEntry *BuiltinIncludeDir; + const DirectoryEntry *BuiltinIncludeDir = nullptr; /// \brief Language options used to parse the module map itself. /// /// These are always simple C language options. LangOptions MMapLangOpts; - // The module that the main source file is associated with (the module - // named LangOpts::CurrentModule, if we've loaded it). - Module *SourceModule; + /// The module that the main source file is associated with (the module + /// named LangOpts::CurrentModule, if we've loaded it). + Module *SourceModule = nullptr; + + /// The global module for the current TU, if we still own it. (Ownership is + /// transferred if/when we create an enclosing module. + std::unique_ptr<Module> PendingGlobalModule; /// \brief The top-level modules that are known. llvm::StringMap<Module *> Modules; /// \brief The number of modules we have created in total. - unsigned NumCreatedModules; + unsigned NumCreatedModules = 0; public: /// \brief Flags describing the role of a module header. @@ -116,6 +121,11 @@ public: // Adjust ModuleMap::addHeader. }; + /// Convert a header kind to a role. Requires Kind to not be HK_Excluded. + static ModuleHeaderRole headerKindToRole(Module::HeaderKind Kind); + /// Convert a header role to a kind. + static Module::HeaderKind headerRoleToKind(ModuleHeaderRole Role); + /// \brief A header that is known to reside within a given module, /// whether it was included or excluded. class KnownHeader { @@ -165,7 +175,13 @@ private: /// \brief Mapping from each header to the module that owns the contents of /// that header. HeadersMap Headers; - + + /// Map from file sizes to modules with lazy header directives of that size. + mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>> LazyHeadersBySize; + /// Map from mtimes to modules with lazy header directives with those mtimes. + mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>> + LazyHeadersByModTime; + /// \brief Mapping from directories with umbrella headers to the module /// that is generated from the umbrella header. /// @@ -257,6 +273,31 @@ private: /// resolved. Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const; + /// Add an unresolved header to a module. + void addUnresolvedHeader(Module *Mod, + Module::UnresolvedHeaderDirective Header); + + /// Look up the given header directive to find an actual header file. + /// + /// \param M The module in which we're resolving the header directive. + /// \param Header The header directive to resolve. + /// \param RelativePathName Filled in with the relative path name from the + /// module to the resolved header. + /// \return The resolved file, if any. + const FileEntry *findHeader(Module *M, + const Module::UnresolvedHeaderDirective &Header, + SmallVectorImpl<char> &RelativePathName); + + /// Resolve the given header directive. + void resolveHeader(Module *M, + const Module::UnresolvedHeaderDirective &Header); + + /// Attempt to resolve the specified header directive as naming a builtin + /// header. + /// \return \c true if a corresponding builtin header was found. + bool resolveAsBuiltinHeader(Module *M, + const Module::UnresolvedHeaderDirective &Header); + /// \brief Looks up the modules that \p File corresponds to. /// /// If \p File represents a builtin header within Clang's builtin include @@ -351,6 +392,15 @@ public: /// the preferred module for the header. ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File) const; + /// Resolve all lazy header directives for the specified file. + /// + /// This ensures that the HeaderFileInfo on HeaderSearch is up to date. This + /// is effectively internal, but is exposed so HeaderSearch can call it. + void resolveHeaderDirectives(const FileEntry *File) const; + + /// Resolve all lazy header directives for the specified module. + void resolveHeaderDirectives(Module *Mod) const; + /// \brief Reports errors if a module must not include a specific file. /// /// \param RequestingModule The module including a file. @@ -426,6 +476,14 @@ public: bool IsFramework, bool IsExplicit); + /// \brief Create a 'global module' for a C++ Modules TS module interface + /// unit. + /// + /// We model the global module as a submodule of the module interface unit. + /// Unfortunately, we can't create the module interface unit's Module until + /// later, because we don't know what it will be called. + Module *createGlobalModuleForInterfaceUnit(SourceLocation Loc); + /// \brief Create a new module for a C++ Modules TS module interface unit. /// The module must not already exist, and will be configured for the current /// compilation. @@ -433,7 +491,8 @@ public: /// Note that this also sets the current module to the newly-created module. /// /// \returns The newly-created module. - Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name); + Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name, + Module *GlobalModule); /// \brief Infer the contents of a framework module map from the given /// framework directory. @@ -507,16 +566,6 @@ public: /// false otherwise. bool resolveConflicts(Module *Mod, bool Complain); - /// \brief Infers the (sub)module based on the given source location and - /// source manager. - /// - /// \param Loc The location within the source that we are querying, along - /// with its source manager. - /// - /// \returns The module that owns this source location, or null if no - /// module owns this source location. - Module *inferModuleFromLocation(FullSourceLoc Loc); - /// \brief Sets the umbrella header of the given module to the given /// header. void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, @@ -546,14 +595,20 @@ public: /// \param HomeDir The directory in which relative paths within this module /// map file will be resolved. /// + /// \param ID The FileID of the file to process, if we've already entered it. + /// + /// \param Offset [inout] On input the offset at which to start parsing. On + /// output, the offset at which the module map terminated. + /// /// \param ExternModuleLoc The location of the "extern module" declaration /// that caused us to load this module map file, if any. /// /// \returns true if an error occurred, false otherwise. bool parseModuleMapFile(const FileEntry *File, bool IsSystem, - const DirectoryEntry *HomeDir, + const DirectoryEntry *HomeDir, FileID ID = FileID(), + unsigned *Offset = nullptr, SourceLocation ExternModuleLoc = SourceLocation()); - + /// \brief Dump the contents of the module map, for debugging purposes. void dump(); diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h index 83e6f99078..3967f86889 100644 --- a/include/clang/Lex/MultipleIncludeOpt.h +++ b/include/clang/Lex/MultipleIncludeOpt.h @@ -92,7 +92,7 @@ public: TheMacro = nullptr; } - /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the + /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the /// top of the file when reading preprocessor directives. Otherwise, reading /// the "ifndef x" would count as reading tokens. bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 2d027f314b..19bce4dd32 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -235,6 +235,14 @@ public: virtual void PragmaWarningPop(SourceLocation Loc) { } + /// \brief Callback invoked when a \#pragma clang assume_nonnull begin directive + /// is read. + virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {} + + /// \brief Callback invoked when a \#pragma clang assume_nonnull end directive + /// is read. + virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {} + /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a /// macro invocation is found. virtual void MacroExpands(const Token &MacroNameTok, @@ -247,10 +255,14 @@ public: } /// \brief Hook called whenever a macro \#undef is seen. + /// \param MacroNameTok The active Token + /// \param MD A MacroDefinition for the named macro. + /// \param Undef New MacroDirective if the macro was defined, null otherwise. /// /// MD is released immediately following this callback. virtual void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { } /// \brief Hook called whenever the 'defined' operator is seen. @@ -262,7 +274,10 @@ public: /// \brief Hook called when a source range is skipped. /// \param Range The SourceRange that was skipped. The range begins at the /// \#if/\#else directive and ends after the \#endif/\#else directive. - virtual void SourceRangeSkipped(SourceRange Range) { + /// \param EndifLoc The end location of the 'endif' token, which may precede + /// the range skipped by the directive (e.g excluding comments after an + /// 'endif'). + virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { } enum ConditionValueKind { @@ -377,6 +392,12 @@ public: Second->Ident(Loc, str); } + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) override { + First->PragmaDirective(Loc, Introducer); + Second->PragmaDirective(Loc, Introducer); + } + void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, StringRef Str) override { First->PragmaComment(Loc, Kind, Str); @@ -389,6 +410,11 @@ public: Second->PragmaDetectMismatch(Loc, Name, Value); } + void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { + First->PragmaDebug(Loc, DebugType); + Second->PragmaDebug(Loc, DebugType); + } + void PragmaMessage(SourceLocation Loc, StringRef Namespace, PragmaMessageKind Kind, StringRef Str) override { First->PragmaMessage(Loc, Namespace, Kind, Str); @@ -433,21 +459,33 @@ public: Second->PragmaWarningPop(Loc); } + void PragmaAssumeNonNullBegin(SourceLocation Loc) override { + First->PragmaAssumeNonNullBegin(Loc); + Second->PragmaAssumeNonNullBegin(Loc); + } + + void PragmaAssumeNonNullEnd(SourceLocation Loc) override { + First->PragmaAssumeNonNullEnd(Loc); + Second->PragmaAssumeNonNullEnd(Loc); + } + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override { First->MacroExpands(MacroNameTok, MD, Range, Args); Second->MacroExpands(MacroNameTok, MD, Range, Args); } - void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { First->MacroDefined(MacroNameTok, MD); Second->MacroDefined(MacroNameTok, MD); } void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override { - First->MacroUndefined(MacroNameTok, MD); - Second->MacroUndefined(MacroNameTok, MD); + const MacroDefinition &MD, + const MacroDirective *Undef) override { + First->MacroUndefined(MacroNameTok, MD, Undef); + Second->MacroUndefined(MacroNameTok, MD, Undef); } void Defined(const Token &MacroNameTok, const MacroDefinition &MD, @@ -456,9 +494,9 @@ public: Second->Defined(MacroNameTok, MD, Range); } - void SourceRangeSkipped(SourceRange Range) override { - First->SourceRangeSkipped(Range); - Second->SourceRangeSkipped(Range); + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { + First->SourceRangeSkipped(Range, EndifLoc); + Second->SourceRangeSkipped(Range, EndifLoc); } /// \brief Hook called whenever an \#if is seen. diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h index 904be792b2..f96af665b1 100644 --- a/include/clang/Lex/PTHLexer.h +++ b/include/clang/Lex/PTHLexer.h @@ -36,7 +36,7 @@ class PTHLexer : public PreprocessorLexer { const unsigned char* LastHashTokPtr; /// PPCond - Pointer to a side table in the PTH file that provides a - /// a consise summary of the preproccessor conditional block structure. + /// a concise summary of the preprocessor conditional block structure. /// This is used to perform quick skipping of conditional blocks. const unsigned char* PPCond; diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 826ba33fbb..882b8aedf7 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -488,7 +488,8 @@ namespace clang { void MacroExpands(const Token &Id, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override; void MacroDefined(const Token &Id, const MacroDirective *MD) override; - void MacroUndefined(const Token &Id, const MacroDefinition &MD) override; + void MacroUndefined(const Token &Id, const MacroDefinition &MD, + const MacroDirective *Undef) override; void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, @@ -503,7 +504,8 @@ namespace clang { void Defined(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range) override; - void SourceRangeSkipped(SourceRange Range) override; + void SourceRangeSkipped(SourceRange Range, + SourceLocation EndifLoc) override; void addMacroExpansion(const Token &Id, const MacroInfo *MI, SourceRange Range); diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 26efa8b8a1..4f211a3eb6 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -47,6 +47,7 @@ class ExternalPreprocessorSource; class FileManager; class FileEntry; class HeaderSearch; +class MemoryBufferCache; class PragmaNamespace; class PragmaHandler; class CommentHandler; @@ -95,6 +96,8 @@ enum MacroUse { /// know anything about preprocessor-level issues like the \#include stack, /// token expansion, etc. class Preprocessor { + friend class VariadicMacroScopeGuard; + friend class VAOptDefinitionContext; std::shared_ptr<PreprocessorOptions> PPOpts; DiagnosticsEngine *Diags; LangOptions &LangOpts; @@ -102,6 +105,7 @@ class Preprocessor { const TargetInfo *AuxTarget; FileManager &FileMgr; SourceManager &SourceMgr; + MemoryBufferCache &PCMCache; std::unique_ptr<ScratchBuffer> ScratchBuf; HeaderSearch &HeaderInfo; ModuleLoader &TheModuleLoader; @@ -128,6 +132,7 @@ class Preprocessor { IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma IdentifierInfo *Ident__identifier; // __identifier IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_extension; // __has_extension IdentifierInfo *Ident__has_builtin; // __has_builtin @@ -281,6 +286,44 @@ class Preprocessor { /// This is used when loading a precompiled preamble. std::pair<int, bool> SkipMainFilePreamble; + class PreambleConditionalStackStore { + enum State { + Off = 0, + Recording = 1, + Replaying = 2, + }; + + public: + PreambleConditionalStackStore() : ConditionalStackState(Off) {} + + void startRecording() { ConditionalStackState = Recording; } + void startReplaying() { ConditionalStackState = Replaying; } + bool isRecording() const { return ConditionalStackState == Recording; } + bool isReplaying() const { return ConditionalStackState == Replaying; } + + ArrayRef<PPConditionalInfo> getStack() const { + return ConditionalStack; + } + + void doneReplaying() { + ConditionalStack.clear(); + ConditionalStackState = Off; + } + + void setStack(ArrayRef<PPConditionalInfo> s) { + if (!isRecording() && !isReplaying()) + return; + ConditionalStack.clear(); + ConditionalStack.append(s.begin(), s.end()); + } + + bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } + + private: + SmallVector<PPConditionalInfo, 4> ConditionalStack; + State ConditionalStackState; + } PreambleConditionalStack; + /// \brief The current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// @@ -322,7 +365,7 @@ class Preprocessor { /// \brief If the current lexer is for a submodule that is being built, this /// is that submodule. - Module *CurSubmodule; + Module *CurLexerSubmodule; /// \brief Keeps track of the stack of files currently /// \#included, and macros currently being expanded from, not counting @@ -505,16 +548,19 @@ class Preprocessor { /// \brief Information about a submodule that we're currently building. struct BuildingSubmoduleInfo { - BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, + BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma, SubmoduleState *OuterSubmoduleState, unsigned OuterPendingModuleMacroNames) - : M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState), + : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma), + OuterSubmoduleState(OuterSubmoduleState), OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {} /// The module that we are building. Module *M; /// The location at which the module was included. SourceLocation ImportLoc; + /// Whether we entered this submodule via a pragma. + bool IsPragma; /// The previous SubmoduleState. SubmoduleState *OuterSubmoduleState; /// The number of pending module macro names when we started building this. @@ -639,19 +685,12 @@ class Preprocessor { /// of that list. MacroInfoChain *MIChainHead; - struct DeserializedMacroInfoChain { - MacroInfo MI; - unsigned OwningModuleID; // MUST be immediately after the MacroInfo object - // so it can be accessed by MacroInfo::getOwningModuleID(). - DeserializedMacroInfoChain *Next; - }; - DeserializedMacroInfoChain *DeserialMIChainHead; - void updateOutOfDateIdentifier(IdentifierInfo &II) const; public: Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM, + MemoryBufferCache &PCMCache, HeaderSearch &Headers, ModuleLoader &TheModuleLoader, IdentifierInfoLookup *IILookup = nullptr, bool OwnsHeaderSearch = false, @@ -691,6 +730,7 @@ public: const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } FileManager &getFileManager() const { return FileMgr; } SourceManager &getSourceManager() const { return SourceMgr; } + MemoryBufferCache &getPCMCache() const { return PCMCache; } HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } IdentifierTable &getIdentifierTable() { return Identifiers; } @@ -769,8 +809,9 @@ public: /// expansions going on at the time. PreprocessorLexer *getCurrentFileLexer() const; - /// \brief Return the submodule owning the file being lexed. - Module *getCurrentSubmodule() const { return CurSubmodule; } + /// \brief Return the submodule owning the file being lexed. This may not be + /// the current module if we have changed modules since entering the file. + Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; } /// \brief Returns the FileID for the preprocessor predefines. FileID getPredefinesFileID() const { return PredefinesFileID; } @@ -1259,6 +1300,10 @@ public: CachedTokens[CachedLexPos-1] = Tok; } + /// Enter an annotation token into the token stream. + void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, + void *AnnotationVal); + /// Update the current token to represent the provided /// identifier, in order to cache an action performed by typo correction. void TypoCorrectToken(const Token &Tok) { @@ -1598,6 +1643,7 @@ private: *Ident_AbnormalTermination; const char *getCurLexerEndPos(); + void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod); public: void PoisonSEHIdentifiers(bool Poison = true); // Borland @@ -1656,10 +1702,6 @@ public: /// \brief Allocate a new MacroInfo object with the provided SourceLocation. MacroInfo *AllocateMacroInfo(SourceLocation L); - /// \brief Allocate a new MacroInfo object loaded from an AST file. - MacroInfo *AllocateDeserializedMacroInfo(SourceLocation L, - unsigned SubModuleID); - /// \brief Turn the specified lexer token into a fully checked and spelled /// filename, e.g. as an operand of \#include. /// @@ -1682,7 +1724,7 @@ public: SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false); + bool *IsMapped, bool SkipCache = false); /// \brief Get the DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. @@ -1717,13 +1759,16 @@ public: bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, bool *ShadowFlag = nullptr); -private: + void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma); + Module *LeaveSubmodule(bool ForPragma); +private: void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); - IncludeMacroStack.emplace_back( - CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer), - CurPPLexer, std::move(CurTokenLexer), CurDirLookup); + IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, + std::move(CurLexer), std::move(CurPTHLexer), + CurPPLexer, std::move(CurTokenLexer), + CurDirLookup); CurPPLexer = nullptr; } @@ -1733,16 +1778,13 @@ private: CurPPLexer = IncludeMacroStack.back().ThePPLexer; CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer); CurDirLookup = IncludeMacroStack.back().TheDirLookup; - CurSubmodule = IncludeMacroStack.back().TheSubmodule; + CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule; CurLexerKind = IncludeMacroStack.back().CurLexerKind; IncludeMacroStack.pop_back(); } void PropagateLineStartLeadingSpaceInfo(Token &Result); - void EnterSubmodule(Module *M, SourceLocation ImportLoc); - void LeaveSubmodule(); - /// Determine whether we need to create module macros for #defines in the /// current context. bool needModuleMacros() const; @@ -1751,9 +1793,6 @@ private: /// macro name. void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info); - /// \brief Allocate a new MacroInfo object. - MacroInfo *AllocateMacroInfo(); - DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc); UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc); @@ -1773,11 +1812,24 @@ private: void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other, bool *ShadowFlag = nullptr); + /// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the + /// entire line) of the macro's tokens and adds them to MacroInfo, and while + /// doing so performs certain validity checks including (but not limited to): + /// - # (stringization) is followed by a macro parameter + /// \param MacroNameTok - Token that represents the macro name + /// \param ImmediatelyAfterHeaderGuard - Macro follows an #ifdef header guard + /// + /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and + /// returns a nullptr if an invalid sequence of tokens is encountered. + + MacroInfo *ReadOptionalMacroParameterListAndBody( + const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard); + /// The ( starting an argument list of a macro definition has just been read. - /// Lex the rest of the arguments and the closing ), updating \p MI with + /// Lex the rest of the parameters and the closing ), updating \p MI with /// what we learn and saving in \p LastTok the last token read. /// Return true if an error occurs parsing the arg list. - bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok); + bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok); /// We just read a \#if or related directive and decided that the /// subsequent tokens are in the \#if'd out portion of the @@ -1787,18 +1839,28 @@ private: /// \p FoundElse is false, then \#else directives are ok, if not, then we have /// already seen one so a \#else directive is a duplicate. When this returns, /// the caller can lex the first valid token. - void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + void SkipExcludedConditionalBlock(const Token &HashToken, + SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, SourceLocation ElseLoc = SourceLocation()); /// \brief A fast PTH version of SkipExcludedConditionalBlock. void PTHSkipExcludedConditionalBlock(); + /// Information about the result for evaluating an expression for a + /// preprocessor directive. + struct DirectiveEvalResult { + /// Whether the expression was evaluated as true or not. + bool Conditional; + /// True if the expression contained identifiers that were undefined. + bool IncludedUndefinedIds; + }; + /// \brief Evaluate an integer constant expression that may occur after a - /// \#if or \#elif directive and return it as a bool. + /// \#if or \#elif directive and return a \p DirectiveEvalResult object. /// /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro. - bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); /// \brief Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. @@ -1829,7 +1891,7 @@ private: /// After reading "MACRO(", this method is invoked to read all of the formal /// arguments specified for the macro invocation. Returns null on error. - MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, + MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI, SourceLocation &ExpansionEnd); /// \brief If an identifier token is read that is to be expanded @@ -1913,20 +1975,24 @@ private: void HandleMicrosoftImportDirective(Token &Tok); public: + /// Check that the given module is available, producing a diagnostic if not. + /// \return \c true if the check failed (because the module is not available). + /// \c false if the module appears to be usable. + static bool checkModuleIsAvailable(const LangOptions &LangOpts, + const TargetInfo &TargetInfo, + DiagnosticsEngine &Diags, Module *M); + // Module inclusion testing. /// \brief Find the module that owns the source or header file that /// \p Loc points to. If the location is in a file that was included /// into a module, or is outside any module, returns nullptr. Module *getModuleForLocation(SourceLocation Loc); - /// \brief Find the module that contains the specified location, either - /// directly or indirectly. - Module *getModuleContainingLocation(SourceLocation Loc); - /// \brief We want to produce a diagnostic at location IncLoc concerning a /// missing module import. /// /// \param IncLoc The location at which the missing import was detected. + /// \param M The desired module. /// \param MLoc A location within the desired module at which some desired /// effect occurred (eg, where a desired entity was declared). /// @@ -1934,20 +2000,47 @@ public: /// Null if no such file could be determined or if a #include is not /// appropriate. const FileEntry *getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc, + Module *M, SourceLocation MLoc); + bool isRecordingPreamble() const { + return PreambleConditionalStack.isRecording(); + } + + bool hasRecordedPreamble() const { + return PreambleConditionalStack.hasRecordedPreamble(); + } + + ArrayRef<PPConditionalInfo> getPreambleConditionalStack() const { + return PreambleConditionalStack.getStack(); + } + + void setRecordedPreambleConditionalStack(ArrayRef<PPConditionalInfo> s) { + PreambleConditionalStack.setStack(s); + } + + void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) { + PreambleConditionalStack.startReplaying(); + PreambleConditionalStack.setStack(s); + } + private: + /// \brief After processing predefined file, initialize the conditional stack from + /// the preamble. + void replayPreambleConditionalStack(); + // Macro handling. void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef); void HandleUndefDirective(); // Conditional Inclusion. - void HandleIfdefDirective(Token &Tok, bool isIfndef, - bool ReadAnyTokensBeforeDirective); - void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective); + void HandleIfdefDirective(Token &Tok, const Token &HashToken, + bool isIfndef, bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &Tok, const Token &HashToken, + bool ReadAnyTokensBeforeDirective); void HandleEndifDirective(Token &Tok); - void HandleElseDirective(Token &Tok); - void HandleElifDirective(Token &Tok); + void HandleElseDirective(Token &Tok, const Token &HashToken); + void HandleElifDirective(Token &Tok, const Token &HashToken); // Pragmas. void HandlePragmaDirective(SourceLocation IntroducerLoc, @@ -1961,6 +2054,7 @@ public: void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); void HandlePragmaIncludeAlias(Token &Tok); + void HandlePragmaModuleBuild(Token &Tok); IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok); // Return true and store the first token only if any CommentHandler diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h index 6d6cf05a96..65021fc2d3 100644 --- a/include/clang/Lex/PreprocessorLexer.h +++ b/include/clang/Lex/PreprocessorLexer.h @@ -17,6 +17,7 @@ #include "clang/Lex/MultipleIncludeOpt.h" #include "clang/Lex/Token.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" namespace clang { @@ -76,7 +77,7 @@ protected: PreprocessorLexer(Preprocessor *pp, FileID fid); PreprocessorLexer() - : PP(nullptr), InitialNumSLocEntries(0), + : PP(nullptr), FID(), InitialNumSLocEntries(0), ParsingPreprocessorDirective(false), ParsingFilename(false), LexingRawMode(false) {} @@ -176,6 +177,11 @@ public: conditional_iterator conditional_end() const { return ConditionalStack.end(); } + + void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) { + ConditionalStack.clear(); + ConditionalStack.append(CL.begin(), CL.end()); + } }; } // end namespace clang diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h index 58d79f7ff8..760b308f92 100644 --- a/include/clang/Lex/PreprocessorOptions.h +++ b/include/clang/Lex/PreprocessorOptions.h @@ -80,7 +80,14 @@ public: /// The boolean indicates whether the preamble ends at the start of a new /// line. std::pair<unsigned, bool> PrecompiledPreambleBytes; - + + /// \brief True indicates that a preamble is being generated. + /// + /// When the lexer is done, one of the things that need to be preserved is the + /// conditional #if stack, so the ASTWriter/ASTReader can save/restore it when + /// processing the rest of the file. + bool GeneratePreamble; + /// The implicit PTH input included at the start of the translation unit, or /// empty. std::string ImplicitPTHInclude; @@ -88,6 +95,16 @@ public: /// If given, a PTH cache file to use for speeding up header parsing. std::string TokenCache; + /// When enabled, preprocessor is in a mode for parsing a single file only. + /// + /// Disables #includes of other files and if there are unresolved identifiers + /// in preprocessor directive conditions it causes all blocks to be parsed so + /// that the client can get the maximum amount of information from the parser. + bool SingleFileParseMode = false; + + /// When enabled, the preprocessor will construct editor placeholder tokens. + bool LexEditorPlaceholders = true; + /// \brief True if the SourceManager should report the original file name for /// contents of files that were remapped to other files. Defaults to true. bool RemappedFilesKeepOriginalName; @@ -143,7 +160,8 @@ public: DisablePCHValidation(false), AllowPCHWithCompilerErrors(false), DumpDeserializedPCHDecls(false), - PrecompiledPreambleBytes(0, true), + PrecompiledPreambleBytes(0, false), + GeneratePreamble(false), RemappedFilesKeepOriginalName(true), RetainRemappedFileBuffers(false), ObjCXXARCStandardLibrary(ARCXX_nolib) { } @@ -173,9 +191,11 @@ public: ImplicitPCHInclude.clear(); ImplicitPTHInclude.clear(); TokenCache.clear(); + SingleFileParseMode = false; + LexEditorPlaceholders = true; RetainRemappedFileBuffers = true; PrecompiledPreambleBytes.first = 0; - PrecompiledPreambleBytes.second = 0; + PrecompiledPreambleBytes.second = false; } }; diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 4393e205ff..02a1fef70f 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -84,6 +84,7 @@ public: StringifiedInMacro = 0x100, // This string or character literal is formed by // macro stringizing or charizing operator. CommaAfterElided = 0x200, // The comma following this token was elided (MS). + IsEditorPlaceholder = 0x400, // This identifier is a placeholder. }; tok::TokenKind getKind() const { return Kind; } @@ -298,6 +299,13 @@ public: /// Returns true if the comma after this token was elided. bool commaAfterElided() const { return getFlag(CommaAfterElided); } + + /// Returns true if this token is an editor placeholder. + /// + /// Editor placeholders are produced by the code-completion engine and are + /// represented as characters between '<#' and '#>' in the source code. The + /// lexer uses identifier tokens to represent placeholders. + bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } }; /// \brief Information about the conditional stack (\#if directives) diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h index fdeed44d8f..17305107ca 100644 --- a/include/clang/Lex/TokenLexer.h +++ b/include/clang/Lex/TokenLexer.h @@ -15,12 +15,14 @@ #define LLVM_CLANG_LEX_TOKENLEXER_H #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" namespace clang { class MacroInfo; class Preprocessor; class Token; class MacroArgs; + class VAOptExpansionContext; /// TokenLexer - This implements a lexer that returns tokens from a macro body /// or token stream instead of lexing from a character buffer. This is used for @@ -55,9 +57,9 @@ class TokenLexer { /// unsigned NumTokens; - /// CurToken - This is the next token that Lex will return. + /// This is the index of the next token that Lex will return. /// - unsigned CurToken; + unsigned CurTokenIdx; /// ExpandLocStart/End - The source location range where this macro was /// expanded. @@ -156,15 +158,56 @@ private: /// isAtEnd - Return true if the next lex call will pop this macro off the /// include stack. bool isAtEnd() const { - return CurToken == NumTokens; + return CurTokenIdx == NumTokens; } - /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## - /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there - /// are is another ## after it, chomp it iteratively. Return the result as - /// Tok. If this returns true, the caller should immediately return the + /// Concatenates the next (sub-)sequence of \p Tokens separated by '##' + /// starting with LHSTok - stopping when we encounter a token that is neither + /// '##' nor preceded by '##'. Places the result back into \p LHSTok and sets + /// \p CurIdx to point to the token following the last one that was pasted. + /// + /// Also performs the MSVC extension wide-literal token pasting involved with: + /// \code L #macro-arg. \endcode + /// + /// \param[in,out] LHSTok - Contains the token to the left of '##' in \p + /// Tokens upon entry and will contain the resulting concatenated Token upon + /// exit. + /// + /// \param[in] TokenStream - The stream of Tokens we are lexing from. + /// + /// \param[in,out] CurIdx - Upon entry, \pTokens[\pCurIdx] must equal '##' + /// (with the exception of the MSVC extension mentioned above). Upon exit, it + /// is set to the index of the token following the last token that was + /// concatenated together. + /// + /// \returns If this returns true, the caller should immediately return the /// token. - bool PasteTokens(Token &Tok); + + bool pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream, + unsigned int &CurIdx); + + /// Calls pasteTokens above, passing in the '*this' object's Tokens and + /// CurTokenIdx data members. + bool pasteTokens(Token &Tok); + + + /// Takes the tail sequence of tokens within ReplacementToks that represent + /// the just expanded __VA_OPT__ tokens (possibly zero tokens) and transforms + /// them into a string. \p VCtx is used to determine which token represents + /// the first __VA_OPT__ replacement token. + /// + /// \param[in,out] ReplacementToks - Contains the current Replacement Tokens + /// (prior to rescanning and token pasting), the tail end of which represents + /// the tokens just expanded through __VA_OPT__ processing. These (sub) + /// sequence of tokens are folded into one stringified token. + /// + /// \param[in] VCtx - contains relevent contextual information about the + /// state of the tokens around and including the __VA_OPT__ token, necessary + /// for stringification. + + void stringifyVAOPTContents(SmallVectorImpl<Token> &ReplacementToks, + const VAOptExpansionContext &VCtx, + SourceLocation VAOPTClosingParenLoc); /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. diff --git a/include/clang/Lex/VariadicMacroSupport.h b/include/clang/Lex/VariadicMacroSupport.h new file mode 100644 index 0000000000..cebaf15187 --- /dev/null +++ b/include/clang/Lex/VariadicMacroSupport.h @@ -0,0 +1,226 @@ +//===- VariadicMacroSupport.h - state machines and scope guards -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines support types to help with preprocessing variadic macro +// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and +// expansions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H +#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H + +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class Preprocessor; + + /// An RAII class that tracks when the Preprocessor starts and stops lexing + /// the definition of a (ISO C/C++) variadic macro. As an example, this is + /// useful for unpoisoning and repoisoning certain identifiers (such as + /// __VA_ARGS__) that are only allowed in this context. Also, being a friend + /// of the Preprocessor class allows it to access PP's cached identifiers + /// directly (as opposed to performing a lookup each time). + class VariadicMacroScopeGuard { + const Preprocessor &PP; + IdentifierInfo *const Ident__VA_ARGS__; + IdentifierInfo *const Ident__VA_OPT__; + + public: + VariadicMacroScopeGuard(const Preprocessor &P) + : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__), + Ident__VA_OPT__(PP.Ident__VA_OPT__) { + assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned " + "outside an ISO C/C++ variadic " + "macro definition!"); + assert( + !Ident__VA_OPT__ || + (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!")); + } + + /// Client code should call this function just before the Preprocessor is + /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro. + void enterScope() { + Ident__VA_ARGS__->setIsPoisoned(false); + if (Ident__VA_OPT__) + Ident__VA_OPT__->setIsPoisoned(false); + } + + /// Client code should call this function as soon as the Preprocessor has + /// either completed lexing the macro's definition tokens, or an error + /// occured and the context is being exited. This function is idempotent + /// (might be explicitly called, and then reinvoked via the destructor). + void exitScope() { + Ident__VA_ARGS__->setIsPoisoned(true); + if (Ident__VA_OPT__) + Ident__VA_OPT__->setIsPoisoned(true); + } + + ~VariadicMacroScopeGuard() { exitScope(); } + }; + + /// \brief A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a variadic macro definition. + class VAOptDefinitionContext { + /// Contains all the locations of so far unmatched lparens. + SmallVector<SourceLocation, 8> UnmatchedOpeningParens; + + const IdentifierInfo *const Ident__VA_OPT__; + + + public: + VAOptDefinitionContext(Preprocessor &PP) + : Ident__VA_OPT__(PP.Ident__VA_OPT__) {} + + bool isVAOptToken(const Token &T) const { + return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__; + } + + /// Returns true if we have seen the __VA_OPT__ and '(' but before having + /// seen the matching ')'. + bool isInVAOpt() const { return UnmatchedOpeningParens.size(); } + + /// Call this function as soon as you see __VA_OPT__ and '('. + void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) { + assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + + } + + SourceLocation getUnmatchedOpeningParenLoc() const { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + return UnmatchedOpeningParens.back(); + } + + /// Call this function each time an rparen is seen. It returns true only if + /// the rparen that was just seen was the eventual (non-nested) closing + /// paren for VAOPT, and ejects us out of the VAOPT context. + bool sawClosingParen() { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.pop_back(); + return !UnmatchedOpeningParens.size(); + } + + /// Call this function each time an lparen is seen. + void sawOpeningParen(SourceLocation LParenLoc) { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + } + + }; + + /// \brief A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a macro during macro expansion. + class VAOptExpansionContext : VAOptDefinitionContext { + + Token SyntheticEOFToken; + + // The (spelling) location of the current __VA_OPT__ in the replacement list + // of the function-like macro being expanded. + SourceLocation VAOptLoc; + + // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first + // token of the current VAOPT contents (so we know where to start eager + // token-pasting and stringification) *within* the substituted tokens of + // the function-like macro's new replacement list. + int NumOfTokensPriorToVAOpt = -1; + + unsigned LeadingSpaceForStringifiedToken : 1; + + unsigned StringifyBefore : 1; + unsigned CharifyBefore : 1; + + + bool hasStringifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return StringifyBefore; + } + + bool isReset() const { + return NumOfTokensPriorToVAOpt == -1 || + VAOptLoc.isInvalid(); + } + + public: + VAOptExpansionContext(Preprocessor &PP) + : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false), + StringifyBefore(false), CharifyBefore(false) { + SyntheticEOFToken.startToken(); + SyntheticEOFToken.setKind(tok::eof); + } + + void reset() { + VAOptLoc = SourceLocation(); + NumOfTokensPriorToVAOpt = -1; + LeadingSpaceForStringifiedToken = false; + StringifyBefore = false; + CharifyBefore = false; + } + + const Token &getEOFTok() const { return SyntheticEOFToken; } + + void sawHashOrHashAtBefore(const bool HasLeadingSpace, + const bool IsHashAt) { + + StringifyBefore = !IsHashAt; + CharifyBefore = IsHashAt; + LeadingSpaceForStringifiedToken = HasLeadingSpace; + } + + + + bool hasCharifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return CharifyBefore; + } + bool hasStringifyOrCharifyBefore() const { + return hasStringifyBefore() || hasCharifyBefore(); + } + + unsigned int getNumberOfTokensPriorToVAOpt() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return NumOfTokensPriorToVAOpt; + } + + bool getLeadingSpaceForStringifiedToken() const { + assert(hasStringifyBefore() && + "Must only be called if this has been marked for stringification"); + return LeadingSpaceForStringifiedToken; + } + + void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, + const unsigned int NumPriorTokens) { + assert(VAOptLoc.isFileID() && "Must not come from a macro expansion"); + assert(isReset() && "Must only be called if the state has been reset"); + VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation()); + this->VAOptLoc = VAOptLoc; + NumOfTokensPriorToVAOpt = NumPriorTokens; + assert(NumOfTokensPriorToVAOpt > -1 && + "Too many prior tokens"); + } + + SourceLocation getVAOptLoc() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid"); + return VAOptLoc; + } + using VAOptDefinitionContext::isVAOptToken; + using VAOptDefinitionContext::isInVAOpt; + using VAOptDefinitionContext::sawClosingParen; + using VAOptDefinitionContext::sawOpeningParen; + + }; +} // end namespace clang + +#endif diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt index ec75f7b96b..2cc7e54b3b 100644 --- a/include/clang/Parse/CMakeLists.txt +++ b/include/clang/Parse/CMakeLists.txt @@ -2,3 +2,9 @@ clang_tablegen(AttrParserStringSwitches.inc -gen-clang-attr-parser-string-switch -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE ../Basic/Attr.td TARGET ClangAttrParserStringSwitches) + +clang_tablegen(AttrSubMatchRulesParserStringSwitches.inc + -gen-clang-attr-subject-match-rules-parser-string-switches + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrSubMatchRulesParserStringSwitches) diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h index 21f9701c3e..34c96816eb 100644 --- a/include/clang/Parse/ParseAST.h +++ b/include/clang/Parse/ParseAST.h @@ -29,10 +29,13 @@ namespace clang { /// This operation inserts the parsed decls into the translation /// unit held by Ctx. /// + /// \param PrintStats Whether to print LLVM statistics related to parsing. /// \param TUKind The kind of translation unit being parsed. - /// /// \param CompletionConsumer If given, an object to consume code completion /// results. + /// \param SkipFunctionBodies Whether to skip parsing of function bodies. + /// This option can be used, for example, to speed up searches for + /// declarations/definitions when indexing. void ParseAST(Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, bool PrintStats = false, TranslationUnitKind TUKind = TU_Complete, @@ -43,7 +46,7 @@ namespace clang { /// abstract syntax tree. void ParseAST(Sema &S, bool PrintStats = false, bool SkipFunctionBodies = false); - + } // end namespace clang #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 70381e507e..ce60cbb431 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -166,6 +166,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr<PragmaHandler> FPContractHandler; std::unique_ptr<PragmaHandler> OpenCLExtensionHandler; std::unique_ptr<PragmaHandler> OpenMPHandler; + std::unique_ptr<PragmaHandler> PCSectionHandler; std::unique_ptr<PragmaHandler> MSCommentHandler; std::unique_ptr<PragmaHandler> MSDetectMismatchHandler; std::unique_ptr<PragmaHandler> MSPointersToMembers; @@ -183,6 +184,8 @@ class Parser : public CodeCompletionHandler { std::unique_ptr<PragmaHandler> LoopHintHandler; std::unique_ptr<PragmaHandler> UnrollHintHandler; std::unique_ptr<PragmaHandler> NoUnrollHintHandler; + std::unique_ptr<PragmaHandler> FPHandler; + std::unique_ptr<PragmaHandler> AttributePragmaHandler; std::unique_ptr<CommentHandler> CommentSemaHandler; @@ -250,6 +253,10 @@ class Parser : public CodeCompletionHandler { /// be NULL. bool ParsingInObjCContainer; + /// Whether to skip parsing of function bodies. + /// + /// This option can be used, for example, to speed up searches for + /// declarations/definitions when indexing. bool SkipFunctionBodies; /// The location of the expression statement that is being parsed right now. @@ -302,8 +309,9 @@ public: } /// ConsumeToken - Consume the current 'peek token' and lex the next one. - /// This does not work with special tokens: string literals, code completion - /// and balanced tokens must be handled using the specific consume methods. + /// This does not work with special tokens: string literals, code completion, + /// annotation tokens and balanced tokens must be handled using the specific + /// consume methods. /// Returns the location of the consumed token. SourceLocation ConsumeToken() { assert(!isTokenSpecial() && @@ -330,6 +338,27 @@ public: return true; } + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the + /// current token type. This should only be used in cases where the type of + /// the token really isn't known, e.g. in error recovery. + SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { + if (isTokenParen()) + return ConsumeParen(); + if (isTokenBracket()) + return ConsumeBracket(); + if (isTokenBrace()) + return ConsumeBrace(); + if (isTokenStringLiteral()) + return ConsumeStringToken(); + if (Tok.is(tok::code_completion)) + return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() + : handleUnexpectedCodeCompletionToken(); + if (Tok.isAnnotation()) + return ConsumeAnnotationToken(); + return ConsumeToken(); + } + + SourceLocation getEndOfPreviousToken() { return PP.getLocForEndOfToken(PrevTokLocation); } @@ -364,7 +393,7 @@ private: /// isTokenSpecial - True if this token requires special consumption methods. bool isTokenSpecial() const { return isTokenStringLiteral() || isTokenParen() || isTokenBracket() || - isTokenBrace() || Tok.is(tok::code_completion); + isTokenBrace() || Tok.is(tok::code_completion) || Tok.isAnnotation(); } /// \brief Returns true if the current token is '=' or is a type of '='. @@ -380,22 +409,12 @@ private: PP.EnterToken(Next); } - /// ConsumeAnyToken - Dispatch to the right Consume* method based on the - /// current token type. This should only be used in cases where the type of - /// the token really isn't known, e.g. in error recovery. - SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { - if (isTokenParen()) - return ConsumeParen(); - if (isTokenBracket()) - return ConsumeBracket(); - if (isTokenBrace()) - return ConsumeBrace(); - if (isTokenStringLiteral()) - return ConsumeStringToken(); - if (Tok.is(tok::code_completion)) - return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() - : handleUnexpectedCodeCompletionToken(); - return ConsumeToken(); + SourceLocation ConsumeAnnotationToken() { + assert(Tok.isAnnotation() && "wrong consume method"); + SourceLocation Loc = Tok.getLocation(); + PrevTokLocation = Tok.getAnnotationEndLoc(); + PP.Lex(Tok); + return Loc; } /// ConsumeParen - This consume method keeps the paren count up-to-date. @@ -487,6 +506,12 @@ private: Kind == tok::annot_module_end || Kind == tok::annot_module_include; } + /// \brief Checks if the \p Level is valid for use in a fold expression. + bool isFoldOperator(prec::Level Level) const; + + /// \brief Checks if the \p Kind is a valid operator for fold expressions. + bool isFoldOperator(tok::TokenKind Kind) const; + /// \brief Initialize all pragma handlers. void initializePragmaHandlers(); @@ -549,6 +574,10 @@ private: void HandlePragmaFPContract(); /// \brief Handle the annotation token produced for + /// #pragma clang fp ... + void HandlePragmaFP(); + + /// \brief Handle the annotation token produced for /// #pragma OPENCL EXTENSION... void HandlePragmaOpenCLExtension(); @@ -560,6 +589,12 @@ private: /// #pragma clang loop and #pragma unroll. bool HandlePragmaLoopHint(LoopHint &Hint); + bool ParsePragmaAttributeSubjectMatchRuleSet( + attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, + SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc); + + void HandlePragmaAttribute(); + /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) /// returns the token after Tok, etc. @@ -580,7 +615,7 @@ public: } /// getTypeAnnotation - Read a parsed type out of an annotation token. - static ParsedType getTypeAnnotation(Token &Tok) { + static ParsedType getTypeAnnotation(const Token &Tok) { return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); } @@ -591,7 +626,7 @@ private: /// \brief Read an already-translated primary expression out of an annotation /// token. - static ExprResult getExprAnnotation(Token &Tok) { + static ExprResult getExprAnnotation(const Token &Tok) { return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue()); } @@ -795,6 +830,14 @@ private: /// \brief Consume any extra semi-colons until the end of the line. void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified); + /// Return false if the next token is an identifier. An 'expected identifier' + /// error is emitted otherwise. + /// + /// The parser tries to recover from the error by checking if the next token + /// is a C++ keyword when parsing Objective-C++. Return false if the recovery + /// was successful. + bool expectIdentifier(); + public: //===--------------------------------------------------------------------===// // Scope manipulation @@ -1429,6 +1472,8 @@ public: }; ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstantExpressionInExprEvalContext( + TypeCastState isTypeCast = NotTypeCast); ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); ExprResult ParseConstraintExpression(); // Expr that doesn't include commas. @@ -1436,7 +1481,6 @@ public: ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, unsigned &NumLineToksConsumed, - void *Info, bool IsUnevaluated); private: @@ -1449,10 +1493,12 @@ private: ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - TypeCastState isTypeCast); + TypeCastState isTypeCast, + bool isVectorLiteral = false); ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, - TypeCastState isTypeCast = NotTypeCast); + TypeCastState isTypeCast = NotTypeCast, + bool isVectorLiteral = false); /// Returns true if the next token cannot start an expression. bool isNotExpressionStart(); @@ -1466,6 +1512,8 @@ private: K == tok::plusplus || K == tok::minusminus); } + bool diagnoseUnknownTemplateId(ExprResult TemplateName, SourceLocation Less); + ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); ExprResult ParseUnaryExprOrTypeTraitExpression(); ExprResult ParseBuiltinPrimaryExpression(); @@ -1479,9 +1527,10 @@ private: typedef SmallVector<SourceLocation, 20> CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, - SmallVectorImpl<SourceLocation> &CommaLocs, - std::function<void()> Completer = nullptr); + bool ParseExpressionList( + SmallVectorImpl<Expr *> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs, + llvm::function_ref<void()> Completer = llvm::function_ref<void()>()); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. @@ -1534,7 +1583,8 @@ private: bool EnteringContext, bool *MayBePseudoDestructor = nullptr, bool IsTypename = false, - IdentifierInfo **LastII = nullptr); + IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false); //===--------------------------------------------------------------------===// // C++0x 5.1.2: Lambda expressions @@ -1686,7 +1736,7 @@ private: StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr, bool AllowOpenMPStandalone = false); - enum AllowedContsructsKind { + enum AllowedConstructsKind { /// \brief Allow any declarations, statements, OpenMP directives. ACK_Any, /// \brief Allow only statements and non-standalone OpenMP directives. @@ -1695,11 +1745,11 @@ private: ACK_StatementsOpenMPAnyExecutable }; StmtResult - ParseStatementOrDeclaration(StmtVector &Stmts, AllowedContsructsKind Allowed, + ParseStatementOrDeclaration(StmtVector &Stmts, AllowedConstructsKind Allowed, SourceLocation *TrailingElseLoc = nullptr); StmtResult ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, - AllowedContsructsKind Allowed, + AllowedConstructsKind Allowed, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs); StmtResult ParseExprStatement(); @@ -1728,7 +1778,7 @@ private: StmtResult ParseAsmStatement(bool &msAsm); StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); StmtResult ParsePragmaLoopHint(StmtVector &Stmts, - AllowedContsructsKind Allowed, + AllowedConstructsKind Allowed, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs); @@ -1813,6 +1863,7 @@ private: DSC_trailing, // C++11 trailing-type-specifier in a trailing return type DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration DSC_top_level, // top-level/namespace declaration context + DSC_template_param, // template parameter context DSC_template_type_arg, // template type argument context DSC_objc_method_result, // ObjC method result context, enables 'instancetype' DSC_condition // condition declaration context @@ -1823,6 +1874,7 @@ private: static bool isTypeSpecifier(DeclSpecContext DSC) { switch (DSC) { case DSC_normal: + case DSC_template_param: case DSC_class: case DSC_top_level: case DSC_objc_method_result: @@ -1843,6 +1895,7 @@ private: static bool isClassTemplateDeductionContext(DeclSpecContext DSC) { switch (DSC) { case DSC_normal: + case DSC_template_param: case DSC_class: case DSC_top_level: case DSC_condition: @@ -2117,18 +2170,25 @@ public: private: void ParseBlockId(SourceLocation CaretLoc); - // Check for the start of a C++11 attribute-specifier-seq in a context where - // an attribute is not allowed. + /// Are [[]] attributes enabled? + bool standardAttributesAllowed() const { + const LangOptions &LO = getLangOpts(); + return LO.DoubleSquareBracketAttributes; + } + + // Check for the start of an attribute-specifier-seq in a context where an + // attribute is not allowed. bool CheckProhibitedCXX11Attribute() { assert(Tok.is(tok::l_square)); - if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square)) + if (!standardAttributesAllowed() || NextToken().isNot(tok::l_square)) return false; return DiagnoseProhibitedCXX11Attribute(); } + bool DiagnoseProhibitedCXX11Attribute(); void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, SourceLocation CorrectLocation) { - if (!getLangOpts().CPlusPlus11) + if (!standardAttributesAllowed()) return; if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && Tok.isNot(tok::kw_alignas)) @@ -2148,17 +2208,18 @@ private: } void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); - // Forbid C++11 attributes that appear on certain syntactic - // locations which standard permits but we don't supported yet, - // for example, attributes appertain to decl specifiers. + // Forbid C++11 and C2x attributes that appear on certain syntactic locations + // which standard permits but we don't supported yet, for example, attributes + // appertain to decl specifiers. void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, unsigned DiagID); - /// \brief Skip C++11 attributes and return the end location of the last one. + /// \brief Skip C++11 and C2x attributes and return the end location of the + /// last one. /// \returns SourceLocation() if there are no attributes. SourceLocation SkipCXX11Attributes(); - /// \brief Diagnose and skip C++11 attributes that appear in syntactic + /// \brief Diagnose and skip C++11 and C2x attributes that appear in syntactic /// locations where attributes are not allowed. void DiagnoseAndSkipCXX11Attributes(); @@ -2208,7 +2269,7 @@ private: AttributeList::Syntax Syntax); void MaybeParseCXX11Attributes(Declarator &D) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; ParseCXX11Attributes(attrs, &endLoc); @@ -2217,7 +2278,7 @@ private: } void MaybeParseCXX11Attributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); ParseCXX11Attributes(attrsWithRange, endLoc); attrs.takeAllFrom(attrsWithRange); @@ -2226,8 +2287,8 @@ private: void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = nullptr, bool OuterMightBeMessageSend = false) { - if (getLangOpts().CPlusPlus11 && - isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) + if (standardAttributesAllowed() && + isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) ParseCXX11Attributes(attrs, endLoc); } @@ -2235,8 +2296,8 @@ private: SourceLocation *EndLoc = nullptr); void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *EndLoc = nullptr); - /// \brief Parses a C++-style attribute argument list. Returns true if this - /// results in adding an attribute to the ParsedAttributes list. + /// \brief Parses a C++11 (or C2x)-style attribute argument list. Returns true + /// if this results in adding an attribute to the ParsedAttributes list. bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, @@ -2566,6 +2627,9 @@ private: Decl *TagDecl = nullptr); /// \brief Parse 'omp declare reduction' construct. DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS); + /// Parses initializer for provided omp_priv declaration inside the reduction + /// initializer. + void ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm); /// \brief Parses simple list of variables. /// @@ -2587,7 +2651,7 @@ private: /// executable directives are allowed. /// StmtResult - ParseOpenMPDeclarativeOrExecutableDirective(AllowedContsructsKind Allowed); + ParseOpenMPDeclarativeOrExecutableDirective(AllowedConstructsKind Allowed); /// \brief Parses clause of kind \a CKind for directive of a kind \a Kind. /// /// \param DKind Kind of current directive. @@ -2678,11 +2742,11 @@ private: AccessSpecifier AS=AS_none, AttributeList *AccessAttrs = nullptr); bool ParseTemplateParameters(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams, + SmallVectorImpl<NamedDecl *> &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams); + SmallVectorImpl<NamedDecl*> &TemplateParams); bool isStartOfTemplateTypeParameter(); Decl *ParseTemplateParameter(unsigned Depth, unsigned Position); Decl *ParseTypeParameter(unsigned Depth, unsigned Position); @@ -2700,10 +2764,7 @@ private: bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList); - bool ParseTemplateIdAfterTemplateName(TemplateTy Template, - SourceLocation TemplateNameLoc, - const CXXScopeSpec &SS, - bool ConsumeLastToken, + bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, SourceLocation &RAngleLoc); diff --git a/include/clang/Parse/RAIIObjectsForParser.h b/include/clang/Parse/RAIIObjectsForParser.h new file mode 100644 index 0000000000..0422b038da --- /dev/null +++ b/include/clang/Parse/RAIIObjectsForParser.h @@ -0,0 +1,467 @@ +//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines and implements the some simple RAII objects that are used +// by the parser to manage bits in recursion. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H +#define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H + +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Sema.h" + +namespace clang { + // TODO: move ParsingClassDefinition here. + // TODO: move TentativeParsingAction here. + + /// \brief A RAII object used to temporarily suppress access-like + /// checking. Access-like checks are those associated with + /// controlling the use of a declaration, like C++ access control + /// errors and deprecation warnings. They are contextually + /// dependent, in that they can only be resolved with full + /// information about what's being declared. They are also + /// suppressed in certain contexts, like the template arguments of + /// an explicit instantiation. However, those suppression contexts + /// cannot necessarily be fully determined in advance; for + /// example, something starting like this: + /// template <> class std::vector<A::PrivateType> + /// might be the entirety of an explicit instantiation: + /// template <> class std::vector<A::PrivateType>; + /// or just an elaborated type specifier: + /// template <> class std::vector<A::PrivateType> make_vector<>(); + /// Therefore this class collects all the diagnostics and permits + /// them to be re-delayed in a new context. + class SuppressAccessChecks { + Sema &S; + sema::DelayedDiagnosticPool DiagnosticPool; + Sema::ParsingDeclState State; + bool Active; + + public: + /// Begin suppressing access-like checks + SuppressAccessChecks(Parser &P, bool activate = true) + : S(P.getActions()), DiagnosticPool(nullptr) { + if (activate) { + State = S.PushParsingDeclaration(DiagnosticPool); + Active = true; + } else { + Active = false; + } + } + SuppressAccessChecks(SuppressAccessChecks &&Other) + : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), + State(Other.State), Active(Other.Active) { + Other.Active = false; + } + void operator=(SuppressAccessChecks &&Other) = delete; + + void done() { + assert(Active && "trying to end an inactive suppression"); + S.PopParsingDeclaration(State, nullptr); + Active = false; + } + + void redelay() { + assert(!Active && "redelaying without having ended first"); + if (!DiagnosticPool.pool_empty()) + S.redelayDiagnostics(DiagnosticPool); + assert(DiagnosticPool.pool_empty()); + } + + ~SuppressAccessChecks() { + if (Active) done(); + } + }; + + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Sema &Actions; + sema::DelayedDiagnosticPool DiagnosticPool; + Sema::ParsingDeclState State; + bool Popped; + + ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete; + void operator=(const ParsingDeclRAIIObject &) = delete; + + public: + enum NoParent_t { NoParent }; + ParsingDeclRAIIObject(Parser &P, NoParent_t _) + : Actions(P.getActions()), DiagnosticPool(nullptr) { + push(); + } + + /// Creates a RAII object whose pool is optionally parented by another. + ParsingDeclRAIIObject(Parser &P, + const sema::DelayedDiagnosticPool *parentPool) + : Actions(P.getActions()), DiagnosticPool(parentPool) { + push(); + } + + /// Creates a RAII object and, optionally, initialize its + /// diagnostics pool by stealing the diagnostics from another + /// RAII object (which is assumed to be the current top pool). + ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) + : Actions(P.getActions()), + DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { + if (other) { + DiagnosticPool.steal(other->DiagnosticPool); + other->abort(); + } + push(); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { + return DiagnosticPool; + } + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return DiagnosticPool; + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(nullptr); + } + + void complete(Decl *D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + /// Unregister this object from Sema, but remember all the + /// diagnostics that were emitted into it. + void abortAndRemember() { + pop(nullptr); + } + + private: + void push() { + State = Actions.PushParsingDeclaration(DiagnosticPool); + Popped = false; + } + + void pop(Decl *D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} + ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, RAII) {} + + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return ParsingRAII.getDelayedDiagnosticPool(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + + /// A class for parsing a field declarator. + class ParsingFieldDeclarator : public FieldDeclarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) + : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + + /// ExtensionRAIIObject - This saves the state of extension warnings when + /// constructed and disables them. When destructed, it restores them back to + /// the way they used to be. This is used to handle __extension__ in the + /// parser. + class ExtensionRAIIObject { + ExtensionRAIIObject(const ExtensionRAIIObject &) = delete; + void operator=(const ExtensionRAIIObject &) = delete; + + DiagnosticsEngine &Diags; + public: + ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { + Diags.IncrementAllExtensionsSilenced(); + } + + ~ExtensionRAIIObject() { + Diags.DecrementAllExtensionsSilenced(); + } + }; + + /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and + /// restores it when destroyed. This says that "foo:" should not be + /// considered a possible typo for "foo::" for error recovery purposes. + class ColonProtectionRAIIObject { + Parser &P; + bool OldVal; + public: + ColonProtectionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ColonIsSacred) { + P.ColonIsSacred = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { + P.ColonIsSacred = OldVal; + } + + ~ColonProtectionRAIIObject() { + restore(); + } + }; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + class GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + public: + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + + class InMessageExpressionRAIIObject { + bool &InMessageExpression; + bool OldValue; + + public: + InMessageExpressionRAIIObject(Parser &P, bool Value) + : InMessageExpression(P.InMessageExpression), + OldValue(P.InMessageExpression) { + InMessageExpression = Value; + } + + ~InMessageExpressionRAIIObject() { + InMessageExpression = OldValue; + } + }; + + /// \brief RAII object that makes sure paren/bracket/brace count is correct + /// after declaration/statement parsing, even when there's a parsing error. + class ParenBraceBracketBalancer { + Parser &P; + unsigned short ParenCount, BracketCount, BraceCount; + public: + ParenBraceBracketBalancer(Parser &p) + : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), + BraceCount(p.BraceCount) { } + + ~ParenBraceBracketBalancer() { + P.ParenCount = ParenCount; + P.BracketCount = BracketCount; + P.BraceCount = BraceCount; + } + }; + + class PoisonSEHIdentifiersRAIIObject { + PoisonIdentifierRAIIObject Ident_AbnormalTermination; + PoisonIdentifierRAIIObject Ident_GetExceptionCode; + PoisonIdentifierRAIIObject Ident_GetExceptionInfo; + PoisonIdentifierRAIIObject Ident__abnormal_termination; + PoisonIdentifierRAIIObject Ident__exception_code; + PoisonIdentifierRAIIObject Ident__exception_info; + PoisonIdentifierRAIIObject Ident___abnormal_termination; + PoisonIdentifierRAIIObject Ident___exception_code; + PoisonIdentifierRAIIObject Ident___exception_info; + public: + PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) + : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), + Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), + Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), + Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), + Ident__exception_code(Self.Ident__exception_code, NewValue), + Ident__exception_info(Self.Ident__exception_info, NewValue), + Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), + Ident___exception_code(Self.Ident___exception_code, NewValue), + Ident___exception_info(Self.Ident___exception_info, NewValue) { + } + }; + + /// \brief RAII class that helps handle the parsing of an open/close delimiter + /// pair, such as braces { ... } or parentheses ( ... ). + class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { + Parser& P; + tok::TokenKind Kind, Close, FinalToken; + SourceLocation (Parser::*Consumer)(); + SourceLocation LOpen, LClose; + + unsigned short &getDepth() { + switch (Kind) { + case tok::l_brace: return P.BraceCount; + case tok::l_square: return P.BracketCount; + case tok::l_paren: return P.ParenCount; + default: llvm_unreachable("Wrong token kind"); + } + } + + enum { MaxDepth = 256 }; + + bool diagnoseOverflow(); + bool diagnoseMissingClose(); + + public: + BalancedDelimiterTracker(Parser& p, tok::TokenKind k, + tok::TokenKind FinalToken = tok::semi) + : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), + P(p), Kind(k), FinalToken(FinalToken) + { + switch (Kind) { + default: llvm_unreachable("Unexpected balanced token"); + case tok::l_brace: + Close = tok::r_brace; + Consumer = &Parser::ConsumeBrace; + break; + case tok::l_paren: + Close = tok::r_paren; + Consumer = &Parser::ConsumeParen; + break; + + case tok::l_square: + Close = tok::r_square; + Consumer = &Parser::ConsumeBracket; + break; + } + } + + SourceLocation getOpenLocation() const { return LOpen; } + SourceLocation getCloseLocation() const { return LClose; } + SourceRange getRange() const { return SourceRange(LOpen, LClose); } + + bool consumeOpen() { + if (!P.Tok.is(Kind)) + return true; + + if (getDepth() < P.getLangOpts().BracketDepth) { + LOpen = (P.*Consumer)(); + return false; + } + + return diagnoseOverflow(); + } + + bool expectAndConsume(unsigned DiagID = diag::err_expected, + const char *Msg = "", + tok::TokenKind SkipToTok = tok::unknown); + bool consumeClose() { + if (P.Tok.is(Close)) { + LClose = (P.*Consumer)(); + return false; + } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) { + SourceLocation SemiLoc = P.ConsumeToken(); + P.Diag(SemiLoc, diag::err_unexpected_semi) + << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); + LClose = (P.*Consumer)(); + return false; + } + + return diagnoseMissingClose(); + } + void skipToEnd(); + }; + + /// \brief RAIIObject to destroy the contents of a SmallVector of + /// TemplateIdAnnotation pointers and clear the vector. + class DestroyTemplateIdAnnotationsRAIIObj { + SmallVectorImpl<TemplateIdAnnotation *> &Container; + + public: + DestroyTemplateIdAnnotationsRAIIObj( + SmallVectorImpl<TemplateIdAnnotation *> &Container) + : Container(Container) {} + + ~DestroyTemplateIdAnnotationsRAIIObj() { + for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I = + Container.begin(), + E = Container.end(); + I != E; ++I) + (*I)->Destroy(); + Container.clear(); + } + }; +} // end namespace clang + +#endif diff --git a/include/clang/Rewrite/Frontend/FrontendActions.h b/include/clang/Rewrite/Frontend/FrontendActions.h index 27976eac4e..5f83ac16fe 100644 --- a/include/clang/Rewrite/Frontend/FrontendActions.h +++ b/include/clang/Rewrite/Frontend/FrontendActions.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H #include "clang/Frontend/FrontendAction.h" +#include "llvm/Support/raw_ostream.h" namespace clang { class FixItRewriter; @@ -34,8 +35,7 @@ protected: std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; - bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) override; + bool BeginSourceFileAction(CompilerInstance &CI) override; void EndSourceFileAction() override; @@ -74,7 +74,10 @@ protected: }; class RewriteIncludesAction : public PreprocessorFrontendAction { + std::shared_ptr<raw_ostream> OutputStream; + class RewriteImportsListener; protected: + bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; }; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 7c1678086c..0580ff8850 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H #define LLVM_CLANG_SEMA_ATTRIBUTELIST_H +#include "clang/Basic/AttrSubjectMatchRules.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/VersionTuple.h" @@ -99,16 +100,20 @@ public: AS_GNU, /// [[...]] AS_CXX11, + /// [[...]] + AS_C2x, /// __declspec(...) AS_Declspec, /// [uuid("...")] class Foo AS_Microsoft, /// __ptr16, alignas(...), etc. AS_Keyword, - /// Context-sensitive version of a keyword attribute. - AS_ContextSensitiveKeyword, /// #pragma ... AS_Pragma, + // Note TableGen depends on the order above. Do not add or change the order + // without adding related code to TableGen/ClangAttrEmitter.cpp. + /// Context-sensitive version of a keyword attribute. + AS_ContextSensitiveKeyword, }; private: @@ -375,6 +380,9 @@ public: bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || isAlignasAttribute(); } + bool isC2xAttribute() const { + return SyntaxUsed == AS_C2x; + } bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; } @@ -509,9 +517,14 @@ public: unsigned getMaxArgs() const; bool hasVariadicArg() const; bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const; + bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const; + void getMatchRules(const LangOptions &LangOpts, + SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> + &MatchRules) const; bool diagnoseLangOpts(class Sema &S) const; bool existsInTarget(const TargetInfo &Target) const; bool isKnownToGCC() const; + bool isSupportedByPragmaAttribute() const; /// \brief If the parsed attribute has a semantic equivalent, and it would /// have a semantic Spelling enumeration (due to having semantically-distinct @@ -774,6 +787,8 @@ public: void clear() { list = nullptr; pool.clear(); } AttributeList *getList() const { return list; } + void clearListOnly() { list = nullptr; } + /// Returns a reference to the attribute list. Try not to introduce /// dependencies on this method, it may not be long-lived. AttributeList *&getListRef() { return list; } @@ -907,6 +922,7 @@ enum AttributeDeclKind { ExpectedTypeOrNamespace, ExpectedObjectiveCInterface, ExpectedMethodOrProperty, + ExpectedFunctionOrMethodOrProperty, ExpectedStructOrUnion, ExpectedStructOrUnionOrClass, ExpectedType, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 82f04a584b..4fc55a1dac 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -280,6 +280,7 @@ public: static const TST TST_half = clang::TST_half; static const TST TST_float = clang::TST_float; static const TST TST_double = clang::TST_double; + static const TST TST_float16 = clang::TST_Float16; static const TST TST_float128 = clang::TST_float128; static const TST TST_bool = clang::TST_bool; static const TST TST_decimal32 = clang::TST_decimal32; @@ -861,11 +862,19 @@ public: const IdentifierInfo *getGetterName() const { return GetterName; } IdentifierInfo *getGetterName() { return GetterName; } - void setGetterName(IdentifierInfo *name) { GetterName = name; } + SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(IdentifierInfo *name, SourceLocation loc) { + GetterName = name; + GetterNameLoc = loc; + } const IdentifierInfo *getSetterName() const { return SetterName; } IdentifierInfo *getSetterName() { return SetterName; } - void setSetterName(IdentifierInfo *name) { SetterName = name; } + SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(IdentifierInfo *name, SourceLocation loc) { + SetterName = name; + SetterNameLoc = loc; + } private: // FIXME: These two are unrelated and mutually exclusive. So perhaps @@ -882,6 +891,9 @@ private: IdentifierInfo *GetterName; // getter name or NULL if no getter IdentifierInfo *SetterName; // setter name or NULL if no setter + SourceLocation GetterNameLoc; // location of the getter attribute's value + SourceLocation SetterNameLoc; // location of the setter attribute's value + }; /// \brief Represents a C++ unqualified-id that has been parsed. @@ -1988,41 +2000,6 @@ public: llvm_unreachable("unknown context kind!"); } - /// diagnoseIdentifier - Return true if the identifier is prohibited and - /// should be diagnosed (because it cannot be anything else). - bool diagnoseIdentifier() const { - switch (Context) { - case FileContext: - case KNRTypeListContext: - case MemberContext: - case BlockContext: - case ForContext: - case InitStmtContext: - case ConditionContext: - case PrototypeContext: - case LambdaExprParameterContext: - case TemplateParamContext: - case CXXCatchContext: - case ObjCCatchContext: - case TypeNameContext: - case FunctionalCastContext: - case ConversionIdContext: - case ObjCParameterContext: - case ObjCResultContext: - case BlockLiteralContext: - case CXXNewContext: - case LambdaExprContext: - return false; - - case AliasDeclContext: - case AliasTemplateContext: - case TemplateTypeArgContext: - case TrailingReturnContext: - return true; - } - llvm_unreachable("unknown context kind!"); - } - /// Return true if the context permits a C++17 decomposition declarator. bool mayHaveDecompositionDeclarator() const { switch (Context) { @@ -2324,6 +2301,42 @@ public: } llvm_unreachable("unknown context kind!"); } + + /// Determine whether this declaration appears in a context where an + /// expression could appear. + bool isExpressionContext() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case TypeNameContext: // FIXME: sizeof(...) permits an expression. + case FunctionalCastContext: + case AliasDeclContext: + case AliasTemplateContext: + case PrototypeContext: + case LambdaExprParameterContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXNewContext: + case CXXCatchContext: + case ObjCCatchContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TrailingReturnContext: + return false; + + case BlockContext: + case ForContext: + case InitStmtContext: + case ConditionContext: + case TemplateTypeArgContext: + return true; + } + + llvm_unreachable("unknown context kind!"); + } /// \brief Return true if a function declarator at this position would be a /// function declaration. diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h index b73ec0868f..d65dbf0cd3 100644 --- a/include/clang/Sema/DelayedDiagnostic.h +++ b/include/clang/Sema/DelayedDiagnostic.h @@ -124,7 +124,8 @@ public: static DelayedDiagnostic makeAvailability(AvailabilityResult AR, SourceLocation Loc, - const NamedDecl *D, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, @@ -164,9 +165,13 @@ public: return *reinterpret_cast<const AccessedEntity*>(AccessData); } - const NamedDecl *getAvailabilityDecl() const { + const NamedDecl *getAvailabilityReferringDecl() const { assert(Kind == Availability && "Not an availability diagnostic."); - return AvailabilityData.Decl; + return AvailabilityData.ReferringDecl; + } + + const NamedDecl *getAvailabilityOffendingDecl() const { + return AvailabilityData.OffendingDecl; } StringRef getAvailabilityMessage() const { @@ -213,7 +218,8 @@ public: private: struct AD { - const NamedDecl *Decl; + const NamedDecl *ReferringDecl; + const NamedDecl *OffendingDecl; const ObjCInterfaceDecl *UnknownObjCClass; const ObjCPropertyDecl *ObjCProperty; const char *Message; diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h index a07834f956..382fe80bea 100644 --- a/include/clang/Sema/IdentifierResolver.h +++ b/include/clang/Sema/IdentifierResolver.h @@ -73,12 +73,10 @@ public: typedef std::input_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; - /// Ptr - There are 3 forms that 'Ptr' represents: + /// Ptr - There are 2 forms that 'Ptr' represents: /// 1) A single NamedDecl. (Ptr & 0x1 == 0) /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the - /// same declaration context. (Ptr & 0x3 == 0x1) - /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent - /// declaration contexts too. (Ptr & 0x3 == 0x3) + /// same declaration context. (Ptr & 0x1 == 0x1) uintptr_t Ptr; typedef IdDeclInfo::DeclsTy::iterator BaseIter; @@ -97,7 +95,7 @@ public: BaseIter getIterator() const { assert(isIterator() && "Ptr not an iterator!"); - return reinterpret_cast<BaseIter>(Ptr & ~0x3); + return reinterpret_cast<BaseIter>(Ptr & ~0x1); } friend class IdentifierResolver; @@ -128,14 +126,6 @@ public: incrementSlowCase(); return *this; } - - uintptr_t getAsOpaqueValue() const { return Ptr; } - - static iterator getFromOpaqueValue(uintptr_t P) { - iterator Result; - Result.Ptr = P; - return Result; - } }; /// begin - Returns an iterator for decls with the name 'Name'. diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 7b13867cdf..bd07b9ea9a 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -70,6 +70,9 @@ public: /// \brief The entity being initialized is a field of block descriptor for /// the copied-in c++ object. EK_BlockElement, + /// The entity being initialized is a field of block descriptor for the + /// copied-in lambda object that's used in the lambda to block conversion. + EK_LambdaToBlockConversionBlockElement, /// \brief The entity being initialized is the real or imaginary part of a /// complex number. EK_ComplexElement, @@ -260,7 +263,13 @@ public: QualType Type, bool NRVO) { return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); } - + + static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_LambdaToBlockConversionBlockElement, + BlockVarLoc, Type, NRVO); + } + /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, QualType Type, bool NRVO) { @@ -822,6 +831,8 @@ public: enum FailureKind { /// \brief Too many initializers provided for a reference. FK_TooManyInitsForReference, + /// \brief Reference initialized from a parenthesized initializer list. + FK_ParenthesizedListInitForReference, /// \brief Array must be initialized with an initializer list. FK_ArrayNeedsInitList, /// \brief Array must be initialized with an initializer list or a @@ -866,6 +877,8 @@ public: FK_ConversionFromPropertyFailed, /// \brief Too many initializers for scalar FK_TooManyInitsForScalar, + /// \brief Scalar initialized from a parenthesized initializer list. + FK_ParenthesizedListInitForScalar, /// \brief Reference initialization from an initializer list FK_ReferenceBindingToInitList, /// \brief Initialization of some unused destination type with an @@ -892,7 +905,7 @@ public: /// having its address taken. FK_AddressOfUnaddressableFunction, /// \brief List-copy-initialization chose an explicit constructor. - FK_ExplicitConstructor + FK_ExplicitConstructor, }; private: diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index 2ed9548b59..546df8842a 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -18,6 +18,8 @@ #include "clang/AST/DeclCXX.h" #include "clang/Sema/Sema.h" +#include "llvm/ADT/Optional.h" + namespace clang { /// @brief Represents the results of name lookup. @@ -137,6 +139,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -146,7 +149,7 @@ public: } // TODO: consider whether this constructor should be restricted to take - // as input a const IndentifierInfo* (instead of Name), + // as input a const IdentifierInfo* (instead of Name), // forcing other cases towards the constructor taking a DNInfo. LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, Sema::LookupNameKind LookupKind, @@ -159,6 +162,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -179,6 +183,7 @@ public: LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl), + ExternalRedecl(Other.ExternalRedecl), HideTags(Other.HideTags), Diagnose(false), AllowHidden(Other.AllowHidden), @@ -199,7 +204,9 @@ public: SemaPtr(std::move(Other.SemaPtr)), NameInfo(std::move(Other.NameInfo)), NameContextRange(std::move(Other.NameContextRange)), LookupKind(std::move(Other.LookupKind)), IDNS(std::move(Other.IDNS)), - Redecl(std::move(Other.Redecl)), HideTags(std::move(Other.HideTags)), + Redecl(std::move(Other.Redecl)), + ExternalRedecl(std::move(Other.ExternalRedecl)), + HideTags(std::move(Other.HideTags)), Diagnose(std::move(Other.Diagnose)), AllowHidden(std::move(Other.AllowHidden)), Shadowed(std::move(Other.Shadowed)) { @@ -219,6 +226,7 @@ public: LookupKind = std::move(Other.LookupKind); IDNS = std::move(Other.IDNS); Redecl = std::move(Other.Redecl); + ExternalRedecl = std::move(Other.ExternalRedecl); HideTags = std::move(Other.HideTags); Diagnose = std::move(Other.Diagnose); AllowHidden = std::move(Other.AllowHidden); @@ -263,6 +271,17 @@ public: return Redecl; } + /// True if this lookup is just looking for an existing declaration to link + /// against a declaration with external linkage. + bool isForExternalRedeclaration() const { + return ExternalRedecl; + } + + Sema::RedeclarationKind redeclarationKind() const { + return ExternalRedecl ? Sema::ForExternalRedeclaration : + Redecl ? Sema::ForVisibleRedeclaration : Sema::NotForRedeclaration; + } + /// \brief Specify whether hidden declarations are visible, e.g., /// for recovery reasons. void setAllowHidden(bool AH) { @@ -273,7 +292,7 @@ public: /// declarations, such as those in modules that have not yet been imported. bool isHiddenDeclarationVisible(NamedDecl *ND) const { return AllowHidden || - (isForRedeclaration() && ND->isExternallyVisible()); + (isForExternalRedeclaration() && ND->isExternallyDeclarable()); } /// Sets whether tag declarations should be hidden by non-tag @@ -465,7 +484,7 @@ public: Paths = nullptr; } } else { - AmbiguityKind SavedAK; + llvm::Optional<AmbiguityKind> SavedAK; bool WasAmbiguous = false; if (ResultKind == Ambiguous) { SavedAK = Ambiguity; @@ -479,7 +498,7 @@ public: if (ResultKind == Ambiguous) { (void)WasAmbiguous; assert(WasAmbiguous); - Ambiguity = SavedAK; + Ambiguity = SavedAK.getValue(); } else if (Paths) { deletePaths(Paths); Paths = nullptr; @@ -554,7 +573,8 @@ public: /// \brief Change this lookup's redeclaration kind. void setRedeclarationKind(Sema::RedeclarationKind RK) { - Redecl = RK; + Redecl = (RK != Sema::NotForRedeclaration); + ExternalRedecl = (RK == Sema::ForExternalRedeclaration); configure(); } @@ -717,6 +737,7 @@ private: unsigned IDNS; // set by configure() bool Redecl; + bool ExternalRedecl; /// \brief True if tag declarations should be hidden if non-tags /// are present diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h index 93e83dc026..1d681a0055 100644 --- a/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/include/clang/Sema/MultiplexExternalSemaSource.h @@ -90,7 +90,7 @@ public: /// initializers themselves. CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; - ExtKind hasExternalDefinitions(unsigned ID) override; + ExtKind hasExternalDefinitions(const Decl *D) override; /// \brief Find all declarations with the given name in the /// given context. diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 5220d98730..05cfe53666 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -98,6 +98,7 @@ namespace clang { ICR_Exact_Match = 0, ///< Exact Match ICR_Promotion, ///< Promotion ICR_Conversion, ///< Conversion + ICR_OCL_Scalar_Widening, ///< OpenCL Scalar Widening ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion ICR_Writeback_Conversion, ///< ObjC ARC writeback conversion ICR_C_Conversion, ///< Conversion only allowed in the C standard. @@ -632,12 +633,9 @@ namespace clang { /// Might be a UsingShadowDecl or a FunctionTemplateDecl. DeclAccessPair FoundDecl; - // BuiltinTypes - Provides the return and parameter types of a - // built-in overload candidate. Only valid when Function is NULL. - struct { - QualType ResultTy; - QualType ParamTypes[3]; - } BuiltinTypes; + /// BuiltinParamTypes - Provides the parameter types of a built-in overload + /// candidate. Only valid when Function is NULL. + QualType BuiltinParamTypes[3]; /// Surrogate - The conversion function for which this candidate /// is a surrogate, but only if IsSurrogate is true. @@ -728,11 +726,20 @@ namespace clang { enum CandidateSetKind { /// Normal lookup. CSK_Normal, - /// Lookup for candidates for a call using operator syntax. Candidates - /// that have no parameters of class type will be skipped unless there - /// is a parameter of (reference to) enum type and the corresponding - /// argument is of the same enum type. - CSK_Operator + /// C++ [over.match.oper]: + /// Lookup of operator function candidates in a call using operator + /// syntax. Candidates that have no parameters of class type will be + /// skipped unless there is a parameter of (reference to) enum type and + /// the corresponding argument is of the same enum type. + CSK_Operator, + /// C++ [over.match.copy]: + /// Copy-initialization of an object of class type by user-defined + /// conversion. + CSK_InitByUserDefinedConversion, + /// C++ [over.match.ctor], [over.match.list] + /// Initialization of an object of class type by constructor, + /// using either a parenthesized or braced list of arguments. + CSK_InitByConstructor, }; private: @@ -797,7 +804,7 @@ namespace clang { } /// \brief Clear out all of the candidates. - void clear(); + void clear(CandidateSetKind CSK); typedef SmallVectorImpl<OverloadCandidate>::iterator iterator; iterator begin() { return Candidates.begin(); } @@ -837,8 +844,7 @@ namespace clang { /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator& Best, - bool UserDefinedConversion = false); + OverloadCandidateSet::iterator& Best); void NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, @@ -850,10 +856,10 @@ namespace clang { }; bool isBetterOverloadCandidate(Sema &S, - const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, SourceLocation Loc, - bool UserDefinedConversion = false); + OverloadCandidateSet::CandidateSetKind Kind); struct ConstructorInfo { DeclAccessPair FoundDecl; diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h index 848837a1de..1e35316fd5 100644 --- a/include/clang/Sema/Ownership.h +++ b/include/clang/Sema/Ownership.h @@ -107,8 +107,7 @@ namespace clang { namespace llvm { template <class T> - class PointerLikeTypeTraits<clang::OpaquePtr<T> > { - public: + struct PointerLikeTypeTraits<clang::OpaquePtr<T> > { static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) { // FIXME: Doesn't work? return P.getAs< void >(); return P.getAsOpaquePtr(); diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h index 03de9ff6ae..01a4ab3f37 100644 --- a/include/clang/Sema/ParsedTemplate.h +++ b/include/clang/Sema/ParsedTemplate.h @@ -145,12 +145,15 @@ namespace clang { /// expressions, or template names, and the source locations for important /// tokens. All of the information about template arguments is allocated /// directly after this structure. - struct TemplateIdAnnotation { + struct TemplateIdAnnotation final + : private llvm::TrailingObjects<TemplateIdAnnotation, + ParsedTemplateArgument> { + friend TrailingObjects; /// \brief The nested-name-specifier that precedes the template name. CXXScopeSpec SS; - /// TemplateKWLoc - The location of the template keyword within the - /// source. + /// TemplateKWLoc - The location of the template keyword. + /// For e.g. typename T::template Y<U> SourceLocation TemplateKWLoc; /// TemplateNameLoc - The location of the template name within the @@ -183,34 +186,56 @@ namespace clang { /// \brief Retrieves a pointer to the template arguments ParsedTemplateArgument *getTemplateArgs() { - return reinterpret_cast<ParsedTemplateArgument *>(this + 1); + return getTrailingObjects<ParsedTemplateArgument>(); } /// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and /// appends it to List. static TemplateIdAnnotation * - Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) { - TemplateIdAnnotation *TemplateId - = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + - sizeof(ParsedTemplateArgument) * NumArgs); - TemplateId->NumArgs = NumArgs; - - // Default-construct nested-name-specifier. - new (&TemplateId->SS) CXXScopeSpec(); - - // Default-construct parsed template arguments. - ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs(); - for (unsigned I = 0; I != NumArgs; ++I) - new (TemplateArgs + I) ParsedTemplateArgument(); - - List.push_back(TemplateId); + Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc, + SourceLocation TemplateNameLoc, IdentifierInfo *Name, + OverloadedOperatorKind OperatorKind, + ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, + SourceLocation LAngleLoc, SourceLocation RAngleLoc, + ArrayRef<ParsedTemplateArgument> TemplateArgs, + SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) { + + TemplateIdAnnotation *TemplateId = new (std::malloc( + totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size()))) + TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name, + OperatorKind, OpaqueTemplateName, TemplateKind, + LAngleLoc, RAngleLoc, TemplateArgs); + CleanupList.push_back(TemplateId); return TemplateId; } - - void Destroy() { - SS.~CXXScopeSpec(); + + void Destroy() { + std::for_each( + getTemplateArgs(), getTemplateArgs() + NumArgs, + [](ParsedTemplateArgument &A) { A.~ParsedTemplateArgument(); }); + this->~TemplateIdAnnotation(); free(this); } + private: + TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; + + TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc, + SourceLocation TemplateNameLoc, IdentifierInfo *Name, + OverloadedOperatorKind OperatorKind, + ParsedTemplateTy OpaqueTemplateName, + TemplateNameKind TemplateKind, + SourceLocation LAngleLoc, SourceLocation RAngleLoc, + ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept + : SS(SS), TemplateKWLoc(TemplateKWLoc), + TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind), + Template(OpaqueTemplateName), Kind(TemplateKind), + LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), + NumArgs(TemplateArgs.size()) { + + std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(), + getTemplateArgs()); + } + ~TemplateIdAnnotation() = default; }; /// Retrieves the range of the given template parameter lists. diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index d0b006b82e..cd58a9910f 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -124,6 +124,12 @@ public: /// We are currently in the filter expression of an SEH except block. SEHFilterScope = 0x200000, + + /// This is a compound statement scope. + CompoundStmtScope = 0x400000, + + /// We are between inheritance colon and the real class/struct definition scope. + ClassInheritanceScope = 0x800000, }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -429,6 +435,11 @@ public: /// \brief Determine whether this scope is a SEH '__except' block. bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; } + /// \brief Determine whether this scope is a compound statement scope. + bool isCompoundStmtScope() const { + return getFlags() & Scope::CompoundStmtScope; + } + /// \brief Returns if rhs has a higher scope depth than this. /// /// The caller is responsible for calling this only if one of the two scopes diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 4487c7c2cc..6bb667deb2 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -388,6 +388,8 @@ public: (HasBranchProtectedScope && HasBranchIntoScope)); } + bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); } + void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) { assert(FirstCoroutineStmtLoc.isInvalid() && "first coroutine statement location already set"); @@ -831,6 +833,12 @@ public: return FSI->Kind == SK_Lambda; } + /// Is this scope known to be for a generic lambda? (This will be false until + /// we parse the first 'auto'-typed parameter. + bool isGenericLambda() const { + return !AutoTemplateParams.empty() || GLTemplateParameterList; + } + /// /// \brief Add a variable that might potentially be captured by the /// lambda and therefore the enclosing lambdas. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 6995740635..66328adad6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -64,7 +64,7 @@ namespace llvm { template <typename ValueT> struct DenseMapInfo; template <typename ValueT, typename ValueInfoT> class DenseSet; class SmallBitVector; - class InlineAsmIdentifierInfo; + struct InlineAsmIdentifierInfo; } namespace clang { @@ -208,6 +208,7 @@ namespace sema { class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; + class SemaPPCallbacks; class TemplateDeductionInfo; } @@ -228,6 +229,10 @@ struct FileNullability { /// not have a corresponding nullability annotation. SourceLocation PointerLoc; + /// The end location for the first pointer declarator in the file. Used for + /// placing fix-its. + SourceLocation PointerEndLoc; + /// Which kind of pointer declarator we saw. uint8_t PointerKind; @@ -280,15 +285,21 @@ class Sema { bool isVisibleSlow(const NamedDecl *D); + /// Determine whether two declarations should be linked together, given that + /// the old declaration might not be visible and the new declaration might + /// not have external linkage. bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { - // We are about to link these. It is now safe to compute the linkage of - // the new decl. If the new decl has external linkage, we will - // link it with the hidden decl (which also has external linkage) and - // it will keep having external linkage. If it has internal linkage, we - // will not link it. Since it has no previous decls, it will remain - // with internal linkage. - return isVisible(Old) || New->isExternallyVisible(); + if (isVisible(Old)) + return true; + // See comment in below overload for why it's safe to compute the linkage + // of the new declaration here. + if (New->isExternallyDeclarable()) { + assert(Old->isExternallyDeclarable() && + "should not have found a non-externally-declarable previous decl"); + return true; + } + return false; } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); @@ -336,6 +347,35 @@ public: /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + /// \brief pragma clang section kind + enum PragmaClangSectionKind { + PCSK_Invalid = 0, + PCSK_BSS = 1, + PCSK_Data = 2, + PCSK_Rodata = 3, + PCSK_Text = 4 + }; + + enum PragmaClangSectionAction { + PCSA_Set = 0, + PCSA_Clear = 1 + }; + + struct PragmaClangSection { + std::string SectionName; + bool Valid = false; + SourceLocation PragmaLocation; + + void Act(SourceLocation PragmaLocation, + PragmaClangSectionAction Action, + StringLiteral* Name); + }; + + PragmaClangSection PragmaClangBSSSection; + PragmaClangSection PragmaClangDataSection; + PragmaClangSection PragmaClangRodataSection; + PragmaClangSection PragmaClangTextSection; + enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) @@ -352,11 +392,12 @@ public: llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; - Slot(llvm::StringRef StackSlotLabel, - ValueType Value, - SourceLocation PragmaLocation) - : StackSlotLabel(StackSlotLabel), Value(Value), - PragmaLocation(PragmaLocation) {} + SourceLocation PragmaPushLocation; + Slot(llvm::StringRef StackSlotLabel, ValueType Value, + SourceLocation PragmaLocation, SourceLocation PragmaPushLocation) + : StackSlotLabel(StackSlotLabel), Value(Value), + PragmaLocation(PragmaLocation), + PragmaPushLocation(PragmaPushLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, @@ -387,6 +428,8 @@ public: explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} + bool hasValue() const { return CurrentValue != DefaultValue; } + SmallVector<Slot, 2> Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; @@ -408,6 +451,13 @@ public: // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack<unsigned> PackStack; + // The current #pragma pack values and locations at each #include. + struct PackIncludeState { + unsigned CurrentValue; + SourceLocation CurrentPragmaLocation; + bool HasNonDefaultValue, ShouldWarnOnInclude; + }; + SmallVector<PackIncludeState, 8> PackIncludeStack; // Segment #pragmas. PragmaStack<StringLiteral *> DataSegStack; PragmaStack<StringLiteral *> BSSSegStack; @@ -437,6 +487,20 @@ public: /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" + /// \brief This represents the stack of attributes that were pushed by + /// \#pragma clang attribute. + struct PragmaAttributeEntry { + SourceLocation Loc; + AttributeList *Attribute; + SmallVector<attr::SubjectMatchRule, 4> MatchRules; + bool IsUsed; + }; + SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack; + + /// \brief The declaration that is currently receiving an attribute from the + /// #pragma attribute stack. + const Decl *PragmaAttributeCurrentTargetDecl; + /// \brief This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. @@ -675,16 +739,37 @@ public: class SynthesizedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; + bool PushedCodeSynthesisContext = false; public: SynthesizedFunctionScope(Sema &S, DeclContext *DC) - : S(S), SavedContext(S, DC) - { + : S(S), SavedContext(S, DC) { S.PushFunctionScope(); - S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + S.PushExpressionEvaluationContext( + Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + if (auto *FD = dyn_cast<FunctionDecl>(DC)) + FD->setWillHaveBody(true); + else + assert(isa<ObjCMethodDecl>(DC)); + } + + void addContextNote(SourceLocation UseLoc) { + assert(!PushedCodeSynthesisContext); + + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction; + Ctx.PointOfInstantiation = UseLoc; + Ctx.Entity = cast<Decl>(S.CurContext); + S.pushCodeSynthesisContext(Ctx); + + PushedCodeSynthesisContext = true; } ~SynthesizedFunctionScope() { + if (PushedCodeSynthesisContext) + S.popCodeSynthesisContext(); + if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext)) + FD->setWillHaveBody(false); S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } @@ -802,7 +887,7 @@ public: /// \brief Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. - enum ExpressionEvaluationContext { + enum class ExpressionEvaluationContext { /// \brief The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but @@ -908,8 +993,12 @@ public: MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); bool isUnevaluated() const { - return Context == Unevaluated || Context == UnevaluatedAbstract || - Context == UnevaluatedList; + return Context == ExpressionEvaluationContext::Unevaluated || + Context == ExpressionEvaluationContext::UnevaluatedAbstract || + Context == ExpressionEvaluationContext::UnevaluatedList; + } + bool isConstantEvaluated() const { + return Context == ExpressionEvaluationContext::ConstantEvaluated; } }; @@ -1007,6 +1096,11 @@ public: /// definition in this translation unit. llvm::MapVector<NamedDecl *, SourceLocation> UndefinedButUsed; + /// Determine if VD, which must be a variable or function, is an external + /// symbol that nonetheless can't be referenced from outside this translation + /// unit because its type has no linkage and it's not extern "C". + bool isExternalWithNoLinkageType(ValueDecl *VD); + /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined); @@ -1042,12 +1136,23 @@ public: CXXInvalid }; - typedef std::pair<CXXRecordDecl*, CXXSpecialMember> SpecialMemberDecl; + typedef llvm::PointerIntPair<CXXRecordDecl *, 3, CXXSpecialMember> + SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. - llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + llvm::SmallPtrSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + + /// The function definitions which were renamed as part of typo-correction + /// to match their respective declarations. We want to keep track of them + /// to ensure that we don't emit a "redefinition" error if we encounter a + /// correctly named definition after the renamed definition. + llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions; + + /// Stack of types that correspond to the parameter entities that are + /// currently being copy-initialized. Can be empty. + llvm::SmallVector<QualType, 4> CurrentParameterCopyTypes; void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); @@ -1065,14 +1170,12 @@ public: /// statements. class FPContractStateRAII { public: - FPContractStateRAII(Sema& S) - : S(S), OldFPContractState(S.FPFeatures.fp_contract) {} - ~FPContractStateRAII() { - S.FPFeatures.fp_contract = OldFPContractState; - } + FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {} + ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; } + private: Sema& S; - bool OldFPContractState : 1; + FPOptions OldFPFeaturesState; }; void addImplicitTypedef(StringRef Name, QualType T); @@ -1190,6 +1293,7 @@ public: void emitAndClearUnusedLocalTypedefWarnings(); + void ActOnStartOfTranslationUnit(); void ActOnEndOfTranslationUnit(); void CheckDelegatingCtorCycles(); @@ -1280,6 +1384,8 @@ public: SourceRange Brackets, DeclarationName Entity); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); + QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); @@ -1427,23 +1533,27 @@ private: TypeDiagnoser *Diagnoser); struct ModuleScope { - clang::Module *Module; + clang::Module *Module = nullptr; + bool ModuleInterface = false; VisibleModuleSet OuterVisibleModules; }; /// The modules we're currently parsing. llvm::SmallVector<ModuleScope, 16> ModuleScopes; - VisibleModuleSet VisibleModules; + /// Get the module whose scope we are currently within. + Module *getCurrentModule() const { + return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; + } - Module *CachedFakeTopLevelModule; + VisibleModuleSet VisibleModules; public: /// \brief Get the module owning an entity. - Module *getOwningModule(Decl *Entity); + Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); } /// \brief Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. - void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc); + void makeMergedDefinitionVisible(NamedDecl *ND); bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); } @@ -1462,6 +1572,11 @@ public: llvm::SmallVectorImpl<Module *> *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); + bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); + + /// Determine if \p D and \p Suggested have a structurally compatible + /// layout as described in C11 6.2.7/1. + bool hasStructuralCompatLayout(Decl *D, Decl *Suggested); /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. @@ -1477,6 +1592,12 @@ public: hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if there is a visible declaration of \p D that is an explicit + /// specialization declaration for a specialization of a template. (For a + /// member specialization, use hasVisibleMemberSpecialization.) + bool hasVisibleExplicitSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( @@ -1544,9 +1665,13 @@ public: // struct SkipBodyInfo { - SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} + SkipBodyInfo() + : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr), + New(nullptr) {} bool ShouldSkip; + bool CheckSameAsPrevious; NamedDecl *Previous; + NamedDecl *New; }; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); @@ -1570,7 +1695,7 @@ public: Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, - bool AllowClassTemplates = false); + bool IsTemplateName = false); /// Attempt to behave like MSVC in situations where lookup of an unqualified /// type name has failed in a dependent context. In these situations, we @@ -1599,7 +1724,6 @@ public: ExprResult Expr; TemplateName Template; ParsedType Type; - const IdentifierInfo *Keyword; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} @@ -1608,8 +1732,7 @@ public: NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} - NameClassification(const IdentifierInfo *Keyword) - : Kind(NC_Keyword), Keyword(Keyword) { } + NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {} static NameClassification Error() { return NameClassification(NC_Error); @@ -1715,6 +1838,23 @@ public: TemplateNameKindForDiagnostics getTemplateNameKindForDiagnostics(TemplateName Name); + /// Determine whether it's plausible that E was intended to be a + /// template-name. + bool mightBeIntendedToBeTemplateName(ExprResult E) { + if (!getLangOpts().CPlusPlus || E.isInvalid()) + return false; + if (auto *DRE = dyn_cast<DeclRefExpr>(E.get())) + return !DRE->hasExplicitTemplateArgs(); + if (auto *ME = dyn_cast<MemberExpr>(E.get())) + return !ME->hasExplicitTemplateArgs(); + // Any additional cases recognized here should also be handled by + // diagnoseExprIntendedAsTemplateName. + return false; + } + void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, + SourceLocation Less, + SourceLocation Greater); + Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, @@ -1735,8 +1875,11 @@ public: static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); + NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, + const LookupResult &R); NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); - void CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R); + void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, + const LookupResult &R); void CheckShadow(Scope *S, VarDecl *D); /// Warn if 'E', which is an expression that is about to be modified, refers @@ -1822,7 +1965,6 @@ public: void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); void ActOnUninitializedDecl(Decl *dcl); void ActOnInitializerError(Decl *Dcl); - bool canInitializeWithParenthesizedList(QualType TargetType); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); @@ -1908,14 +2050,15 @@ public: SourceLocation SemiLoc); enum class ModuleDeclKind { - Module, ///< 'module X;' + Interface, ///< 'export module X;' + Implementation, ///< 'module X;' Partition, ///< 'module partition X;' - Implementation, ///< 'module implementation X;' }; /// The parser has processed a module-declaration that begins the definition /// of a module interface or implementation. - DeclGroupPtrTy ActOnModuleDecl(SourceLocation ModuleLoc, ModuleDeclKind MDK, + DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, + SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path); /// \brief The parser has processed a module import declaration. @@ -2040,15 +2183,14 @@ public: }; Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, - SourceLocation ModulePrivateLoc, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent, - SourceLocation ScopedEnumKWLoc, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation NameLoc, AttributeList *Attr, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, + MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, + bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, - bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr); + bool IsTypeSpecifier, bool IsTemplateParamOrArg, + SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, @@ -2113,6 +2255,12 @@ public: /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); + /// Perform ODR-like check for C/ObjC when merging tag types from modules. + /// Differently from C++, actually parse the body and reject / error out + /// in case of a structural mismatch. + bool ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev, + SkipBodyInfo &SkipBody); + typedef void *SkippedDefinitionContext; /// \brief Invoked when we enter a tag definition that we're skipping. @@ -2166,8 +2314,8 @@ public: Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, - AttributeList *Attrs, - SourceLocation EqualLoc, Expr *Val); + AttributeList *Attrs, SourceLocation EqualLoc, + Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef<Decl *> Elements, @@ -2310,6 +2458,7 @@ public: void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); + void notePreviousDefinition(const NamedDecl *Old, SourceLocation New); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions @@ -2556,7 +2705,8 @@ public: OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, - bool PartialOverloading = false); + bool PartialOverloading = false, + bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, @@ -2604,13 +2754,15 @@ public: CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -2621,8 +2773,7 @@ public: SourceLocation OpLoc, ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, SourceRange OpRange = SourceRange()); - void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, - ArrayRef<Expr *> Args, + void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); @@ -2651,6 +2802,14 @@ public: EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, bool MissingImplicitThis = false); + /// Find the failed Boolean condition within a given Boolean + /// constant expression, and describe it with a string. + /// + /// \param AllowTopLevelCond Whether to allow the result to be the + /// complete top-level condition. + std::pair<Expr *, std::string> + findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond); + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// non-ArgDependent DiagnoseIfAttrs. /// @@ -2670,7 +2829,7 @@ public: /// of a function. /// /// Returns true if any errors were emitted. - bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function, + bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, SourceLocation Loc); /// Returns whether the given function's address can be taken or not, @@ -2700,7 +2859,8 @@ public: resolveAddressOfOnlyViableOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); - bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr); + bool resolveAndFixAddressOfOnlyViableOverloadCandidate( + ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, @@ -2760,12 +2920,13 @@ public: ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *input); + Expr *input, bool RequiresADL = true); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS); + Expr *LHS, Expr *RHS, + bool RequiresADL = true); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, @@ -2880,14 +3041,31 @@ public: /// purpose of redeclaring the name. NotForRedeclaration = 0, /// \brief The lookup results will be used for redeclaration of a name, - /// if an entity by that name already exists. - ForRedeclaration + /// if an entity by that name already exists and is visible. + ForVisibleRedeclaration, + /// \brief The lookup results will be used for redeclaration of a name + /// with external linkage; non-visible lookup results with external linkage + /// may also be found. + ForExternalRedeclaration }; + RedeclarationKind forRedeclarationInCurContext() { + // A declaration with an owning module for linkage can never link against + // anything that is not visible. We don't need to check linkage here; if + // the context has internal linkage, redeclaration lookup won't find things + // from other TUs, and we can't safely compute linkage yet in general. + if (cast<Decl>(CurContext) + ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) + return ForVisibleRedeclaration; + return ForExternalRedeclaration; + } + /// \brief The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. LOLR_Error, + /// \brief The lookup found no match but no diagnostic was issued. + LOLR_ErrorNoDiagnostic, /// \brief The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, @@ -2991,9 +3169,6 @@ public: void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); - void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions, - DeclAccessPair Operator, - QualType T1, QualType T2); LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, SourceLocation GnuLabelLoc = SourceLocation()); @@ -3015,7 +3190,8 @@ public: ArrayRef<QualType> ArgTys, bool AllowRaw, bool AllowTemplate, - bool AllowStringTemplate); + bool AllowStringTemplate, + bool DiagnoseMissing); bool isKnownName(StringRef name); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, @@ -3026,7 +3202,8 @@ public: bool IncludeGlobalScope = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope = true); + bool IncludeGlobalScope = true, + bool IncludeDependentBases = false); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. @@ -3100,6 +3277,8 @@ public: const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); + void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef<Expr *> Args, AssociatedNamespaceSet &AssociatedNamespaces, @@ -3108,6 +3287,8 @@ public: void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); + bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); + void DiagnoseAmbiguousLookup(LookupResult &Result); //@} @@ -3126,7 +3307,7 @@ public: void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); - // Helper for delayed proccessing of attributes. + // Helper for delayed processing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, bool IncludeCXX11Attributes = true); @@ -3145,11 +3326,12 @@ public: bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckNoReturnAttr(const AttributeList &attr); + bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); - void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); + bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceAttr::Spelling SemanticSpelling); @@ -3238,9 +3420,10 @@ public: /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. - void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl); - void DefaultSynthesizeProperties(Scope *S, Decl *D); + void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, + ObjCInterfaceDecl *IDecl, + SourceLocation AtEnd); + void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor @@ -3266,7 +3449,9 @@ public: SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, + SourceLocation GetterNameLoc, Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, @@ -3282,7 +3467,9 @@ public: SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, + SourceLocation GetterNameLoc, Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, @@ -3627,15 +3814,15 @@ public: Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc); + void FillInlineAsmIdentifierInfo(Expr *Res, + llvm::InlineAsmIdentifierInfo &Info); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, - llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, - llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef<Token> AsmToks, @@ -3736,6 +3923,9 @@ public: void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); + /// Warn when implicitly casting 0 to nullptr. + void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } @@ -3751,11 +3941,10 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, - StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess); + void DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks = false); bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); @@ -3768,8 +3957,9 @@ public: bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass=nullptr, - bool ObjCPropertyAccess=false); + const ObjCInterfaceDecl *UnknownObjCClass = nullptr, + bool ObjCPropertyAccess = false, + bool AvoidPartialAvailabilityChecks = false); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); @@ -3811,7 +4001,7 @@ public: void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); - void MarkDeclRefReferenced(DeclRefExpr *E); + void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); void UpdateMarkingForLValueToRValue(Expr *E); @@ -4983,7 +5173,7 @@ public: ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc); - /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support + /// ActOnArrayTypeTrait - Parsed one of the binary type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, @@ -5136,7 +5326,8 @@ public: CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, - bool *IsCorrectedToColon = nullptr); + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); /// \brief The parser has parsed a nested-name-specifier 'identifier::'. /// @@ -5160,13 +5351,16 @@ public: /// are allowed. The bool value pointed by this parameter is set to 'true' /// if the identifier is treated as if it was followed by ':', not '::'. /// + /// \param OnlyNamespace If true, only considers namespaces in lookup. + /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, - bool *IsCorrectedToColon = nullptr); + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); ExprResult ActOnDecltypeExpression(Expr *E); @@ -5904,7 +6098,7 @@ public: SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ArrayRef<Decl *> Params, + ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, Expr *RequiresClause); @@ -6047,6 +6241,7 @@ public: TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); + void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); DeclResult ActOnExplicitInstantiation(Scope *S, @@ -6903,6 +7098,10 @@ public: /// We are declaring an implicit special member function. DeclaringSpecialMember, + + /// We are defining a synthesized function (such as a defaulted special + /// member). + DefiningSynthesizedFunction, } Kind; /// \brief Was the enclosing context a non-instantiation SFINAE context? @@ -7196,9 +7395,13 @@ public: PrintInstantiationStack(); LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size(); } + if (PragmaAttributeCurrentTargetDecl) + PrintPragmaAttributeInstantiationPoint(); } void PrintInstantiationStack(); + void PrintPragmaAttributeInstantiationPoint(); + /// \brief Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. @@ -7308,9 +7511,9 @@ public: /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingInstantiations; - class SavePendingInstantiationsAndVTableUsesRAII { + class GlobalEagerInstantiationScope { public: - SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled) + GlobalEagerInstantiationScope(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; @@ -7318,7 +7521,14 @@ public: SavedVTableUses.swap(S.VTableUses); } - ~SavePendingInstantiationsAndVTableUsesRAII() { + void perform() { + if (Enabled) { + S.DefineUsedVTables(); + S.PerformPendingInstantiations(); + } + } + + ~GlobalEagerInstantiationScope() { if (!Enabled) return; // Restore the set of pending vtables. @@ -7348,14 +7558,16 @@ public: /// types, static variables, enumerators, etc. std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; - class SavePendingLocalImplicitInstantiationsRAII { + class LocalEagerInstantiationScope { public: - SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) { + LocalEagerInstantiationScope(Sema &S) : S(S) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } - ~SavePendingLocalImplicitInstantiationsRAII() { + void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); } + + ~LocalEagerInstantiationScope() { assert(S.PendingLocalImplicitInstantiations.empty() && "there shouldn't be any pending local implicit instantiations"); SavedPendingLocalImplicitInstantiations.swap( @@ -7365,7 +7577,7 @@ public: private: Sema &S; std::deque<PendingImplicitInstantiation> - SavedPendingLocalImplicitInstantiations; + SavedPendingLocalImplicitInstantiations; }; /// A helper class for building up ExtParameterInfos. @@ -7418,6 +7630,10 @@ public: unsigned ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); + bool SubstExceptionSpec(SourceLocation Loc, + FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &ExceptionStorage, + const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -7497,6 +7713,15 @@ public: LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); + void + InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *OuterMostScope = nullptr); + + bool usesPartialOrExplicitSpecialization( + SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec); + bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -7571,7 +7796,8 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, - const MultiLevelTemplateArgumentList &TemplateArgs); + const MultiLevelTemplateArgumentList &TemplateArgs, + bool FindingInstantiatedContext = false); DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -7658,7 +7884,8 @@ public: Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc); + SourceLocation EndProtoLoc, + AttributeList *AttrList); Decl *ActOnStartClassImplementation( SourceLocation AtClassImplLoc, @@ -8002,6 +8229,11 @@ public: POAK_Reset // #pragma options align=reset }; + /// ActOnPragmaClangSection - Called on well formed \#pragma clang section + void ActOnPragmaClangSection(SourceLocation PragmaLoc, + PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName); + /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); @@ -8010,6 +8242,15 @@ public: void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); + enum class PragmaPackDiagnoseKind { + NonDefaultStateAtInclude, + ChangedStateAtExit + }; + + void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind, + SourceLocation IncludeLoc); + void DiagnoseUnterminatedPragmaPack(); + /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); @@ -8100,8 +8341,9 @@ public: SourceLocation AliasNameLoc); /// ActOnPragmaFPContract - Called on well formed - /// \#pragma {STDC,OPENCL} FP_CONTRACT - void ActOnPragmaFPContract(tok::OnOffSwitch OOS); + /// \#pragma {STDC,OPENCL} FP_CONTRACT and + /// \#pragma clang fp contract + void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. @@ -8134,6 +8376,20 @@ public: /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); + /// \brief Called on well-formed '\#pragma clang attribute push'. + void ActOnPragmaAttributePush(AttributeList &Attribute, + SourceLocation PragmaLoc, + attr::ParsedSubjectMatchRuleSet Rules); + + /// \brief Called on well-formed '\#pragma clang attribute pop'. + void ActOnPragmaAttributePop(SourceLocation PragmaLoc); + + /// \brief Adds the attributes that have been specified using the + /// '\#pragma clang attribute push' directives to the given declaration. + void AddPragmaAttributes(Scope *S, Decl *D); + + void DiagnoseUnterminatedPragmaAttribute(); + /// \brief Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); @@ -8164,6 +8420,11 @@ public: void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE, unsigned SpellingListIndex); + /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular + /// declaration. + void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, + unsigned SpellingListIndex); + /// AddAlignValueAttr - Adds an align_value attribute to a particular /// declaration. void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -8185,9 +8446,13 @@ public: unsigned SpellingListIndex, bool isNSConsumed, bool isTemplateInstantiation); + bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); + //===--------------------------------------------------------------------===// // C++ Coroutines TS // + bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc, + StringRef Keyword); ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); @@ -8253,7 +8518,7 @@ public: /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. - bool checkOpenCLDisabledDecl(const Decl &D, const Expr &E); + bool checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E); //===--------------------------------------------------------------------===// // OpenMP directives and clauses. @@ -8271,6 +8536,12 @@ private: /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; + /// Push new OpenMP function region for non-capturing function. + void pushOpenMPFunctionRegion(); + + /// Pop OpenMP function region for non-capturing function. + void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); + /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. @@ -8305,6 +8576,11 @@ public: /// is performed. bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level); + /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) + /// for \p FD based on DSA for the provided corresponding captured declaration + /// \p D. + void setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level); + /// \brief Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. @@ -8357,9 +8633,11 @@ public: /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// \brief Initialize declare reduction construct initializer. - void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); + /// \return omp_priv variable. + VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. - void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer); + void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, + VarDecl *OmpPrivParm); /// \brief Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); @@ -8477,7 +8755,8 @@ public: StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskgroup'. - StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, + StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, @@ -8819,6 +9098,20 @@ public: CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions = llvm::None); + /// Called on well-formed 'task_reduction' clause. + OMPClause *ActOnOpenMPTaskReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = llvm::None); + /// Called on well-formed 'in_reduction' clause. + OMPClause *ActOnOpenMPInReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = llvm::None); /// \brief Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, @@ -9185,6 +9478,8 @@ public: /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); + QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS); QualType CheckPointerToMemberOperands( // C++ 5.5 ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation OpLoc, bool isIndirect); @@ -9334,14 +9629,14 @@ public: enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// \brief Checks for invalid conversions and casts between - /// retainable pointers and other pointer kinds. - ARCConversionResult CheckObjCARCConversion(SourceRange castRange, - QualType castType, Expr *&op, - CheckedConversionKind CCK, - bool Diagnose = true, - bool DiagnoseCFAudited = false, - BinaryOperatorKind Opc = BO_PtrMemD - ); + /// retainable pointers and other pointer kinds for ARC and Weak. + ARCConversionResult CheckObjCConversion(SourceRange castRange, + QualType castType, Expr *&op, + CheckedConversionKind CCK, + bool Diagnose = true, + bool DiagnoseCFAudited = false, + BinaryOperatorKind Opc = BO_PtrMemD + ); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); @@ -9914,8 +10209,7 @@ public: void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); - void CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, + void CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, @@ -9934,6 +10228,7 @@ public: MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteNaturalLanguage(); + void CodeCompleteAvailabilityPlatformName(); void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl<CodeCompletionResult> &Results); @@ -9997,12 +10292,11 @@ private: bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStartImpl(CallExpr *TheCall); - bool SemaBuiltinVAStart(CallExpr *TheCall); - bool SemaBuiltinMSVAStart(CallExpr *TheCall); - bool SemaBuiltinVAStartARM(CallExpr *Call); + bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); + bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + bool SemaBuiltinVSX(CallExpr *TheCall); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); public: @@ -10171,6 +10465,12 @@ private: IdentifierInfo *Ident_NSError = nullptr; + /// \brief The handler for the FileChanged preprocessor events. + /// + /// Used for diagnostics that implement custom semantic analysis for #include + /// directives, like -Wpragma-pack. + sema::SemaPPCallbacks *SemaPPCallbackHandler; + protected: friend class Parser; friend class InitializationSequence; @@ -10211,17 +10511,6 @@ public: return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } - /// \brief The diagnostic we should emit for \c D, or \c AR_Available. - /// - /// \param D The declaration to check. Note that this may be altered to point - /// to another declaration that \c D gets it's availability from. i.e., we - /// walk the list of typedefs to find an availability attribute. - /// - /// \param Message If non-null, this will be populated with the message from - /// the availability attribute that is selected. - AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, - std::string *Message); - const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. @@ -10245,6 +10534,36 @@ public: SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses; private: + class SavePendingParsedClassStateRAII { + public: + SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); } + + ~SavePendingParsedClassStateRAII() { + assert(S.DelayedExceptionSpecChecks.empty() && + "there shouldn't be any pending delayed exception spec checks"); + assert(S.DelayedDefaultedMemberExceptionSpecs.empty() && + "there shouldn't be any pending delayed defaulted member " + "exception specs"); + assert(S.DelayedDllExportClasses.empty() && + "there shouldn't be any pending delayed DLL export classes"); + swapSavedState(); + } + + private: + Sema &S; + decltype(DelayedExceptionSpecChecks) SavedExceptionSpecChecks; + decltype(DelayedDefaultedMemberExceptionSpecs) + SavedDefaultedMemberExceptionSpecs; + decltype(DelayedDllExportClasses) SavedDllExportClasses; + + void swapSavedState() { + SavedExceptionSpecChecks.swap(S.DelayedExceptionSpecChecks); + SavedDefaultedMemberExceptionSpecs.swap( + S.DelayedDefaultedMemberExceptionSpecs); + SavedDllExportClasses.swap(S.DelayedDllExportClasses); + } + }; + /// \brief Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { @@ -10298,6 +10617,7 @@ class EnterExpressionEvaluationContext { bool Entered = true; public: + EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, @@ -10328,8 +10648,8 @@ public: // a context. if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { - Actions.PushExpressionEvaluationContext(Sema::UnevaluatedList, nullptr, - false); + Actions.PushExpressionEvaluationContext( + Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false); Entered = true; } } diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h index a01e8d639f..4dc215ba21 100644 --- a/include/clang/Sema/SemaInternal.h +++ b/include/clang/Sema/SemaInternal.h @@ -73,7 +73,8 @@ inline void MarkVarDeclODRUsed(VarDecl *Var, // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && - (!Var->isExternallyVisible() || Var->isInline()) && + (!Var->isExternallyVisible() || Var->isInline() || + SemaRef.isExternalWithNoLinkageType(Var)) && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h index d92cbab4fb..cd9ed6abfa 100644 --- a/include/clang/Sema/TemplateDeduction.h +++ b/include/clang/Sema/TemplateDeduction.h @@ -88,6 +88,12 @@ public: HasSFINAEDiagnostic = false; } + /// Peek at the SFINAE diagnostic. + const PartialDiagnosticAt &peekSFINAEDiagnostic() const { + assert(HasSFINAEDiagnostic); + return SuppressedDiagnostics.front(); + } + /// \brief Provide a new template argument list that contains the /// results of template argument deduction. void reset(TemplateArgumentList *NewDeduced) { diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index de8e2a8183..42c62257ad 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -604,6 +604,12 @@ namespace clang { OPENCL_EXTENSION_DECLS = 59, MODULAR_CODEGEN_DECLS = 60, + + /// \brief Record code for \#pragma pack options. + PACK_PRAGMA_OPTIONS = 61, + + /// \brief The stack of open #ifs/#ifdefs recorded in a preamble. + PP_CONDITIONAL_STACK = 62, }; /// \brief Record types used within a source manager block. @@ -710,6 +716,9 @@ namespace clang { /// \brief Specifies some declarations with initializers that must be /// emitted to initialize the module. SUBMODULE_INITIALIZERS = 16, + /// \brief Specifies the name of the module that will eventually + /// re-export the entities in this module. + SUBMODULE_EXPORT_AS = 17, }; /// \brief Record types used within a comments block. @@ -820,6 +829,8 @@ namespace clang { PREDEF_TYPE_OMP_ARRAY_SECTION = 42, /// \brief The '__float128' type PREDEF_TYPE_FLOAT128_ID = 43, + /// \brief The '_Float16' type + PREDEF_TYPE_FLOAT16_ID = 44, /// \brief OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, @@ -927,7 +938,11 @@ namespace clang { /// \brief An ObjCTypeParamType record. TYPE_OBJC_TYPE_PARAM = 44, /// \brief A DeducedTemplateSpecializationType record. - TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45 + TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45, + /// \brief A DependentSizedExtVectorType record. + TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46, + /// \brief A DependentAddressSpaceType record. + TYPE_DEPENDENT_ADDRESS_SPACE = 47 }; /// \brief The type IDs for special types constructed by semantic @@ -1537,9 +1552,14 @@ namespace clang { // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr - + STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt - EXPR_LAMBDA // LambdaExpr + EXPR_LAMBDA, // LambdaExpr + STMT_COROUTINE_BODY, + STMT_CORETURN, + EXPR_COAWAIT, + EXPR_COYIELD, + EXPR_DEPENDENT_COAWAIT, }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 5a1514ad80..9c5ad00691 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -400,7 +400,7 @@ private: Preprocessor &PP; /// \brief The AST context into which we'll read the AST files. - ASTContext &Context; + ASTContext *ContextObj = nullptr; /// \brief The AST consumer. ASTConsumer *Consumer = nullptr; @@ -408,6 +408,9 @@ private: /// \brief The module manager which manages modules and their dependencies ModuleManager ModuleMgr; + /// The cache that manages memory buffers for PCM files. + MemoryBufferCache &PCMCache; + /// \brief A dummy identifier resolver used to merge TU-scope declarations in /// C, for the cases where we don't have a Sema object to provide a real /// identifier resolver. @@ -475,10 +478,18 @@ private: /// in the chain. DeclUpdateOffsetsMap DeclUpdateOffsets; + struct PendingUpdateRecord { + Decl *D; + serialization::GlobalDeclID ID; + // Whether the declaration was just deserialized. + bool JustLoaded; + PendingUpdateRecord(serialization::GlobalDeclID ID, Decl *D, + bool JustLoaded) + : D(D), ID(ID), JustLoaded(JustLoaded) {} + }; /// \brief Declaration updates for already-loaded declarations that we need /// to apply once we finish processing an import. - llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16> - PendingUpdateRecords; + llvm::SmallVector<PendingUpdateRecord, 16> PendingUpdateRecords; enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded }; @@ -700,7 +711,7 @@ private: /// \brief Mapping from global preprocessing entity IDs to the module in /// which the preprocessed entity resides along with the offset that should be - /// added to the global preprocessing entitiy ID to produce a local ID. + /// added to the global preprocessing entity ID to produce a local ID. GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap; /// \name CodeGen-relevant special data @@ -808,6 +819,18 @@ private: int PragmaMSPointersToMembersState = -1; SourceLocation PointersToMembersPragmaLocation; + /// \brief The pragma pack state. + Optional<unsigned> PragmaPackCurrentValue; + SourceLocation PragmaPackCurrentLocation; + struct PragmaPackStackEntry { + unsigned Value; + SourceLocation Location; + SourceLocation PushLocation; + StringRef SlotLabel; + }; + llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack; + llvm::SmallVector<std::string, 2> PragmaPackStrings; + /// \brief The OpenCL extension settings. OpenCLOptions OpenCLExtensions; @@ -845,9 +868,6 @@ private: SmallVector<ImportedSubmodule, 2> ImportedModules; //@} - /// \brief The directory that the PCH we are reading is stored in. - std::string CurrentDir; - /// \brief The system include root to be used when loading the /// precompiled header. std::string isysroot; @@ -970,14 +990,26 @@ private: /// \brief The generation number of each identifier, which keeps track of /// the last time we loaded information about this identifier. llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration; - - /// \brief Contains declarations and definitions that will be + + class InterestingDecl { + Decl *D; + bool DeclHasPendingBody; + + public: + InterestingDecl(Decl *D, bool HasBody) + : D(D), DeclHasPendingBody(HasBody) {} + Decl *getDecl() { return D; } + /// Whether the declaration has a pending body. + bool hasPendingBody() { return DeclHasPendingBody; } + }; + + /// \brief Contains declarations and definitions that could be /// "interesting" to the ASTConsumer, when we get that AST consumer. /// /// "Interesting" declarations are those that have data that may /// need to be emitted, such as inline function definitions or /// Objective-C protocols. - std::deque<Decl *> InterestingDecls; + std::deque<InterestingDecl> PotentiallyInterestingDecls; /// \brief The list of redeclaration chains that still need to be /// reconstructed, and the local offset to the corresponding list @@ -1011,8 +1043,11 @@ private: /// once recursing loading has been completed. llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks; + using DataPointers = + std::pair<CXXRecordDecl *, struct CXXRecordDecl::DefinitionData *>; + /// \brief Record definitions in which we found an ODR violation. - llvm::SmallDenseMap<CXXRecordDecl *, llvm::TinyPtrVector<CXXRecordDecl *>, 2> + llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, 2>, 2> PendingOdrMergeFailures; /// \brief DeclContexts in which we have diagnosed an ODR violation. @@ -1101,6 +1136,8 @@ private: /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; + llvm::DenseMap<const Decl *, bool> DefinitionSource; + /// \brief Reads a statement from the specified cursor. Stmt *ReadStmtFromStream(ModuleFile &F); @@ -1110,6 +1147,7 @@ private: time_t StoredTime; bool Overridden; bool Transient; + bool TopLevelModuleMap; }; /// \brief Reads the stored information about an input file. @@ -1251,7 +1289,7 @@ private: RecordLocation DeclCursorForID(serialization::DeclID ID, SourceLocation &Location); - void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); + void loadDeclUpdateRecords(PendingUpdateRecord &Record); void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration = 0); @@ -1350,7 +1388,7 @@ public: /// precompiled header will be loaded. /// /// \param Context the AST context that this precompiled header will be - /// loaded into. + /// loaded into, if any. /// /// \param PCHContainerRdr the PCHContainerOperations to use for loading and /// creating modules. @@ -1382,7 +1420,7 @@ public: /// /// \param ReadTimer If non-null, a timer used to track the time spent /// deserializing. - ASTReader(Preprocessor &PP, ASTContext &Context, + ASTReader(Preprocessor &PP, ASTContext *Context, const PCHContainerReader &PCHContainerRdr, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, StringRef isysroot = "", bool DisableValidation = false, @@ -1582,7 +1620,7 @@ public: const LangOptions &LangOpts, const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts, - std::string ExistingModuleCachePath); + StringRef ExistingModuleCachePath); /// \brief Returns the suggested contents of the predefines buffer, /// which contains a (typically-empty) subset of the predefines @@ -1983,7 +2021,7 @@ public: /// \brief Return a descriptor for the corresponding module. llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override; - ExtKind hasExternalDefinitions(unsigned ID) override; + ExtKind hasExternalDefinitions(const Decl *D) override; /// \brief Retrieve a selector from the given module with its local ID /// number. @@ -2107,9 +2145,19 @@ public: // \brief Read a string static std::string ReadString(const RecordData &Record, unsigned &Idx); + // \brief Skip a string + static void SkipString(const RecordData &Record, unsigned &Idx) { + Idx += Record[Idx] + 1; + } + // \brief Read a path std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx); + // \brief Skip a path + static void SkipPath(const RecordData &Record, unsigned &Idx) { + SkipString(Record, Idx); + } + /// \brief Read a version tuple. static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx); @@ -2171,7 +2219,10 @@ public: void completeVisibleDeclsMap(const DeclContext *DC) override; /// \brief Retrieve the AST context that this AST reader supplements. - ASTContext &getContext() { return Context; } + ASTContext &getContext() { + assert(ContextObj && "requested AST context when not loading AST"); + return *ContextObj; + } // \brief Contains the IDs for declarations that were requested before we have // access to a Sema object. @@ -2213,6 +2264,12 @@ public: llvm::function_ref<void(const serialization::InputFile &IF, bool isSystem)> Visitor); + /// Visit all the top-level module maps loaded when building the given module + /// file. + void visitTopLevelModuleMaps(serialization::ModuleFile &MF, + llvm::function_ref< + void(const FileEntry *)> Visitor); + bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; } }; diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index f3c644b9e2..392a4652d6 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -54,6 +54,7 @@ class MacroInfo; class OpaqueValueExpr; class OpenCLOptions; class ASTReader; +class MemoryBufferCache; class Module; class ModuleFileExtension; class ModuleFileExtensionWriter; @@ -109,6 +110,9 @@ private: /// The buffer associated with the bitstream. const SmallVectorImpl<char> &Buffer; + /// \brief The PCM manager which manages memory buffers for pcm files. + MemoryBufferCache &PCMCache; + /// \brief The ASTContext we're writing. ASTContext *Context = nullptr; @@ -481,6 +485,7 @@ private: void WriteOptimizePragmaOptions(Sema &SemaRef); void WriteMSStructPragmaOptions(Sema &SemaRef); void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef); + void WritePackPragmaOptions(Sema &SemaRef); void WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer); @@ -512,6 +517,7 @@ public: /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer, + MemoryBufferCache &PCMCache, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, bool IncludeTimestamps = true); ~ASTWriter() override; @@ -621,10 +627,6 @@ public: /// \brief Add a version tuple to the given record void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record); - /// \brief Infer the submodule ID that contains an entity at the given - /// source location. - serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc); - /// \brief Retrieve or create a submodule ID for this module, or return 0 if /// the submodule is neither local (a submodle of the currently-written module) /// nor from an imported module. @@ -696,7 +698,8 @@ private: void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) override; + const FunctionDecl *Delete, + Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; void StaticDataMemberInstantiated(const VarDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index c1d4a9fd2d..4e4bf44f34 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -163,9 +163,9 @@ public: /// \brief The generation of which this module file is a part. unsigned Generation; - /// \brief The memory buffer that stores the data associated with - /// this AST file. - std::unique_ptr<llvm::MemoryBuffer> Buffer; + /// The memory buffer that stores the data associated with + /// this AST file, owned by the PCMCache in the ModuleManager. + llvm::MemoryBuffer *Buffer; /// \brief The size of this file, in bits. uint64_t SizeInBits = 0; diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h index 70c9d9e540..ffc42ce604 100644 --- a/include/clang/Serialization/ModuleManager.h +++ b/include/clang/Serialization/ModuleManager.h @@ -24,8 +24,10 @@ namespace clang { class GlobalModuleIndex; +class MemoryBufferCache; class ModuleMap; class PCHContainerReader; +class HeaderSearch; namespace serialization { @@ -51,9 +53,15 @@ class ModuleManager { /// FileEntry *. FileManager &FileMgr; + /// Cache of PCM files. + IntrusiveRefCntPtr<MemoryBufferCache> PCMCache; + /// \brief Knows how to unwrap module containers. const PCHContainerReader &PCHContainerRdr; + /// \brief Preprocessor's HeaderSearchInfo containing the module map. + const HeaderSearch &HeaderSearchInfo; + /// \brief A lookup of in-memory (virtual file) buffers llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>> InMemoryBuffers; @@ -123,8 +131,9 @@ public: ModuleReverseIterator; typedef std::pair<uint32_t, StringRef> ModuleOffset; - explicit ModuleManager(FileManager &FileMgr, - const PCHContainerReader &PCHContainerRdr); + explicit ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, + const PCHContainerReader &PCHContainerRdr, + const HeaderSearch &HeaderSearchInfo); ~ModuleManager(); /// \brief Forward iterator to traverse all loaded modules. @@ -159,8 +168,11 @@ public: /// \brief Returns the module associated with the given index ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; } - /// \brief Returns the module associated with the given name - ModuleFile *lookup(StringRef Name) const; + /// \brief Returns the module associated with the given file name. + ModuleFile *lookupByFileName(StringRef FileName) const; + + /// \brief Returns the module associated with the given module name. + ModuleFile *lookupByModuleName(StringRef ModName) const; /// \brief Returns the module associated with the given module file. ModuleFile *lookup(const FileEntry *File) const; @@ -290,6 +302,8 @@ public: /// \brief View the graphviz representation of the module graph. void viewGraph(); + + MemoryBufferCache &getPCMCache() const { return *PCMCache; } }; } } // end namespace clang::serialization diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td index ab33c76767..be8b1494c8 100644 --- a/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -38,6 +38,11 @@ def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden; // default. Such checkers belong in the alpha package. def OptIn : Package<"optin">; +// In the Portability package reside checkers for finding code that relies on +// implementation-defined behavior. Such checks are wanted for cross-platform +// development, but unwanted for developers who target only a single platform. +def PortabilityOptIn : Package<"portability">, InPackage<OptIn>; + def Nullability : Package<"nullability">; def Cplusplus : Package<"cplusplus">; @@ -127,6 +132,10 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">, HelpText<"Generate dynamic type information">, DescFile<"DynamicTypePropagation.cpp">; +def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">, + HelpText<"Assume that const string-like globals are non-null">, + DescFile<"NonilStringConstantsChecker.cpp">; + } // end "core" let ParentPackage = CoreAlpha in { @@ -279,9 +288,19 @@ def VirtualCallChecker : Checker<"VirtualCall">, let ParentPackage = CplusplusAlpha in { -def IteratorPastEndChecker : Checker<"IteratorPastEnd">, - HelpText<"Check iterators used past end">, - DescFile<"IteratorPastEndChecker.cpp">; +def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">, + HelpText<"Reports destructions of polymorphic objects with a non-virtual " + "destructor in their base class">, + DescFile<"DeleteWithNonVirtualDtorChecker.cpp">; + +def IteratorRangeChecker : Checker<"IteratorRange">, + HelpText<"Check for iterators used outside their valid ranges">, + DescFile<"IteratorChecker.cpp">; + +def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">, + HelpText<"Method calls on a moved-from object and copying a moved-from " + "object will be reported">, + DescFile<"MisusedMovedObjectChecker.cpp">; } // end: "alpha.cplusplus" @@ -411,7 +430,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">, let ParentPackage = Unix in { -def UnixAPIChecker : Checker<"API">, +def UnixAPIMisuseChecker : Checker<"API">, HelpText<"Check calls to various UNIX/Posix functions">, DescFile<"UnixAPIChecker.cpp">; @@ -730,10 +749,6 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">, HelpText<"View Exploded Graphs using GraphViz">, DescFile<"DebugCheckers.cpp">; -def BugHashDumper : Checker<"DumpBugHash">, - HelpText<"Dump the bug hash for all statements.">, - DescFile<"DebugCheckers.cpp">; - } // end "debug" @@ -749,3 +764,14 @@ def CloneChecker : Checker<"CloneChecker">, } // end "clone" +//===----------------------------------------------------------------------===// +// Portability checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = PortabilityOptIn in { + +def UnixAPIPortabilityChecker : Checker<"UnixAPI">, + HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">, + DescFile<"UnixAPIChecker.cpp">; + +} // end optin.portability diff --git a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h index 25886545e2..e5e857e970 100644 --- a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h +++ b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h @@ -145,9 +145,11 @@ public: /// Indicates that the tracked object is an Objective-C object. ObjC, /// Indicates that the tracked object could be a CF or Objective-C object. - AnyObj + AnyObj, + /// Indicates that the tracked object is a generalized object. + Generalized }; - + private: Kind K; ObjKind O; diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def index 3355f4b694..281a2ac3a6 100644 --- a/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/include/clang/StaticAnalyzer/Core/Analyses.def @@ -22,14 +22,16 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR #endif ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) +ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3ConstraintManager) #ifndef ANALYSIS_DIAGNOSTICS #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 4fb50deb0f..ce50cc582d 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -205,9 +205,18 @@ private: /// Controls which C++ member functions will be considered for inlining. CXXInlineableMemberKind CXXMemberInliningMode; + /// \sa includeImplicitDtorsInCFG + Optional<bool> IncludeImplicitDtorsInCFG; + /// \sa includeTemporaryDtorsInCFG Optional<bool> IncludeTemporaryDtorsInCFG; - + + /// \sa IncludeLifetimeInCFG + Optional<bool> IncludeLifetimeInCFG; + + /// \sa IncludeLoopExitInCFG + Optional<bool> IncludeLoopExitInCFG; + /// \sa mayInlineCXXStandardLibrary Optional<bool> InlineCXXStandardLibrary; @@ -269,6 +278,9 @@ private: /// \sa shouldWidenLoops Optional<bool> WidenLoops; + /// \sa shouldUnrollLoops + Optional<bool> UnrollLoops; + /// \sa shouldDisplayNotesAsEvents Optional<bool> DisplayNotesAsEvents; @@ -395,6 +407,27 @@ public: /// accepts the values "true" and "false". bool includeTemporaryDtorsInCFG(); + /// Returns whether or not implicit destructors for C++ objects should + /// be included in the CFG. + /// + /// This is controlled by the 'cfg-implicit-dtors' config option, which + /// accepts the values "true" and "false". + bool includeImplicitDtorsInCFG(); + + /// Returns whether or not end-of-lifetime information should be included in + /// the CFG. + /// + /// This is controlled by the 'cfg-lifetime' config option, which accepts + /// the values "true" and "false". + bool includeLifetimeInCFG(); + + /// Returns whether or not the end of the loop information should be included + /// in the CFG. + /// + /// This is controlled by the 'cfg-loopexit' config option, which accepts + /// the values "true" and "false". + bool includeLoopExitInCFG(); + /// Returns whether or not C++ standard library functions may be considered /// for inlining. /// @@ -540,6 +573,10 @@ public: /// This is controlled by the 'widen-loops' config option. bool shouldWidenLoops(); + /// Returns true if the analysis should try to unroll loops with known bounds. + /// This is controlled by the 'unroll-loops' config option. + bool shouldUnrollLoops(); + /// Returns true if the bug reporter should transparently treat extra note /// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic /// consumer doesn't support the extra note pieces. diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 0f1eb096c4..cd1355d03b 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -17,7 +17,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h index b72bce5fc9..2043896fd2 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -1,4 +1,4 @@ -//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===// +//===--- BugReporterVisitors.h - Generate PathDiagnostics -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H -#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/FoldingSet.h" diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h index 8df2bc331b..0e80e7bc19 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h @@ -17,6 +17,7 @@ namespace clang { extern const char * const CoreFoundationObjectiveC; extern const char * const LogicError; extern const char * const MemoryCoreFoundationObjectiveC; + extern const char * const MemoryError; extern const char * const UnixAPI; } } diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index dc6e54a332..a07cd88950 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -550,13 +550,15 @@ public: class PathDiagnosticCallPiece : public PathDiagnosticPiece { PathDiagnosticCallPiece(const Decl *callerD, const PathDiagnosticLocation &callReturnPos) - : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), - NoExit(false), callReturn(callReturnPos) {} + : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), + NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false), + callReturn(callReturnPos) {} PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) - : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), - NoExit(true), path(oldPath) {} - + : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), + NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false), + path(oldPath) {} + const Decl *Caller; const Decl *Callee; @@ -564,6 +566,10 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece { // call exit. bool NoExit; + // Flag signifying that the callee function is an Objective-C autosynthesized + // property getter or setter. + bool IsCalleeAnAutosynthesizedPropertyAccessor; + // The custom string, which should appear after the call Return Diagnostic. // TODO: Should we allow multiple diagnostics? std::string CallStackMessage; diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 52ed260346..88cb08a4b6 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -286,7 +286,7 @@ public: void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng); - /// \brief Run checkers on begining of function. + /// \brief Run checkers on beginning of function. void runCheckersForBeginFunction(ExplodedNodeSet &Dst, const BlockEdge &L, ExplodedNode *Pred, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 3e0913ec4e..15b930bc3f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 0d1a120c9d..4aa87443e4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -20,6 +20,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" namespace clang { namespace ento { @@ -29,8 +30,9 @@ class CompoundValData : public llvm::FoldingSetNode { llvm::ImmutableList<SVal> L; public: - CompoundValData(QualType t, llvm::ImmutableList<SVal> l) - : T(t), L(l) {} + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) { + assert(NonLoc::isCompoundType(t)); + } typedef llvm::ImmutableList<SVal>::iterator iterator; iterator begin() const { return L.begin(); } @@ -47,7 +49,9 @@ class LazyCompoundValData : public llvm::FoldingSetNode { const TypedValueRegion *region; public: LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) - : store(st), region(r) {} + : store(st), region(r) { + assert(NonLoc::isCompoundType(r->getValueType())); + } const void *getStore() const { return store.getStore(); } const TypedValueRegion *getRegion() const { return region; } @@ -120,7 +124,7 @@ public: /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); - return APSIntType(Ctx.getTypeSize(T), + return APSIntType(Ctx.getIntWidth(T), !T->isSignedIntegerOrEnumerationType()); } @@ -176,6 +180,11 @@ public: return getValue(X); } + inline const llvm::APSInt& getZeroWithTypeSize(QualType T) { + assert(T->isScalarType()); + return getValue(0, Ctx.getTypeSize(T), true); + } + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index aaecf38f33..9fec217aca 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -19,7 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -383,7 +383,9 @@ public: // Iterator access to formal parameters and their types. private: - typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun; + struct GetTypeFn { + QualType operator()(ParmVarDecl *PD) const { return PD->getType(); } + }; public: /// Return call's formal parameters. @@ -393,7 +395,7 @@ public: /// correspond with the argument value returned by \c getArgSVal(0). virtual ArrayRef<ParmVarDecl*> parameters() const = 0; - typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, get_type_fun> + typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, GetTypeFn> param_type_iterator; /// Returns an iterator over the types of the call's formal parameters. @@ -402,13 +404,11 @@ public: /// definition because it represents a public interface, and probably has /// more annotations. param_type_iterator param_type_begin() const { - return llvm::map_iterator(parameters().begin(), - get_type_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(parameters().begin(), GetTypeFn()); } /// \sa param_type_begin() param_type_iterator param_type_end() const { - return llvm::map_iterator(parameters().end(), - get_type_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(parameters().end(), GetTypeFn()); } // For debugging purposes only @@ -436,20 +436,7 @@ public: return cast<FunctionDecl>(CallEvent::getDecl()); } - RuntimeDefinition getRuntimeDefinition() const override { - const FunctionDecl *FD = getDecl(); - // Note that the AnalysisDeclContext will have the FunctionDecl with - // the definition (if one exists). - if (FD) { - AnalysisDeclContext *AD = - getLocationContext()->getAnalysisDeclContext()-> - getManager()->getContext(FD); - if (AD->getBody()) - return RuntimeDefinition(AD->getDecl()); - } - - return RuntimeDefinition(); - } + RuntimeDefinition getRuntimeDefinition() const override; bool argumentsMayEscape() const override; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index e380982d43..78d38a3d59 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -196,6 +196,13 @@ public: return getState()->getSVal(S, getLocationContext()); } + /// \brief Returns true if the value of \p E is greater than or equal to \p + /// Val under unsigned comparison + bool isGreaterOrEqual(const Expr *E, unsigned long long Val); + + /// Returns true if the value of \p E is negative. + bool isNegative(const Expr *E); + /// \brief Generates a new transition in the program state graph /// (ExplodedGraph). Uses the default CheckerContext predecessor node. /// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index fa12d7727d..c01600d5c9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -184,6 +184,9 @@ std::unique_ptr<ConstraintManager> CreateRangeConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine); +std::unique_ptr<ConstraintManager> +CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine); + } // end GR namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 12ec5b6c64..7472a7147f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index a66e1a1aed..c63ed4a013 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ImmutableMap.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index a710ae68be..dcea5e461d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -20,14 +20,14 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H #include "clang/AST/Decl.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include <memory> @@ -404,7 +404,7 @@ private: }; class ExplodedNodeSet { - typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; + typedef llvm::SmallSetVector<ExplodedNode*, 4> ImplTy; ImplTy Impl; public: @@ -424,7 +424,7 @@ public: unsigned size() const { return Impl.size(); } bool empty() const { return Impl.empty(); } - bool erase(ExplodedNode *N) { return Impl.erase(N); } + bool erase(ExplodedNode *N) { return Impl.remove(N); } void clear() { Impl.clear(); } void insert(const ExplodedNodeSet &S) { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index fa7769bcfc..ecff5c6623 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -196,6 +196,8 @@ public: void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred); + void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); @@ -237,7 +239,7 @@ public: const CFGBlock *DstF) override; /// Called by CoreEngine. Used to processing branching behavior - /// at static initalizers. + /// at static initializers. void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext& BuilderCtx, ExplodedNode *Pred, @@ -621,16 +623,16 @@ private: void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call); - /// If the value of the given expression is a NonLoc, copy it into a new - /// temporary object region, and replace the value of the expression with - /// that. + /// If the value of the given expression \p InitWithAdjustments is a NonLoc, + /// copy it into a new temporary object region, and replace the value of the + /// expression with that. /// - /// If \p ResultE is provided, the new region will be bound to this expression - /// instead of \p E. + /// If \p Result is provided, the new region will be bound to this expression + /// instead of \p InitWithAdjustments. ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, const LocationContext *LC, - const Expr *E, - const Expr *ResultE = nullptr); + const Expr *InitWithAdjustments, + const Expr *Result = nullptr); /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG /// block to find the constructor expression that directly constructed into diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h new file mode 100644 index 0000000000..a4c505ce5f --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h @@ -0,0 +1,50 @@ +//===--- LoopUnrolling.h - Unroll loops -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This header contains the declarations of functions which are used to decide +/// which loops should be completely unrolled and mark their corresponding +/// CFGBlocks. It is done by tracking a stack of loops in the ProgramState. This +/// way specific loops can be marked as completely unrolled. For considering a +/// loop to be completely unrolled it has to fulfill the following requirements: +/// - Currently only forStmts can be considered. +/// - The bound has to be known. +/// - The counter variable has not escaped before/in the body of the loop and +/// changed only in the increment statement corresponding to the loop. It also +/// has to be initialized by a literal in the corresponding initStmt. +/// - Does not contain goto, switch and returnStmt. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H + +#include "clang/Analysis/CFG.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +namespace clang { +namespace ento { +class AnalysisManager; + +/// Returns if the given State indicates that is inside a completely unrolled +/// loop. +bool isUnrolledState(ProgramStateRef State); + +/// Updates the stack of loops contained by the ProgramState. +ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx, + ExplodedNode* Pred, unsigned maxVisitOnPath); + +/// Updates the given ProgramState. In current implementation it removes the top +/// element of the stack of loops. +ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index da4b964424..8ab6656230 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -21,7 +21,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/FoldingSet.h" @@ -182,6 +182,7 @@ protected: MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) { assert(classof(this)); + assert(mgr); } MemRegionManager* getMemRegionManager() const override { return Mgr; } @@ -215,9 +216,12 @@ public: class GlobalsSpaceRegion : public MemSpaceRegion { virtual void anchor(); + protected: - GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) - : MemSpaceRegion(mgr, k) {} + GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) { + assert(classof(this)); + } + public: static bool classof(const MemRegion *R) { Kind k = R->getKind(); @@ -236,7 +240,9 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { const CodeTextRegion *CR; StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) - : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {} + : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) { + assert(cr); + } public: void Profile(llvm::FoldingSetNodeID &ID) const override; @@ -257,9 +263,13 @@ public: /// RegionStoreManager::invalidateRegions (instead of finding all the dependent /// globals, we invalidate the whole parent region). class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { + virtual void anchor() override; + protected: NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) - : GlobalsSpaceRegion(mgr, k) {} + : GlobalsSpaceRegion(mgr, k) { + assert(classof(this)); + } public: @@ -326,7 +336,6 @@ public: }; class HeapSpaceRegion : public MemSpaceRegion { - virtual void anchor(); friend class MemRegionManager; HeapSpaceRegion(MemRegionManager *mgr) @@ -341,10 +350,10 @@ public: }; class UnknownSpaceRegion : public MemSpaceRegion { - virtual void anchor(); friend class MemRegionManager; UnknownSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} + public: void dumpToStream(raw_ostream &os) const override; @@ -355,13 +364,15 @@ public: }; class StackSpaceRegion : public MemSpaceRegion { -private: + virtual void anchor(); + const StackFrameContext *SFC; protected: StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) : MemSpaceRegion(mgr, k), SFC(sfc) { assert(classof(this)); + assert(sfc); } public: @@ -376,7 +387,6 @@ public: }; class StackLocalsSpaceRegion : public StackSpaceRegion { - virtual void anchor(); friend class MemRegionManager; StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} @@ -391,7 +401,6 @@ public: class StackArgumentsSpaceRegion : public StackSpaceRegion { private: - virtual void anchor(); friend class MemRegionManager; StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} @@ -408,11 +417,15 @@ public: /// SubRegion - A region that subsets another larger region. Most regions /// are subclasses of SubRegion. class SubRegion : public MemRegion { -private: virtual void anchor(); + protected: const MemRegion* superRegion; - SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} + SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) { + assert(classof(this)); + assert(sReg); + } + public: const MemRegion* getSuperRegion() const { return superRegion; @@ -440,13 +453,18 @@ public: /// by a call to 'alloca'. class AllocaRegion : public SubRegion { friend class MemRegionManager; -protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of // memory allocated by alloca at the same call site. const Expr *Ex; - AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion) - : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) { + assert(Ex); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, + unsigned Cnt, const MemRegion *superRegion); public: @@ -458,9 +476,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, - unsigned Cnt, const MemRegion *superRegion); - void dumpToStream(raw_ostream &os) const override; static bool classof(const MemRegion* R) { @@ -470,10 +485,12 @@ public: /// TypedRegion - An abstract class representing regions that are typed. class TypedRegion : public SubRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) { + assert(classof(this)); + } public: virtual QualType getLocationType() const = 0; @@ -492,10 +509,12 @@ public: /// TypedValueRegion - An abstract class representing regions having a typed value. class TypedValueRegion : public TypedRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {} + TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) { + assert(classof(this)); + } public: virtual QualType getValueType() const = 0; @@ -524,10 +543,13 @@ public: class CodeTextRegion : public TypedRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} + CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) { + assert(classof(this)); + } + public: bool isBoundable() const override { return false; } @@ -539,13 +561,19 @@ public: /// FunctionCodeRegion - A region that represents code texts of function. class FunctionCodeRegion : public CodeTextRegion { + friend class MemRegionManager; + const NamedDecl *FD; -public: - FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg) + + FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg) : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) { assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd)); } + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, + const MemRegion*); + +public: QualType getLocationType() const override { const ASTContext &Ctx = getContext(); if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) { @@ -568,9 +596,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, - const MemRegion*); - static bool classof(const MemRegion* R) { return R->getKind() == FunctionCodeRegionKind; } @@ -591,8 +616,16 @@ class BlockCodeRegion : public CodeTextRegion { CanQualType locTy; BlockCodeRegion(const BlockDecl *bd, CanQualType lTy, - AnalysisDeclContext *ac, const MemRegion* sreg) - : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {} + AnalysisDeclContext *ac, const CodeSpaceRegion* sreg) + : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) { + assert(bd); + assert(ac); + assert(lTy->getTypePtr()->isBlockPointerType()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const AnalysisDeclContext*, + const MemRegion*); public: QualType getLocationType() const override { @@ -609,10 +642,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, - CanQualType, const AnalysisDeclContext*, - const MemRegion*); - static bool classof(const MemRegion* R) { return R->getKind() == BlockCodeRegionKind; } @@ -626,6 +655,7 @@ public: /// variables. class BlockDataRegion : public TypedRegion { friend class MemRegionManager; + const BlockCodeRegion *BC; const LocationContext *LC; // Can be null */ unsigned BlockCount; @@ -633,10 +663,19 @@ class BlockDataRegion : public TypedRegion { void *OriginalVars; BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc, - unsigned count, const MemRegion *sreg) - : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), - BlockCount(count), - ReferencedVars(nullptr), OriginalVars(nullptr) {} + unsigned count, const MemSpaceRegion *sreg) + : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), + BlockCount(count), ReferencedVars(nullptr), OriginalVars(nullptr) { + assert(bc); + assert(lc); + assert(isa<GlobalImmutableSpaceRegion>(sreg) || + isa<StackLocalsSpaceRegion>(sreg) || + isa<UnknownSpaceRegion>(sreg)); + } + + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *, + const LocationContext *, unsigned, + const MemRegion *); public: const BlockCodeRegion *getCodeRegion() const { return BC; } @@ -686,10 +725,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *, - const LocationContext *, unsigned, - const MemRegion *); - static bool classof(const MemRegion* R) { return R->getKind() == BlockDataRegionKind; } @@ -705,13 +740,20 @@ private: /// map the concept of symbolic values into the domain of regions. Symbolic /// regions do not need to be typed. class SymbolicRegion : public SubRegion { -protected: + friend class MemRegionManager; + const SymbolRef sym; -public: - SymbolicRegion(const SymbolRef s, const MemRegion* sreg) - : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) { + assert(s); + assert(s->getType()->isAnyPointerType() || + s->getType()->isReferenceType() || + s->getType()->isBlockPointerType()); + assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg)); + } +public: SymbolRef getSymbol() const { return sym; } @@ -736,11 +778,13 @@ public: /// StringRegion - Region associated with a StringLiteral. class StringRegion : public TypedValueRegion { friend class MemRegionManager; + const StringLiteral* Str; -protected: - StringRegion(const StringLiteral* str, const MemRegion* sreg) - : TypedValueRegion(sreg, StringRegionKind), Str(str) {} + StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg) + : TypedValueRegion(sreg, StringRegionKind), Str(str) { + assert(str); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const StringLiteral* Str, @@ -772,12 +816,15 @@ public: /// The region associated with an ObjCStringLiteral. class ObjCStringRegion : public TypedValueRegion { friend class MemRegionManager; + const ObjCStringLiteral* Str; -protected: - - ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg) - : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {} - + + ObjCStringRegion(const ObjCStringLiteral *str, + const GlobalInternalSpaceRegion *sreg) + : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) { + assert(str); + } + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCStringLiteral* Str, const MemRegion* superRegion); @@ -807,12 +854,17 @@ public: /// Compound literals are essentially temporaries that are stack allocated /// or in the global constant pool. class CompoundLiteralRegion : public TypedValueRegion { -private: friend class MemRegionManager; + const CompoundLiteralExpr *CL; - CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg) - : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + CompoundLiteralRegion(const CompoundLiteralExpr *cl, + const MemSpaceRegion *sReg) + : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) { + assert(cl); + assert(isa<GlobalInternalSpaceRegion>(sReg) || + isa<StackLocalsSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const CompoundLiteralExpr *CL, @@ -839,8 +891,11 @@ class DeclRegion : public TypedValueRegion { protected: const Decl *D; - DeclRegion(const Decl *d, const MemRegion* sReg, Kind k) - : TypedValueRegion(sReg, k), D(d) {} + DeclRegion(const Decl *d, const MemRegion *sReg, Kind k) + : TypedValueRegion(sReg, k), D(d) { + assert(classof(this)); + assert(d); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, const MemRegion* superRegion, Kind k); @@ -859,17 +914,24 @@ class VarRegion : public DeclRegion { friend class MemRegionManager; // Constructors and private methods. - VarRegion(const VarDecl *vd, const MemRegion* sReg) - : DeclRegion(vd, sReg, VarRegionKind) {} + VarRegion(const VarDecl *vd, const MemRegion *sReg) + : DeclRegion(vd, sReg, VarRegionKind) { + // VarRegion appears in unknown space when it's a block variable as seen + // from a block using it, when this block is analyzed at top-level. + // Other block variables appear within block data regions, + // which, unlike everything else on this list, are not memory spaces. + assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) || + isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, const MemRegion *superRegion) { DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); } +public: void Profile(llvm::FoldingSetNodeID& ID) const override; -public: const VarDecl *getDecl() const { return cast<VarDecl>(D); } const StackFrameContext *getStackFrame() const; @@ -895,17 +957,19 @@ public: /// referred to by 'this', but rather 'this' itself. class CXXThisRegion : public TypedValueRegion { friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, - const MemRegion *sReg) - : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + const StackArgumentsSpaceRegion *sReg) + : TypedValueRegion(sReg, CXXThisRegionKind), + ThisPointerTy(thisPointerTy) {} static void ProfileRegion(llvm::FoldingSetNodeID &ID, const PointerType *PT, const MemRegion *sReg); +public: void Profile(llvm::FoldingSetNodeID &ID) const override; -public: QualType getValueType() const override { return QualType(ThisPointerTy, 0); } @@ -923,9 +987,14 @@ private: class FieldRegion : public DeclRegion { friend class MemRegionManager; - FieldRegion(const FieldDecl *fd, const MemRegion* sReg) + FieldRegion(const FieldDecl *fd, const SubRegion* sReg) : DeclRegion(fd, sReg, FieldRegionKind) {} + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + public: const FieldDecl *getDecl() const { return cast<FieldDecl>(D); } @@ -936,11 +1005,6 @@ public: DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, - const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); - } - static bool classof(const MemRegion* R) { return R->getKind() == FieldRegionKind; } @@ -954,10 +1018,9 @@ public: }; class ObjCIvarRegion : public DeclRegion { - friend class MemRegionManager; - ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg); + ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg); static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, const MemRegion* superRegion); @@ -982,7 +1045,6 @@ public: class ElementRegion; class RegionRawOffset { -private: friend class ElementRegion; const MemRegion *Region; @@ -1007,9 +1069,9 @@ class ElementRegion : public TypedValueRegion { QualType ElementType; NonLoc Index; - ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) - : TypedValueRegion(sReg, ElementRegionKind), - ElementType(elementType), Index(Idx) { + ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg) + : TypedValueRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { assert((!Idx.getAs<nonloc::ConcreteInt>() || Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) && "The index must be signed"); @@ -1047,12 +1109,16 @@ class CXXTempObjectRegion : public TypedValueRegion { Expr const *Ex; - CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) - : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {} + CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg) + : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) { + assert(E); + assert(isa<StackLocalsSpaceRegion>(sReg) || + isa<GlobalInternalSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID &ID, Expr const *E, const MemRegion *sReg); - + public: const Expr *getExpr() const { return Ex; } @@ -1077,8 +1143,10 @@ class CXXBaseObjectRegion : public TypedValueRegion { llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data; CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, - const MemRegion *SReg) - : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {} + const SubRegion *SReg) + : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) { + assert(RD); + } static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, bool IsVirtual, const MemRegion *SReg); @@ -1204,16 +1272,16 @@ public: /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl and super region. - const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); - + const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR); + /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, - const MemRegion *superRegion, + const SubRegion *superRegion, ASTContext &Ctx); const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getElementRegion(ER->getElementType(), ER->getIndex(), superRegion, ER->getContext()); } @@ -1223,10 +1291,10 @@ public: /// memory region (which typically represents the memory representing /// a structure or class). const FieldRegion *getFieldRegion(const FieldDecl *fd, - const MemRegion* superRegion); + const SubRegion* superRegion); const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getFieldRegion(FR->getDecl(), superRegion); } @@ -1235,7 +1303,7 @@ public: /// to the containing region (which typically represents the Objective-C /// object). const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd, - const MemRegion* superRegion); + const SubRegion* superRegion); const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, LocationContext const *LC); @@ -1245,14 +1313,14 @@ public: /// /// The type of \p Super is assumed be a class deriving from \p BaseClass. const CXXBaseObjectRegion * - getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super, + getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super, bool IsVirtual); /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different /// super region. const CXXBaseObjectRegion * getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, baseReg->isVirtual()); } @@ -1276,17 +1344,22 @@ public: const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); private: - template <typename RegionTy, typename A1> - RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + template <typename RegionTy, typename SuperTy, + typename Arg1Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, + const SuperTy* superRegion); + + template <typename RegionTy, typename SuperTy, + typename Arg1Ty, typename Arg2Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, + const SuperTy* superRegion); + + template <typename RegionTy, typename SuperTy, + typename Arg1Ty, typename Arg2Ty, typename Arg3Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, + const Arg3Ty arg3, + const SuperTy* superRegion); - template <typename RegionTy, typename A1, typename A2> - RegionTy* getSubRegion(const A1 a1, const A2 a2, - const MemRegion* superRegion); - - template <typename RegionTy, typename A1, typename A2, typename A3> - RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, - const MemRegion* superRegion); - template <typename REG> const REG* LazyAllocate(REG*& region); @@ -1339,21 +1412,18 @@ public: bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const; bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const; }; - -} // end GR namespace - -} // end clang namespace //===----------------------------------------------------------------------===// // Pretty-printing regions. //===----------------------------------------------------------------------===// - -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::MemRegion* R) { +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::MemRegion *R) { R->dumpToStream(os); return os; } -} // end llvm namespace + +} // namespace ento + +} // namespace clang #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 2910ef4212..e3a2164b11 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -43,6 +43,7 @@ typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)( ProgramStateManager &, SubEngine *); typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)( ProgramStateManager &); +typedef llvm::ImmutableMap<const SubRegion*, TaintTagType> TaintedSubRegions; //===----------------------------------------------------------------------===// // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. @@ -343,6 +344,9 @@ public: ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the value is marked as tainted. + ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the symbol is marked as tainted. ProgramStateRef addTaint(SymbolRef S, TaintTagType Kind = TaintTagGeneric) const; @@ -351,6 +355,14 @@ public: ProgramStateRef addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in a which a sub-region of a given symbol is tainted. + /// This might be necessary when referring to regions that can not have an + /// individual symbol, e.g. if they are represented by the default binding of + /// a LazyCompoundVal. + ProgramStateRef addPartialTaint(SymbolRef ParentSym, + const SubRegion *SubRegion, + TaintTagType Kind = TaintTagGeneric) const; + /// Check if the statement is tainted in the current state. bool isTainted(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; @@ -453,6 +465,7 @@ private: std::unique_ptr<ConstraintManager> ConstraintMgr; ProgramState::GenericDataMap::Factory GDMFactory; + TaintedSubRegions::Factory TSRFactory; typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; GDMContextsTy GDMContexts; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index a4c01fc453..d58d0a690c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -112,6 +112,11 @@ public: /// Evaluates a given SVal. If the SVal has only one possible (integer) value, /// that value is returned. Otherwise, returns NULL. virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0; + + /// Simplify symbolic expressions within a given SVal. Return an SVal + /// that represents the same value, but is hopefully easier to work with + /// than the original SVal. + virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0; /// Constructs a symbolic expression for two non-location values. SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op, @@ -310,6 +315,13 @@ public: return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); } + /// Create NULL pointer, with proper pointer bit-width for given address + /// space. + /// \param type pointer type. + Loc makeNullWithType(QualType type) { + return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type)); + } + Loc makeNull() { return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index cc3c02a02c..af1af4590d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -41,6 +41,22 @@ class MemRegionManager; class ProgramStateManager; class SValBuilder; +namespace nonloc { +/// Sub-kinds for NonLoc values. +enum Kind { +#define NONLOC_SVAL(Id, Parent) Id ## Kind, +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" +}; +} + +namespace loc { +/// Sub-kinds for Loc values. +enum Kind { +#define LOC_SVAL(Id, Parent) Id ## Kind, +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" +}; +} + /// SVal - This represents a symbolic expression, which can be either /// an L-value or an R-value. /// @@ -75,10 +91,7 @@ public: template<typename T> T castAs() const { assert(T::isKind(*this)); - T t; - SVal& sv = t; - sv = *this; - return t; + return *static_cast<const T *>(this); } /// \brief Convert to the specified SVal type, returning None if this SVal is @@ -87,10 +100,7 @@ public: Optional<T> getAs() const { if (!T::isKind(*this)) return None; - T t; - SVal& sv = t; - sv = *this; - return t; + return *static_cast<const T *>(this); } /// BufferTy - A temporary buffer to hold a set of SVals. @@ -188,6 +198,10 @@ public: } }; +inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) { + V.dumpToStream(os); + return os; +} class UndefinedVal : public SVal { public: @@ -273,6 +287,11 @@ protected: public: void dumpToStream(raw_ostream &Out) const; + static inline bool isCompoundType(QualType T) { + return T->isArrayType() || T->isRecordType() || + T->isComplexType() || T->isVectorType(); + } + private: friend class SVal; static bool isKind(const SVal& V) { @@ -307,15 +326,11 @@ private: namespace nonloc { -enum Kind { -#define NONLOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; - /// \brief Represents symbolic expression. class SymbolVal : public NonLoc { public: - SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + SymbolVal() = delete; + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); } SymbolRef getSymbol() const { return (const SymExpr*) Data; @@ -327,7 +342,6 @@ public: private: friend class SVal; - SymbolVal() {} static bool isKind(const SVal& V) { return V.getBaseKind() == NonLocKind && V.getSubKind() == SymbolValKind; @@ -373,7 +387,11 @@ class LocAsInteger : public NonLoc { explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) : NonLoc(LocAsIntegerKind, &data) { - assert (data.first.getAs<Loc>()); + // We do not need to represent loc::ConcreteInt as LocAsInteger, + // as it'd collapse into a nonloc::ConcreteInt instead. + assert(data.first.getBaseKind() == LocKind && + (data.first.getSubKind() == loc::MemRegionValKind || + data.first.getSubKind() == loc::GotoLabelKind)); } public: @@ -513,14 +531,11 @@ private: namespace loc { -enum Kind { -#define LOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; - class GotoLabel : public Loc { public: - explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} + explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) { + assert(Label); + } const LabelDecl *getLabel() const { return static_cast<const LabelDecl*>(Data); @@ -541,7 +556,9 @@ private: class MemRegionVal : public Loc { public: - explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {} + explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) { + assert(r); + } /// \brief Get the underlining region. const MemRegion* getRegion() const { @@ -609,11 +626,6 @@ private: } // end clang namespace namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - clang::ento::SVal V) { - V.dumpToStream(os); - return os; -} template <typename T> struct isPodLike; template <> struct isPodLike<clang::ento::SVal> { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 7fa7515bf2..25d20a17af 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -51,7 +51,7 @@ public: virtual ~StoreManager() {} /// Return the value bound to specified location in a given state. - /// \param[in] store The analysis state. + /// \param[in] store The store in which to make the lookup. /// \param[in] loc The symbolic memory location. /// \param[in] T An optional type that provides a hint indicating the /// expected type of the returned value. This is used if the value is @@ -83,12 +83,12 @@ public: return getDefaultBinding(lcv.getStore(), lcv.getRegion()); } - /// Return a state with the specified value bound to the given location. - /// \param[in] store The analysis state. + /// Return a store with the specified value bound to the given location. + /// \param[in] store The store in which to make the binding. /// \param[in] loc The symbolic memory location. /// \param[in] val The value to bind to location \c loc. - /// \return A pointer to a ProgramState object that contains the same - /// bindings as \c state with the addition of having the value specified + /// \return A StoreRef object that contains the same + /// bindings as \c store with the addition of having the value specified /// by \c val bound to the location given for \c loc. virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; @@ -160,7 +160,7 @@ public: /// valid only if Failed flag is set to false. SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed); - const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); + const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T); /// castRegion - Used by ExprEngine::VisitCast to handle casts from /// a MemRegion* to a specific location type. 'R' is the region being @@ -259,8 +259,9 @@ public: virtual void iterBindings(Store store, BindingsHandler& f) = 0; protected: - const MemRegion *MakeElementRegion(const MemRegion *baseRegion, - QualType pointeeTy, uint64_t index = 0); + const ElementRegion *MakeElementRegion(const SubRegion *baseRegion, + QualType pointeeTy, + uint64_t index = 0); /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index e16df136ca..8ccd34751b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -83,7 +83,7 @@ public: const CFGBlock *DstF) = 0; /// Called by CoreEngine. Used to processing branching behavior - /// at static initalizers. + /// at static initializers. virtual void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext& BuilderCtx, ExplodedNode *Pred, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h index 18bc60754b..9780d01447 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h @@ -42,6 +42,12 @@ private: protected: SymExpr(Kind k) : K(k) {} + static bool isValidTypeForSymbol(QualType T) { + // FIXME: Depending on whether we choose to deprecate structural symbols, + // this may become much stricter. + return !T.isNull() && !T->isVoidType(); + } + public: virtual ~SymExpr() {} @@ -92,6 +98,12 @@ public: virtual const MemRegion *getOriginRegion() const { return nullptr; } }; +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} + typedef const SymExpr *SymbolRef; typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; @@ -103,7 +115,9 @@ class SymbolData : public SymExpr { const SymbolID Sym; protected: - SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) { + assert(classof(this)); + } public: ~SymbolData() override {} diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index f00dce568e..7d2e5ad8ba 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -17,7 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" @@ -44,7 +44,10 @@ class SymbolRegionValue : public SymbolData { public: SymbolRegionValue(SymbolID sym, const TypedValueRegion *r) - : SymbolData(SymbolRegionValueKind, sym), R(r) {} + : SymbolData(SymbolRegionValueKind, sym), R(r) { + assert(r); + assert(isValidTypeForSymbol(r->getValueType())); + } const TypedValueRegion* getRegion() const { return R; } @@ -81,7 +84,15 @@ public: SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, QualType t, unsigned count, const void *symbolTag) : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count), - LCtx(lctx), SymbolTag(symbolTag) {} + LCtx(lctx), SymbolTag(symbolTag) { + // FIXME: 's' might be a nullptr if we're conducting invalidation + // that was caused by a destructor call on a temporary object, + // which has no statement associated with it. + // Due to this, we might be creating the same invalidation symbol for + // two different invalidation passes (for two different temporaries). + assert(lctx); + assert(isValidTypeForSymbol(t)); + } const Stmt *getStmt() const { return S; } unsigned getCount() const { return Count; } @@ -120,7 +131,11 @@ class SymbolDerived : public SymbolData { public: SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r) - : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {} + : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) { + assert(parent); + assert(r); + assert(isValidTypeForSymbol(r->getValueType())); + } SymbolRef getParentSymbol() const { return parentSymbol; } const TypedValueRegion *getRegion() const { return R; } @@ -155,7 +170,9 @@ class SymbolExtent : public SymbolData { public: SymbolExtent(SymbolID sym, const SubRegion *r) - : SymbolData(SymbolExtentKind, sym), R(r) {} + : SymbolData(SymbolExtentKind, sym), R(r) { + assert(r); + } const SubRegion *getRegion() const { return R; } @@ -193,7 +210,13 @@ public: SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t, const LocationContext *LCtx, unsigned count, const void *tag) : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx), - Count(count), Tag(tag) {} + Count(count), Tag(tag) { + assert(r); + assert(s); + assert(isValidTypeForSymbol(t)); + assert(LCtx); + assert(tag); + } const MemRegion *getRegion() const { return R; } const Stmt *getStmt() const { return S; } @@ -236,8 +259,13 @@ class SymbolCast : public SymExpr { QualType ToTy; public: - SymbolCast(const SymExpr *In, QualType From, QualType To) : - SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { } + SymbolCast(const SymExpr *In, QualType From, QualType To) + : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { + assert(In); + assert(isValidTypeForSymbol(From)); + // FIXME: GenericTaintChecker creates symbols of void type. + // Otherwise, 'To' should also be a valid type. + } QualType getType() const override { return ToTy; } @@ -270,7 +298,10 @@ class BinarySymExpr : public SymExpr { protected: BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) - : SymExpr(k), Op(op), T(t) {} + : SymExpr(k), Op(op), T(t) { + assert(classof(this)); + assert(isValidTypeForSymbol(t)); + } public: // FIXME: We probably need to make this out-of-line to avoid redundant @@ -293,8 +324,10 @@ class SymIntExpr : public BinarySymExpr { public: SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) - : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {} + const llvm::APSInt &rhs, QualType t) + : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(lhs); + } void dumpToStream(raw_ostream &os) const override; @@ -327,9 +360,11 @@ class IntSymExpr : public BinarySymExpr { const SymExpr *RHS; public: - IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, + IntSymExpr(const llvm::APSInt &lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {} + : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(rhs); + } void dumpToStream(raw_ostream &os) const override; @@ -364,7 +399,10 @@ class SymSymExpr : public BinarySymExpr { public: SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {} + : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(lhs); + assert(rhs); + } const SymExpr *getLHS() const { return LHS; } const SymExpr *getRHS() const { return RHS; } @@ -595,11 +633,4 @@ public: } // end clang namespace -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::SymExpr *SE) { - SE->dumpToStream(os); - return os; -} -} // end llvm namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h index d39b5017d3..7b76263f04 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -35,6 +35,16 @@ template<> struct ProgramStateTrait<TaintMap> static void *GDMIndex() { static int index = 0; return &index; } }; +/// The GDM component mapping derived symbols' parent symbols to their +/// underlying regions. This is used to efficiently check whether a symbol is +/// tainted when it represents a sub-region of a tainted symbol. +struct DerivedSymTaint {}; +typedef llvm::ImmutableMap<SymbolRef, TaintedSubRegions> DerivedSymTaintImpl; +template<> struct ProgramStateTrait<DerivedSymTaint> + : public ProgramStatePartialTrait<DerivedSymTaintImpl> { + static void *GDMIndex() { static int index; return &index; } +}; + class TaintManager { TaintManager() {} diff --git a/include/clang/Tooling/ASTDiff/ASTDiff.h b/include/clang/Tooling/ASTDiff/ASTDiff.h new file mode 100644 index 0000000000..dd11c91ac0 --- /dev/null +++ b/include/clang/Tooling/ASTDiff/ASTDiff.h @@ -0,0 +1,127 @@ +//===- ASTDiff.h - AST differencing API -----------------------*- C++ -*- -===// +// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file specifies an interface that can be used to compare C++ syntax +// trees. +// +// We use the gumtree algorithm which combines a heuristic top-down search that +// is able to match large subtrees that are equivalent, with an optimal +// algorithm to match small subtrees. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H +#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H + +#include "clang/Tooling/ASTDiff/ASTDiffInternal.h" + +namespace clang { +namespace diff { + +enum ChangeKind { + None, + Delete, // (Src): delete node Src. + Update, // (Src, Dst): update the value of node Src to match Dst. + Insert, // (Src, Dst, Pos): insert Src as child of Dst at offset Pos. + Move, // (Src, Dst, Pos): move Src to be a child of Dst at offset Pos. + UpdateMove // Same as Move plus Update. +}; + +/// Represents a Clang AST node, alongside some additional information. +struct Node { + NodeId Parent, LeftMostDescendant, RightMostDescendant; + int Depth, Height, Shift = 0; + ast_type_traits::DynTypedNode ASTNode; + SmallVector<NodeId, 4> Children; + ChangeKind Change = None; + + ast_type_traits::ASTNodeKind getType() const; + StringRef getTypeLabel() const; + bool isLeaf() const { return Children.empty(); } + llvm::Optional<StringRef> getIdentifier() const; + llvm::Optional<std::string> getQualifiedIdentifier() const; +}; + +class ASTDiff { +public: + ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options); + ~ASTDiff(); + + // Returns the ID of the node that is mapped to the given node in SourceTree. + NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const; + + class Impl; + +private: + std::unique_ptr<Impl> DiffImpl; +}; + +/// SyntaxTree objects represent subtrees of the AST. +/// They can be constructed from any Decl or Stmt. +class SyntaxTree { +public: + /// Constructs a tree from a translation unit. + SyntaxTree(ASTContext &AST); + /// Constructs a tree from any AST node. + template <class T> + SyntaxTree(T *Node, ASTContext &AST) + : TreeImpl(llvm::make_unique<Impl>(this, Node, AST)) {} + SyntaxTree(SyntaxTree &&Other) = default; + ~SyntaxTree(); + + const ASTContext &getASTContext() const; + StringRef getFilename() const; + + int getSize() const; + NodeId getRootId() const; + using PreorderIterator = NodeId; + PreorderIterator begin() const; + PreorderIterator end() const; + + const Node &getNode(NodeId Id) const; + int findPositionInParent(NodeId Id) const; + + // Returns the starting and ending offset of the node in its source file. + std::pair<unsigned, unsigned> getSourceRangeOffsets(const Node &N) const; + + /// Serialize the node attributes to a string representation. This should + /// uniquely distinguish nodes of the same kind. Note that this function just + /// returns a representation of the node value, not considering descendants. + std::string getNodeValue(NodeId Id) const; + std::string getNodeValue(const Node &Node) const; + + class Impl; + std::unique_ptr<Impl> TreeImpl; +}; + +struct ComparisonOptions { + /// During top-down matching, only consider nodes of at least this height. + int MinHeight = 2; + + /// During bottom-up matching, match only nodes with at least this value as + /// the ratio of their common descendants. + double MinSimilarity = 0.5; + + /// Whenever two subtrees are matched in the bottom-up phase, the optimal + /// mapping is computed, unless the size of either subtrees exceeds this. + int MaxSize = 100; + + bool StopAfterTopDown = false; + + /// Returns false if the nodes should never be matched. + bool isMatchingAllowed(const Node &N1, const Node &N2) const { + return N1.getType().isSame(N2.getType()); + } +}; + +} // end namespace diff +} // end namespace clang + +#endif diff --git a/include/clang/Tooling/ASTDiff/ASTDiffInternal.h b/include/clang/Tooling/ASTDiff/ASTDiffInternal.h new file mode 100644 index 0000000000..a76ad37336 --- /dev/null +++ b/include/clang/Tooling/ASTDiff/ASTDiffInternal.h @@ -0,0 +1,48 @@ +//===- ASTDiffInternal.h --------------------------------------*- C++ -*- -===// +// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H +#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H + +#include "clang/AST/ASTTypeTraits.h" + +namespace clang { +namespace diff { + +using DynTypedNode = ast_type_traits::DynTypedNode; + +class SyntaxTree; +class SyntaxTreeImpl; +struct ComparisonOptions; + +/// Within a tree, this identifies a node by its preorder offset. +struct NodeId { +private: + static constexpr int InvalidNodeId = -1; + +public: + int Id; + + NodeId() : Id(InvalidNodeId) {} + NodeId(int Id) : Id(Id) {} + + operator int() const { return Id; } + NodeId &operator++() { return ++Id, *this; } + NodeId &operator--() { return --Id, *this; } + // Support defining iterators on NodeId. + NodeId &operator*() { return *this; } + + bool isValid() const { return Id != InvalidNodeId; } + bool isInvalid() const { return Id == InvalidNodeId; } +}; + +} // end namespace diff +} // end namespace clang +#endif diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h index 1fd7be6887..4eb02251a7 100644 --- a/include/clang/Tooling/ArgumentsAdjusters.h +++ b/include/clang/Tooling/ArgumentsAdjusters.h @@ -44,6 +44,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster(); /// arguments. ArgumentsAdjuster getClangStripOutputAdjuster(); +/// \brief Gets an argument adjuster which removes dependency-file +/// related command line arguments. +ArgumentsAdjuster getClangStripDependencyFileAdjuster(); + enum class ArgumentInsertPosition { BEGIN, END }; /// \brief Gets an argument adjuster which inserts \p Extra arguments in the diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h index 3d630c5f76..15e8161dd7 100644 --- a/include/clang/Tooling/CommonOptionsParser.h +++ b/include/clang/Tooling/CommonOptionsParser.h @@ -27,8 +27,10 @@ #ifndef LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H #define LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H +#include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" namespace clang { namespace tooling { @@ -84,14 +86,19 @@ public: /// /// All options not belonging to \p Category become hidden. /// - /// I also allows calls to set the required number of positional parameters. - /// - /// This constructor exits program in case of error. + /// It also allows calls to set the required number of positional parameters. CommonOptionsParser(int &argc, const char **argv, llvm::cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview = nullptr); + /// \brief A factory method that is similar to the above constructor, except + /// this returns an error instead exiting the program on error. + static llvm::Expected<CommonOptionsParser> + create(int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview = nullptr); + /// Returns a reference to the loaded compilations database. CompilationDatabase &getCompilations() { return *Compilations; @@ -102,13 +109,46 @@ public: return SourcePathList; } + /// Returns the argument adjuster calculated from "--extra-arg" and + //"--extra-arg-before" options. + ArgumentsAdjuster getArgumentsAdjuster() { return Adjuster; } + static const char *const HelpMessage; private: + CommonOptionsParser() = default; + + llvm::Error init(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview); + std::unique_ptr<CompilationDatabase> Compilations; std::vector<std::string> SourcePathList; - std::vector<std::string> ExtraArgsBefore; - std::vector<std::string> ExtraArgsAfter; + ArgumentsAdjuster Adjuster; +}; + +class ArgumentsAdjustingCompilations : public CompilationDatabase { +public: + ArgumentsAdjustingCompilations( + std::unique_ptr<CompilationDatabase> Compilations) + : Compilations(std::move(Compilations)) {} + + void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster); + + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override; + + std::vector<std::string> getAllFiles() const override; + + std::vector<CompileCommand> getAllCompileCommands() const override; + +private: + std::unique_ptr<CompilationDatabase> Compilations; + std::vector<ArgumentsAdjuster> Adjusters; + + std::vector<CompileCommand> + adjustCommands(std::vector<CompileCommand> Commands) const; }; } // namespace tooling diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h index 4611d3cdae..28af33a407 100644 --- a/include/clang/Tooling/CompilationDatabase.h +++ b/include/clang/Tooling/CompilationDatabase.h @@ -60,16 +60,6 @@ struct CompileCommand { /// The output file associated with the command. std::string Output; - - /// \brief An optional mapping from each file's path to its content for all - /// files needed for the compilation that are not available via the file - /// system. - /// - /// Note that a tool implementation is required to fall back to the file - /// system if a source file is not provided in the mapped sources, as - /// compilation databases will usually not provide all files in mapped sources - /// for performance reasons. - std::vector<std::pair<std::string, std::string> > MappedSources; }; /// \brief Interface for compilation databases. @@ -114,7 +104,7 @@ public: /// \brief Returns all compile commands in which the specified file was /// compiled. /// - /// This includes compile comamnds that span multiple source files. + /// This includes compile commands that span multiple source files. /// For example, consider a project with the following compilations: /// $ clang++ -o test a.cc b.cc t.cc /// $ clang++ -o production a.cc b.cc -DPRODUCTION @@ -186,10 +176,11 @@ public: /// the number of arguments before "--", if "--" was found in the argument /// list. /// \param Argv Points to the command line arguments. + /// \param ErrorMsg Contains error text if the function returns null pointer. /// \param Directory The base directory used in the FixedCompilationDatabase. - static FixedCompilationDatabase *loadFromCommandLine(int &Argc, - const char *const *Argv, - Twine Directory = "."); + static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine( + int &Argc, const char *const *Argv, std::string &ErrorMsg, + Twine Directory = "."); /// \brief Constructs a compilation data base from a specified directory /// and command line. diff --git a/include/clang/Tooling/Core/Diagnostic.h b/include/clang/Tooling/Core/Diagnostic.h index d657f16df1..b4920d4fe4 100644 --- a/include/clang/Tooling/Core/Diagnostic.h +++ b/include/clang/Tooling/Core/Diagnostic.h @@ -58,9 +58,9 @@ struct Diagnostic { Diagnostic(llvm::StringRef DiagnosticName, Level DiagLevel, StringRef BuildDirectory); - Diagnostic(llvm::StringRef DiagnosticName, DiagnosticMessage &Message, - llvm::StringMap<Replacements> &Fix, - SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, + Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message, + const llvm::StringMap<Replacements> &Fix, + const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, llvm::StringRef BuildDirectory); /// \brief Name identifying the Diagnostic. diff --git a/include/clang/Tooling/Core/Replacement.h b/include/clang/Tooling/Core/Replacement.h index 8d4a22adf3..3fea9aee60 100644 --- a/include/clang/Tooling/Core/Replacement.h +++ b/include/clang/Tooling/Core/Replacement.h @@ -255,7 +255,7 @@ class Replacements { /// \brief Merges \p Replaces into the current replacements. \p Replaces /// refers to code after applying the current replacements. - Replacements merge(const Replacements &Replaces) const; + LLVM_NODISCARD Replacements merge(const Replacements &Replaces) const; // Returns the affected ranges in the changed code. std::vector<Range> getAffectedRanges() const; diff --git a/include/clang/Tooling/DiagnosticsYaml.h b/include/clang/Tooling/DiagnosticsYaml.h index f32b9fa9c9..4d6ff06364 100644 --- a/include/clang/Tooling/DiagnosticsYaml.h +++ b/include/clang/Tooling/DiagnosticsYaml.h @@ -56,6 +56,9 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> { MappingNormalization<NormalizedDiagnostic, clang::tooling::Diagnostic> Keys( Io, D); Io.mapRequired("DiagnosticName", Keys->DiagnosticName); + Io.mapRequired("Message", Keys->Message.Message); + Io.mapRequired("FileOffset", Keys->Message.FileOffset); + Io.mapRequired("FilePath", Keys->Message.FilePath); // FIXME: Export properly all the different fields. @@ -82,17 +85,7 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> { template <> struct MappingTraits<clang::tooling::TranslationUnitDiagnostics> { static void mapping(IO &Io, clang::tooling::TranslationUnitDiagnostics &Doc) { Io.mapRequired("MainSourceFile", Doc.MainSourceFile); - - std::vector<clang::tooling::Diagnostic> Diagnostics; - for (auto &Diagnostic : Doc.Diagnostics) { - // FIXME: Export all diagnostics, not just the ones with fixes. - // Update MappingTraits<clang::tooling::Diagnostic>::mapping. - if (Diagnostic.Fix.size() > 0) { - Diagnostics.push_back(Diagnostic); - } - } - Io.mapRequired("Diagnostics", Diagnostics); - Doc.Diagnostics = Diagnostics; + Io.mapRequired("Diagnostics", Doc.Diagnostics); } }; } // end namespace yaml diff --git a/include/clang/Tooling/Execution.h b/include/clang/Tooling/Execution.h new file mode 100644 index 0000000000..9d07c5659e --- /dev/null +++ b/include/clang/Tooling/Execution.h @@ -0,0 +1,168 @@ +//===--- Execution.h - Executing clang frontend actions -*- C++ ---------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines framework for executing clang frontend actions. +// +// The framework can be extended to support different execution plans including +// standalone execution on the given TUs or parallel execution on all TUs in +// the codebase. +// +// In order to enable multiprocessing execution, tool actions are expected to +// output result into the ToolResults provided by the executor. The +// `ToolResults` is an interface that abstracts how results are stored e.g. +// in-memory for standalone execution or on-disk for large-scale execution. +// +// New executors can be registered as ToolExecutorPlugins via the +// `ToolExecutorPluginRegistry`. CLI tools can use +// `createExecutorFromCommandLineArgs` to create a specific registered executor +// according to the command-line arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_EXECUTION_H +#define LLVM_CLANG_TOOLING_EXECUTION_H + +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +/// \brief An abstraction for the result of a tool execution. For example, the +/// underlying result can be in-memory or on-disk. +/// +/// Results should be string key-value pairs. For example, a refactoring tool +/// can use source location as key and a replacement in YAML format as value. +class ToolResults { +public: + virtual ~ToolResults() = default; + virtual void addResult(StringRef Key, StringRef Value) = 0; + virtual std::vector<std::pair<std::string, std::string>> AllKVResults() = 0; + virtual void forEachResult( + llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) = 0; +}; + +class InMemoryToolResults : public ToolResults { +public: + void addResult(StringRef Key, StringRef Value) override; + std::vector<std::pair<std::string, std::string>> AllKVResults() override; + void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)> + Callback) override; + +private: + std::vector<std::pair<std::string, std::string>> KVResults; +}; + +/// \brief The context of an execution, including the information about +/// compilation and results. +class ExecutionContext { +public: + virtual ~ExecutionContext() {} + + /// \brief Initializes a context. This does not take ownership of `Results`. + explicit ExecutionContext(ToolResults *Results) : Results(Results) {} + + /// \brief Adds a KV pair to the result container of this execution. + void reportResult(StringRef Key, StringRef Value); + + // Returns the source control system's revision number if applicable. + // Otherwise returns an empty string. + virtual std::string getRevision() { return ""; } + + // Returns the corpus being analyzed, e.g. "llvm" for the LLVM codebase, if + // applicable. + virtual std::string getCorpus() { return ""; } + + // Returns the currently processed compilation unit if available. + virtual std::string getCurrentCompilationUnit() { return ""; } + +private: + ToolResults *Results; +}; + +/// \brief Interface for executing clang frontend actions. +/// +/// This can be extended to support running tool actions in different +/// execution mode, e.g. on a specific set of TUs or many TUs in parallel. +/// +/// New executors can be registered as ToolExecutorPlugins via the +/// `ToolExecutorPluginRegistry`. CLI tools can use +/// `createExecutorFromCommandLineArgs` to create a specific registered +/// executor according to the command-line arguments. +class ToolExecutor { +public: + virtual ~ToolExecutor() {} + + /// \brief Returns the name of a specific executor. + virtual StringRef getExecutorName() const = 0; + + /// \brief Executes each action with a corresponding arguments adjuster. + virtual llvm::Error + execute(llvm::ArrayRef< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions) = 0; + + /// \brief Convenient functions for the above `execute`. + llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action); + /// Executes an action with an argument adjuster. + llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action, + ArgumentsAdjuster Adjuster); + + /// \brief Returns a reference to the execution context. + /// + /// This should be passed to tool callbacks, and tool callbacks should report + /// results via the returned context. + virtual ExecutionContext *getExecutionContext() = 0; + + /// \brief Returns a reference to the result container. + /// + /// NOTE: This should only be used after the execution finishes. Tool + /// callbacks should report results via `ExecutionContext` instead. + virtual ToolResults *getToolResults() = 0; + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A buffer of the file's content. + virtual void mapVirtualFile(StringRef FilePath, StringRef Content) = 0; +}; + +/// \brief Interface for factories that create specific executors. This is also +/// used as a plugin to be registered into ToolExecutorPluginRegistry. +class ToolExecutorPlugin { +public: + virtual ~ToolExecutorPlugin() {} + + /// \brief Create an `ToolExecutor`. + /// + /// `OptionsParser` can be consumed (e.g. moved) if the creation succeeds. + virtual llvm::Expected<std::unique_ptr<ToolExecutor>> + create(CommonOptionsParser &OptionsParser) = 0; +}; + +/// \brief This creates a ToolExecutor that is in the global registry based on +/// commandline arguments. +/// +/// This picks the right executor based on the `--executor` option. This parses +/// the commandline arguments with `CommonOptionsParser`, so caller does not +/// need to parse again. +/// +/// By default, this creates a `StandaloneToolExecutor` ("standalone") if +/// `--executor` is not provided. +llvm::Expected<std::unique_ptr<ToolExecutor>> +createExecutorFromCommandLineArgs(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview = nullptr); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_EXECUTION_H diff --git a/include/clang/Tooling/FixIt.h b/include/clang/Tooling/FixIt.h index e2259d4357..c1e5088492 100644 --- a/include/clang/Tooling/FixIt.h +++ b/include/clang/Tooling/FixIt.h @@ -65,6 +65,13 @@ FixItHint createReplacement(const D &Destination, const S &Source, getText(Source, Context)); } +// \brief Returns a FixItHint to replace \p Destination by \p Source. +template <typename D> +FixItHint createReplacement(const D &Destination, StringRef Source) { + return FixItHint::CreateReplacement(internal::getSourceRange(Destination), + Source); +} + } // end namespace fixit } // end namespace tooling } // end namespace clang diff --git a/include/clang/Tooling/Refactoring/ASTSelection.h b/include/clang/Tooling/Refactoring/ASTSelection.h new file mode 100644 index 0000000000..aa02a6899e --- /dev/null +++ b/include/clang/Tooling/Refactoring/ASTSelection.h @@ -0,0 +1,155 @@ +//===--- ASTSelection.h - Clang refactoring library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include <vector> + +namespace clang { + +class ASTContext; + +namespace tooling { + +enum class SourceSelectionKind { + /// A node that's not selected. + None, + + /// A node that's considered to be selected because the whole selection range + /// is inside of its source range. + ContainsSelection, + /// A node that's considered to be selected because the start of the selection + /// range is inside its source range. + ContainsSelectionStart, + /// A node that's considered to be selected because the end of the selection + /// range is inside its source range. + ContainsSelectionEnd, + + /// A node that's considered to be selected because the node is entirely in + /// the selection range. + InsideSelection, +}; + +/// Represents a selected AST node. +/// +/// AST selection is represented using a tree of \c SelectedASTNode. The tree +/// follows the top-down shape of the actual AST. Each selected node has +/// a selection kind. The kind might be none as the node itself might not +/// actually be selected, e.g. a statement in macro whose child is in a macro +/// argument. +struct SelectedASTNode { + ast_type_traits::DynTypedNode Node; + SourceSelectionKind SelectionKind; + std::vector<SelectedASTNode> Children; + + SelectedASTNode(const ast_type_traits::DynTypedNode &Node, + SourceSelectionKind SelectionKind) + : Node(Node), SelectionKind(SelectionKind) {} + SelectedASTNode(SelectedASTNode &&) = default; + SelectedASTNode &operator=(SelectedASTNode &&) = default; + + void dump(llvm::raw_ostream &OS = llvm::errs()) const; + + using ReferenceType = std::reference_wrapper<const SelectedASTNode>; +}; + +/// Traverses the given ASTContext and creates a tree of selected AST nodes. +/// +/// \returns None if no nodes are selected in the AST, or a selected AST node +/// that corresponds to the TranslationUnitDecl otherwise. +Optional<SelectedASTNode> findSelectedASTNodes(const ASTContext &Context, + SourceRange SelectionRange); + +/// An AST selection value that corresponds to a selection of a set of +/// statements that belong to one body of code (like one function). +/// +/// For example, the following selection in the source. +/// +/// \code +/// void function() { +/// // selection begin: +/// int x = 0; +/// { +/// // selection end +/// x = 1; +/// } +/// x = 2; +/// } +/// \endcode +/// +/// Would correspond to a code range selection of statements "int x = 0" +/// and the entire compound statement that follows it. +/// +/// A \c CodeRangeASTSelection value stores references to the full +/// \c SelectedASTNode tree and should not outlive it. +class CodeRangeASTSelection { +public: + CodeRangeASTSelection(CodeRangeASTSelection &&) = default; + CodeRangeASTSelection &operator=(CodeRangeASTSelection &&) = default; + + /// Returns the parent hierarchy (top to bottom) for the selected nodes. + ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; } + + /// Returns the number of selected statements. + size_t size() const { + if (!AreChildrenSelected) + return 1; + return SelectedNode.get().Children.size(); + } + + const Stmt *operator[](size_t I) const { + if (!AreChildrenSelected) { + assert(I == 0 && "Invalid index"); + return SelectedNode.get().Node.get<Stmt>(); + } + return SelectedNode.get().Children[I].Node.get<Stmt>(); + } + + /// Returns true when a selected code range is in a function-like body + /// of code, like a function, method or a block. + /// + /// This function can be used to test against selected expressions that are + /// located outside of a function, e.g. global variable initializers, default + /// argument values, or even template arguments. + /// + /// Use the \c getFunctionLikeNearestParent to get the function-like parent + /// declaration. + bool isInFunctionLikeBodyOfCode() const; + + /// Returns the nearest function-like parent declaration or null if such + /// declaration doesn't exist. + const Decl *getFunctionLikeNearestParent() const; + + static Optional<CodeRangeASTSelection> + create(SourceRange SelectionRange, const SelectedASTNode &ASTSelection); + +private: + CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode, + ArrayRef<SelectedASTNode::ReferenceType> Parents, + bool AreChildrenSelected) + : SelectedNode(SelectedNode), Parents(Parents.begin(), Parents.end()), + AreChildrenSelected(AreChildrenSelected) {} + + /// The reference to the selected node (or reference to the selected + /// child nodes). + SelectedASTNode::ReferenceType SelectedNode; + /// The parent hierarchy (top to bottom) for the selected noe. + llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents; + /// True only when the children of the selected node are actually selected. + bool AreChildrenSelected; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H diff --git a/include/clang/Tooling/Refactoring/AtomicChange.h b/include/clang/Tooling/Refactoring/AtomicChange.h index f437c4ba41..8a468a6de8 100644 --- a/include/clang/Tooling/Refactoring/AtomicChange.h +++ b/include/clang/Tooling/Refactoring/AtomicChange.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H #include "clang/Basic/SourceManager.h" +#include "clang/Format/Format.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -45,6 +46,14 @@ public: AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key) : Key(Key), FilePath(FilePath) {} + AtomicChange(AtomicChange &&) = default; + AtomicChange(const AtomicChange &) = default; + + AtomicChange &operator=(AtomicChange &&) = default; + AtomicChange &operator=(const AtomicChange &) = default; + + bool operator==(const AtomicChange &Other) const; + /// \brief Returns the atomic change as a YAML string. std::string toYAMLString(); @@ -70,6 +79,12 @@ public: /// \brief Returns the error message or an empty string if it does not exist. const std::string &getError() const { return Error; } + /// \brief Adds a replacement that replaces the given Range with + /// ReplacementText. + /// \returns An llvm::Error carrying ReplacementError on error. + llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range, + llvm::StringRef ReplacementText); + /// \brief Adds a replacement that replaces range [Loc, Loc+Length) with /// \p Text. /// \returns An llvm::Error carrying ReplacementError on error. @@ -123,6 +138,41 @@ private: tooling::Replacements Replaces; }; +using AtomicChanges = std::vector<AtomicChange>; + +// Defines specs for applying changes. +struct ApplyChangesSpec { + // If true, cleans up redundant/erroneous code around changed code with + // clang-format's cleanup functionality, e.g. redundant commas around deleted + // parameter or empty namespaces introduced by deletions. + bool Cleanup = true; + + format::FormatStyle Style = format::getNoStyle(); + + // Options for selectively formatting changes with clang-format: + // kAll: Format all changed lines. + // kNone: Don't format anything. + // kViolations: Format lines exceeding the `ColumnLimit` in `Style`. + enum FormatOption { kAll, kNone, kViolations }; + + FormatOption Format = kNone; +}; + +/// \brief Applies all AtomicChanges in \p Changes to the \p Code. +/// +/// This completely ignores the file path in each change and replaces them with +/// \p FilePath, i.e. callers are responsible for ensuring all changes are for +/// the same file. +/// +/// \returns The changed code if all changes are applied successfully; +/// otherwise, an llvm::Error carrying llvm::StringError is returned (the Error +/// message can be converted to string with `llvm::toString()` and the +/// error_code should be ignored). +llvm::Expected<std::string> +applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code, + llvm::ArrayRef<AtomicChange> Changes, + const ApplyChangesSpec &Spec); + } // end namespace tooling } // end namespace clang diff --git a/include/clang/Tooling/Refactoring/Extract/Extract.h b/include/clang/Tooling/Refactoring/Extract/Extract.h new file mode 100644 index 0000000000..2fd76d252c --- /dev/null +++ b/include/clang/Tooling/Refactoring/Extract/Extract.h @@ -0,0 +1,53 @@ +//===--- Extract.h - Clang refactoring library ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H +#define LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H + +#include "clang/Tooling/Refactoring/ASTSelection.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" + +namespace clang { +namespace tooling { + +/// An "Extract Function" refactoring moves code into a new function that's +/// then called from the place where the original code was. +class ExtractFunction final : public SourceChangeRefactoringRule { +public: + /// Initiates the extract function refactoring operation. + /// + /// \param Code The selected set of statements. + /// \param DeclName The name name of the extract function. If None, + /// "extracted" is used. + static Expected<ExtractFunction> initiate(RefactoringRuleContext &Context, + CodeRangeASTSelection Code, + Optional<std::string> DeclName); + + static const RefactoringDescriptor &describe(); + +private: + ExtractFunction(CodeRangeASTSelection Code, Optional<std::string> DeclName) + : Code(std::move(Code)), + DeclName(DeclName ? std::move(*DeclName) : "extracted") {} + + Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) override; + + CodeRangeASTSelection Code; + + // FIXME: Account for naming collisions: + // - error when name is specified by user. + // - rename to "extractedN" when name is implicit. + std::string DeclName; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H diff --git a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h new file mode 100644 index 0000000000..8b01a61256 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h @@ -0,0 +1,122 @@ +//===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief A wrapper class around \c RecursiveASTVisitor that visits each +/// occurrences of a named symbol. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H +#define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H + +#include "clang/AST/AST.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Lex/Lexer.h" + +namespace clang { +namespace tooling { + +/// Traverses the AST and visits the occurrence of each named symbol in the +/// given nodes. +template <typename T> +class RecursiveSymbolVisitor + : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> { + using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>; + +public: + RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts) + : SM(SM), LangOpts(LangOpts) {} + + bool visitSymbolOccurrence(const NamedDecl *ND, + ArrayRef<SourceRange> NameRanges) { + return true; + } + + // Declaration visitors: + + bool VisitNamedDecl(const NamedDecl *D) { + return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation()); + } + + bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { + for (const auto *Initializer : CD->inits()) { + // Ignore implicit initializers. + if (!Initializer->isWritten()) + continue; + if (const FieldDecl *FD = Initializer->getMember()) { + if (!visit(FD, Initializer->getSourceLocation(), + Lexer::getLocForEndOfToken(Initializer->getSourceLocation(), + 0, SM, LangOpts))) + return false; + } + } + return true; + } + + // Expression visitors: + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + return visit(Expr->getFoundDecl(), Expr->getLocation()); + } + + bool VisitMemberExpr(const MemberExpr *Expr) { + return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc()); + } + + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + const SourceLocation TypeBeginLoc = Loc.getBeginLoc(); + const SourceLocation TypeEndLoc = + Lexer::getLocForEndOfToken(TypeBeginLoc, 0, SM, LangOpts); + if (const auto *TemplateTypeParm = + dyn_cast<TemplateTypeParmType>(Loc.getType())) { + if (!visit(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc)) + return false; + } + if (const auto *TemplateSpecType = + dyn_cast<TemplateSpecializationType>(Loc.getType())) { + if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(), + TypeBeginLoc, TypeEndLoc)) + return false; + } + return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc); + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + // The base visitor will visit NNSL prefixes, so we should only look at + // the current NNS. + if (NNS) { + const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace(); + if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc())) + return false; + } + return BaseType::TraverseNestedNameSpecifierLoc(NNS); + } + +private: + const SourceManager &SM; + const LangOptions &LangOpts; + + bool visit(const NamedDecl *ND, SourceLocation BeginLoc, + SourceLocation EndLoc) { + return static_cast<T *>(this)->visitSymbolOccurrence( + ND, SourceRange(BeginLoc, EndLoc)); + } + bool visit(const NamedDecl *ND, SourceLocation Loc) { + return visit(ND, Loc, + Loc.getLocWithOffset(ND->getNameAsString().length() - 1)); + } +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H diff --git a/include/clang/Tooling/Refactoring/RefactoringAction.h b/include/clang/Tooling/Refactoring/RefactoringAction.h new file mode 100644 index 0000000000..c4080237f1 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringAction.h @@ -0,0 +1,64 @@ +//===--- RefactoringAction.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" +#include <vector> + +namespace clang { +namespace tooling { + +/// A refactoring action is a class that defines a set of related refactoring +/// action rules. These rules get grouped under a common umbrella - a single +/// clang-refactor subcommand. +/// +/// A subclass of \c RefactoringAction is responsible for creating the set of +/// grouped refactoring action rules that represent one refactoring operation. +/// Although the rules in one action may have a number of different +/// implementations, they should strive to produce a similar result. It should +/// be easy for users to identify which refactoring action produced the result +/// regardless of which refactoring action rule was used. +/// +/// The distinction between actions and rules enables the creation of action +/// that uses very different rules, for example: +/// - local vs global: a refactoring operation like +/// "add missing switch cases" can be applied to one switch when it's +/// selected in an editor, or to all switches in a project when an enum +/// constant is added to an enum. +/// - tool vs editor: some refactoring operation can be initiated in the +/// editor when a declaration is selected, or in a tool when the name of +/// the declaration is passed using a command-line argument. +class RefactoringAction { +public: + virtual ~RefactoringAction() {} + + /// Returns the name of the subcommand that's used by clang-refactor for this + /// action. + virtual StringRef getCommand() const = 0; + + virtual StringRef getDescription() const = 0; + + RefactoringActionRules createActiveActionRules(); + +protected: + /// Returns a set of refactoring actions rules that are defined by this + /// action. + virtual RefactoringActionRules createActionRules() const = 0; +}; + +/// Returns the list of all the available refactoring actions. +std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions(); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/include/clang/Tooling/Refactoring/RefactoringActionRule.h new file mode 100644 index 0000000000..4130e29d8d --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringActionRule.h @@ -0,0 +1,74 @@ +//===--- RefactoringActionRule.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { +namespace tooling { + +class RefactoringOptionVisitor; +class RefactoringResultConsumer; +class RefactoringRuleContext; + +struct RefactoringDescriptor { + /// A unique identifier for the specific refactoring. + StringRef Name; + /// A human readable title for the refactoring. + StringRef Title; + /// A human readable description of what the refactoring does. + StringRef Description; +}; + +/// A common refactoring action rule interface that defines the 'invoke' +/// function that performs the refactoring operation (either fully or +/// partially). +class RefactoringActionRuleBase { +public: + virtual ~RefactoringActionRuleBase() {} + + /// Initiates and performs a specific refactoring action. + /// + /// The specific rule will invoke an appropriate \c handle method on a + /// consumer to propagate the result of the refactoring action. + virtual void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) = 0; + + /// Returns the structure that describes the refactoring. + // static const RefactoringDescriptor &describe() = 0; +}; + +/// A refactoring action rule is a wrapper class around a specific refactoring +/// action rule (SourceChangeRefactoringRule, etc) that, in addition to invoking +/// the action, describes the requirements that determine when the action can be +/// initiated. +class RefactoringActionRule : public RefactoringActionRuleBase { +public: + /// Returns true when the rule has a source selection requirement that has + /// to be fullfilled before refactoring can be performed. + virtual bool hasSelectionRequirement() = 0; + + /// Traverses each refactoring option used by the rule and invokes the + /// \c visit callback in the consumer for each option. + /// + /// Options are visited in the order of use, e.g. if a rule has two + /// requirements that use options, the options from the first requirement + /// are visited before the options in the second requirement. + virtual void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) = 0; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h new file mode 100644 index 0000000000..355a6a55f2 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h @@ -0,0 +1,123 @@ +//===--- RefactoringActionRuleRequirements.h - Clang refactoring library --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" +#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" +#include "clang/Tooling/Refactoring/RefactoringOption.h" +#include "clang/Tooling/Refactoring/RefactoringRuleContext.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +/// A refactoring action rule requirement determines when a refactoring action +/// rule can be invoked. The rule can be invoked only when all of the +/// requirements are satisfied. +/// +/// Subclasses must implement the +/// 'Expected<T> evaluate(RefactoringRuleContext &) const' member function. +/// \c T is used to determine the return type that is passed to the +/// refactoring rule's constructor. +/// For example, the \c SourceRangeSelectionRequirement subclass defines +/// 'Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const' +/// function. When this function returns a non-error value, the resulting +/// source range is passed to the specific refactoring action rule +/// constructor (provided all other requirements are satisfied). +class RefactoringActionRuleRequirement { + // Expected<T> evaluate(RefactoringRuleContext &Context) const; +}; + +/// A base class for any requirement that expects some part of the source to be +/// selected in an editor (or the refactoring tool with the -selection option). +class SourceSelectionRequirement : public RefactoringActionRuleRequirement {}; + +/// A selection requirement that is satisfied when any portion of the source +/// text is selected. +class SourceRangeSelectionRequirement : public SourceSelectionRequirement { +public: + Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const { + if (Context.getSelectionRange().isValid()) + return Context.getSelectionRange(); + return Context.createDiagnosticError(diag::err_refactor_no_selection); + } +}; + +/// An AST selection requirement is satisfied when any portion of the AST +/// overlaps with the selection range. +/// +/// The requirement will be evaluated only once during the initiation and +/// search of matching refactoring action rules. +class ASTSelectionRequirement : public SourceRangeSelectionRequirement { +public: + Expected<SelectedASTNode> evaluate(RefactoringRuleContext &Context) const; +}; + +/// A selection requirement that is satisfied when the selection range overlaps +/// with a number of neighbouring statements in the AST. The statemenst must be +/// contained in declaration like a function. The selection range must be a +/// non-empty source selection (i.e. cursors won't be accepted). +/// +/// The requirement will be evaluated only once during the initiation and search +/// of matching refactoring action rules. +/// +/// \see CodeRangeASTSelection +class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement { +public: + Expected<CodeRangeASTSelection> + evaluate(RefactoringRuleContext &Context) const; +}; + +/// A base class for any requirement that requires some refactoring options. +class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement { +public: + virtual ~RefactoringOptionsRequirement() {} + + /// Returns the set of refactoring options that are used when evaluating this + /// requirement. + virtual ArrayRef<std::shared_ptr<RefactoringOption>> + getRefactoringOptions() const = 0; +}; + +/// A requirement that evaluates to the value of the given \c OptionType when +/// the \c OptionType is a required option. When the \c OptionType is an +/// optional option, the requirement will evaluate to \c None if the option is +/// not specified or to an appropriate value otherwise. +template <typename OptionType> +class OptionRequirement : public RefactoringOptionsRequirement { +public: + OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {} + + ArrayRef<std::shared_ptr<RefactoringOption>> + getRefactoringOptions() const final override { + return Opt; + } + + Expected<typename OptionType::ValueType> + evaluate(RefactoringRuleContext &) const { + return static_cast<OptionType *>(Opt.get())->getValue(); + } + +private: + /// The partially-owned option. + /// + /// The ownership of the option is shared among the different requirements + /// because the same option can be used by multiple rules in one refactoring + /// action. + std::shared_ptr<RefactoringOption> Opt; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRules.h b/include/clang/Tooling/Refactoring/RefactoringActionRules.h new file mode 100644 index 0000000000..33206d9a5d --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringActionRules.h @@ -0,0 +1,94 @@ +//===--- RefactoringActionRules.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H + +#include "clang/Tooling/Refactoring/RefactoringActionRule.h" +#include "clang/Tooling/Refactoring/RefactoringActionRulesInternal.h" + +namespace clang { +namespace tooling { + +/// Creates a new refactoring action rule that constructs and invokes the +/// \c RuleType rule when all of the requirements are satisfied. +/// +/// This function takes in a list of values whose type derives from +/// \c RefactoringActionRuleRequirement. These values describe the initiation +/// requirements that have to be satisfied by the refactoring engine before +/// the provided action rule can be constructed and invoked. The engine +/// verifies that the requirements are satisfied by evaluating them (using the +/// 'evaluate' member function) and checking that the results don't contain +/// any errors. Once all requirements are satisfied, the provided refactoring +/// rule is constructed by passing in the values returned by the requirements' +/// evaluate functions as arguments to the constructor. The rule is then invoked +/// immediately after construction. +/// +/// The separation of requirements, their evaluation and the invocation of the +/// refactoring action rule allows the refactoring clients to: +/// - Disable refactoring action rules whose requirements are not supported. +/// - Gather the set of options and define a command-line / visual interface +/// that allows users to input these options without ever invoking the +/// action. +template <typename RuleType, typename... RequirementTypes> +std::unique_ptr<RefactoringActionRule> +createRefactoringActionRule(const RequirementTypes &... Requirements); + +/// A set of refactoring action rules that should have unique initiation +/// requirements. +using RefactoringActionRules = + std::vector<std::unique_ptr<RefactoringActionRule>>; + +/// A type of refactoring action rule that produces source replacements in the +/// form of atomic changes. +/// +/// This action rule is typically used for local refactorings that replace +/// source in a single AST unit. +class SourceChangeRefactoringRule : public RefactoringActionRuleBase { +public: + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) final override { + Expected<AtomicChanges> Changes = createSourceReplacements(Context); + if (!Changes) + Consumer.handleError(Changes.takeError()); + else + Consumer.handle(std::move(*Changes)); + } + +private: + virtual Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) = 0; +}; + +/// A type of refactoring action rule that finds a set of symbol occurrences +/// that reference a particular symbol. +/// +/// This action rule is typically used for an interactive rename that allows +/// users to specify the new name and the set of selected occurrences during +/// the refactoring. +class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase { +public: + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) final override { + Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context); + if (!Occurrences) + Consumer.handleError(Occurrences.takeError()); + else + Consumer.handle(std::move(*Occurrences)); + } + +private: + virtual Expected<SymbolOccurrences> + findSymbolOccurrences(RefactoringRuleContext &Context) = 0; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h new file mode 100644 index 0000000000..75b6c8f70d --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h @@ -0,0 +1,158 @@ +//===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRule.h" +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" +#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" +#include "clang/Tooling/Refactoring/RefactoringRuleContext.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { +namespace internal { + +inline llvm::Error findError() { return llvm::Error::success(); } + +inline void ignoreError() {} + +template <typename FirstT, typename... RestT> +void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) { + if (!First) + llvm::consumeError(First.takeError()); + ignoreError(Rest...); +} + +/// Scans the tuple and returns a valid \c Error if any of the values are +/// invalid. +template <typename FirstT, typename... RestT> +llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) { + if (!First) { + ignoreError(Rest...); + return First.takeError(); + } + return findError(Rest...); +} + +template <typename RuleType, typename... RequirementTypes, size_t... Is> +void invokeRuleAfterValidatingRequirements( + RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context, + const std::tuple<RequirementTypes...> &Requirements, + llvm::index_sequence<Is...>) { + // Check if the requirements we're interested in can be evaluated. + auto Values = + std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...); + auto Err = findError(std::get<Is>(Values)...); + if (Err) + return Consumer.handleError(std::move(Err)); + // Construct the target action rule by extracting the evaluated + // requirements from Expected<> wrappers and then run it. + auto Rule = + RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...); + if (!Rule) + return Consumer.handleError(Rule.takeError()); + Rule->invoke(Consumer, Context); +} + +inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {} + +/// Scans the list of requirements in a rule and visits all the refactoring +/// options that are used by all the requirements. +template <typename FirstT, typename... RestT> +void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor, + const FirstT &First, const RestT &... Rest) { + struct OptionGatherer { + RefactoringOptionVisitor &Visitor; + + void operator()(const RefactoringOptionsRequirement &Requirement) { + for (const auto &Option : Requirement.getRefactoringOptions()) + Option->passToVisitor(Visitor); + } + void operator()(const RefactoringActionRuleRequirement &) {} + }; + (OptionGatherer{Visitor})(First); + return visitRefactoringOptionsImpl(Visitor, Rest...); +} + +template <typename... RequirementTypes, size_t... Is> +void visitRefactoringOptions( + RefactoringOptionVisitor &Visitor, + const std::tuple<RequirementTypes...> &Requirements, + llvm::index_sequence<Is...>) { + visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...); +} + +/// A type trait that returns true when the given type list has at least one +/// type whose base is the given base type. +template <typename Base, typename First, typename... Rest> +struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value || + HasBaseOf<Base, Rest...>::value, + std::true_type, std::false_type>::type {}; + +template <typename Base, typename T> +struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {}; + +/// A type trait that returns true when the given type list contains types that +/// derive from Base. +template <typename Base, typename First, typename... Rest> +struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value && + AreBaseOf<Base, Rest...>::value, + std::true_type, std::false_type>::type {}; + +template <typename Base, typename T> +struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {}; + +} // end namespace internal + +template <typename RuleType, typename... RequirementTypes> +std::unique_ptr<RefactoringActionRule> +createRefactoringActionRule(const RequirementTypes &... Requirements) { + static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value, + "Expected a refactoring action rule type"); + static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement, + RequirementTypes...>::value, + "Expected a list of refactoring action rules"); + + class Rule final : public RefactoringActionRule { + public: + Rule(std::tuple<RequirementTypes...> Requirements) + : Requirements(Requirements) {} + + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) override { + internal::invokeRuleAfterValidatingRequirements<RuleType>( + Consumer, Context, Requirements, + llvm::index_sequence_for<RequirementTypes...>()); + } + + bool hasSelectionRequirement() override { + return internal::HasBaseOf<SourceSelectionRequirement, + RequirementTypes...>::value; + } + + void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override { + internal::visitRefactoringOptions( + Visitor, Requirements, + llvm::index_sequence_for<RequirementTypes...>()); + } + private: + std::tuple<RequirementTypes...> Requirements; + }; + + return llvm::make_unique<Rule>(std::make_tuple(Requirements...)); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H diff --git a/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h new file mode 100644 index 0000000000..6767dc708e --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h @@ -0,0 +1,30 @@ +//===--- RefactoringDiagnostic.h - ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H +#define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" + +namespace clang { +namespace diag { +enum { +#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY) \ + ENUM, +#define REFACTORINGSTART +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +#undef DIAG + NUM_BUILTIN_REFACTORING_DIAGNOSTICS +}; +} // end namespace diag +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H diff --git a/include/clang/Tooling/Refactoring/RefactoringOption.h b/include/clang/Tooling/Refactoring/RefactoringOption.h new file mode 100644 index 0000000000..5011223cce --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringOption.h @@ -0,0 +1,64 @@ +//===--- RefactoringOption.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H + +#include "clang/Basic/LLVM.h" +#include <memory> +#include <type_traits> + +namespace clang { +namespace tooling { + +class RefactoringOptionVisitor; + +/// A refactoring option is an interface that describes a value that +/// has an impact on the outcome of a refactoring. +/// +/// Refactoring options can be specified using command-line arguments when +/// the clang-refactor tool is used. +class RefactoringOption { +public: + virtual ~RefactoringOption() {} + + /// Returns the name of the refactoring option. + /// + /// Each refactoring option must have a unique name. + virtual StringRef getName() const = 0; + + virtual StringRef getDescription() const = 0; + + /// True when this option must be specified before invoking the refactoring + /// action. + virtual bool isRequired() const = 0; + + /// Invokes the \c visit method in the option consumer that's appropriate + /// for the option's value type. + /// + /// For example, if the option stores a string value, this method will + /// invoke the \c visit method with a reference to an std::string value. + virtual void passToVisitor(RefactoringOptionVisitor &Visitor) = 0; +}; + +/// Constructs a refactoring option of the given type. +/// +/// The ownership of options is shared among requirements that use it because +/// one option can be used by multiple rules in a refactoring action. +template <typename OptionType> +std::shared_ptr<OptionType> createRefactoringOption() { + static_assert(std::is_base_of<RefactoringOption, OptionType>::value, + "invalid option type"); + return std::make_shared<OptionType>(); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H diff --git a/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h new file mode 100644 index 0000000000..aea8fa5493 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h @@ -0,0 +1,62 @@ +//===--- RefactoringOptionVisitor.h - Clang refactoring library -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H + +#include "clang/Basic/LLVM.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +class RefactoringOption; + +/// An interface that declares functions that handle different refactoring +/// option types. +/// +/// A valid refactoring option type must have a corresponding \c visit +/// declaration in this interface. +class RefactoringOptionVisitor { +public: + virtual ~RefactoringOptionVisitor() {} + + virtual void visit(const RefactoringOption &Opt, + Optional<std::string> &Value) = 0; +}; + +namespace traits { +namespace internal { + +template <typename T> struct HasHandle { +private: + template <typename ClassT> + static auto check(ClassT *) -> typename std::is_same< + decltype(std::declval<RefactoringOptionVisitor>().visit( + std::declval<RefactoringOption>(), *std::declval<Optional<T> *>())), + void>::type; + + template <typename> static std::false_type check(...); + +public: + using Type = decltype(check<RefactoringOptionVisitor>(nullptr)); +}; + +} // end namespace internal + +/// A type trait that returns true iff the given type is a type that can be +/// stored in a refactoring option. +template <typename T> +struct IsValidOptionType : internal::HasHandle<T>::Type {}; + +} // end namespace traits +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H diff --git a/include/clang/Tooling/Refactoring/RefactoringOptions.h b/include/clang/Tooling/Refactoring/RefactoringOptions.h new file mode 100644 index 0000000000..e45c0a09fd --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringOptions.h @@ -0,0 +1,58 @@ +//===--- RefactoringOptions.h - Clang refactoring library -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" +#include "clang/Tooling/Refactoring/RefactoringOption.h" +#include "clang/Tooling/Refactoring/RefactoringOptionVisitor.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +/// A refactoring option that stores a value of type \c T. +template <typename T, typename = typename std::enable_if< + traits::IsValidOptionType<T>::value>::type> +class OptionalRefactoringOption : public RefactoringOption { +public: + void passToVisitor(RefactoringOptionVisitor &Visitor) final override { + Visitor.visit(*this, Value); + } + + bool isRequired() const override { return false; } + + using ValueType = Optional<T>; + + const ValueType &getValue() const { return Value; } + +protected: + Optional<T> Value; +}; + +/// A required refactoring option that stores a value of type \c T. +template <typename T, typename = typename std::enable_if< + traits::IsValidOptionType<T>::value>::type> +class RequiredRefactoringOption : public OptionalRefactoringOption<T> { +public: + using ValueType = T; + + const ValueType &getValue() const { + return *OptionalRefactoringOption<T>::Value; + } + bool isRequired() const final override { return true; } +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H diff --git a/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h new file mode 100644 index 0000000000..fe7738e734 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h @@ -0,0 +1,52 @@ +//===--- RefactoringResultConsumer.h - Clang refactoring library ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace tooling { + +/// An abstract interface that consumes the various refactoring results that can +/// be produced by refactoring actions. +/// +/// A valid refactoring result must be handled by a \c handle method. +class RefactoringResultConsumer { +public: + virtual ~RefactoringResultConsumer() {} + + /// Handles an initation or an invication error. An initiation error typically + /// has a \c DiagnosticError payload that describes why initation failed. + virtual void handleError(llvm::Error Err) = 0; + + /// Handles the source replacements that are produced by a refactoring action. + virtual void handle(AtomicChanges SourceReplacements) { + defaultResultHandler(); + } + + /// Handles the symbol occurrences that are found by an interactive + /// refactoring action. + virtual void handle(SymbolOccurrences Occurrences) { defaultResultHandler(); } + +private: + void defaultResultHandler() { + handleError(llvm::make_error<llvm::StringError>( + "unsupported refactoring result", llvm::inconvertibleErrorCode())); + } +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H diff --git a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h new file mode 100644 index 0000000000..882ab824b6 --- /dev/null +++ b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h @@ -0,0 +1,90 @@ +//===--- RefactoringRuleContext.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H + +#include "clang/Basic/DiagnosticError.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" + +namespace clang { + +class ASTContext; + +namespace tooling { + +/// The refactoring rule context stores all of the inputs that might be needed +/// by a refactoring action rule. It can create the specialized +/// \c ASTRefactoringOperation or \c PreprocessorRefactoringOperation values +/// that can be used by the refactoring action rules. +/// +/// The following inputs are stored by the operation: +/// +/// - SourceManager: a reference to a valid source manager. +/// +/// - SelectionRange: an optional source selection ranges that can be used +/// to represent a selection in an editor. +class RefactoringRuleContext { +public: + RefactoringRuleContext(const SourceManager &SM) : SM(SM) {} + + const SourceManager &getSources() const { return SM; } + + /// Returns the current source selection range as set by the + /// refactoring engine. Can be invalid. + SourceRange getSelectionRange() const { return SelectionRange; } + + void setSelectionRange(SourceRange R) { SelectionRange = R; } + + bool hasASTContext() const { return AST; } + + ASTContext &getASTContext() const { + assert(AST && "no AST!"); + return *AST; + } + + void setASTContext(ASTContext &Context) { AST = &Context; } + + /// Creates an llvm::Error value that contains a diagnostic. + /// + /// The errors should not outlive the context. + llvm::Error createDiagnosticError(SourceLocation Loc, unsigned DiagID) { + return DiagnosticError::create(Loc, PartialDiagnostic(DiagID, DiagStorage)); + } + + llvm::Error createDiagnosticError(unsigned DiagID) { + return createDiagnosticError(SourceLocation(), DiagID); + } + + void setASTSelection(std::unique_ptr<SelectedASTNode> Node) { + ASTNodeSelection = std::move(Node); + } + +private: + /// The source manager for the translation unit / file on which a refactoring + /// action might operate on. + const SourceManager &SM; + /// An optional source selection range that's commonly used to represent + /// a selection in an editor. + SourceRange SelectionRange; + /// An optional AST for the translation unit on which a refactoring action + /// might operate on. + ASTContext *AST = nullptr; + /// The allocator for diagnostics. + PartialDiagnostic::StorageAllocator DiagStorage; + + // FIXME: Remove when memoized. + std::unique_ptr<SelectedASTNode> ASTNodeSelection; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H diff --git a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h new file mode 100644 index 0000000000..d9ed7d3a1f --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h @@ -0,0 +1,100 @@ +//===--- RenamingAction.h - Clang refactoring library ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to rename every symbol at a point. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H + +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" +#include "clang/Tooling/Refactoring/RefactoringOptions.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/Support/Error.h" + +namespace clang { +class ASTConsumer; +class CompilerInstance; + +namespace tooling { + +class RenamingAction { +public: + RenamingAction(const std::vector<std::string> &NewNames, + const std::vector<std::string> &PrevNames, + const std::vector<std::vector<std::string>> &USRList, + std::map<std::string, tooling::Replacements> &FileToReplaces, + bool PrintLocations = false) + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} + + std::unique_ptr<ASTConsumer> newASTConsumer(); + +private: + const std::vector<std::string> &NewNames, &PrevNames; + const std::vector<std::vector<std::string>> &USRList; + std::map<std::string, tooling::Replacements> &FileToReplaces; + bool PrintLocations; +}; + +class RenameOccurrences final : public SourceChangeRefactoringRule { +public: + static Expected<RenameOccurrences> initiate(RefactoringRuleContext &Context, + SourceRange SelectionRange, + std::string NewName); + + static const RefactoringDescriptor &describe(); + +private: + RenameOccurrences(const NamedDecl *ND, std::string NewName) + : ND(ND), NewName(std::move(NewName)) {} + + Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) override; + + const NamedDecl *ND; + std::string NewName; +}; + +/// Returns source replacements that correspond to the rename of the given +/// symbol occurrences. +llvm::Expected<std::vector<AtomicChange>> +createRenameReplacements(const SymbolOccurrences &Occurrences, + const SourceManager &SM, const SymbolName &NewName); + +/// Rename all symbols identified by the given USRs. +class QualifiedRenamingAction { +public: + QualifiedRenamingAction( + const std::vector<std::string> &NewNames, + const std::vector<std::vector<std::string>> &USRList, + std::map<std::string, tooling::Replacements> &FileToReplaces) + : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {} + + std::unique_ptr<ASTConsumer> newASTConsumer(); + +private: + /// New symbol names. + const std::vector<std::string> &NewNames; + + /// A list of USRs. Each element represents USRs of a symbol being renamed. + const std::vector<std::vector<std::string>> &USRList; + + /// A file path to replacements map. + std::map<std::string, tooling::Replacements> &FileToReplaces; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolName.h b/include/clang/Tooling/Refactoring/Rename/SymbolName.h new file mode 100644 index 0000000000..e69d2908b5 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/SymbolName.h @@ -0,0 +1,49 @@ +//===--- SymbolName.h - Clang refactoring library -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace tooling { + +/// A name of a symbol. +/// +/// Symbol's name can be composed of multiple strings. For example, Objective-C +/// methods can contain multiple argument lables: +/// +/// \code +/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y; +/// // ^~ string 0 ~~~~~ ^~ string 1 ~~~~~ +/// \endcode +class SymbolName { +public: + explicit SymbolName(StringRef Name) { + // While empty symbol names are valid (Objective-C selectors can have empty + // name pieces), occurrences Objective-C selectors are created using an + // array of strings instead of just one string. + assert(!Name.empty() && "Invalid symbol name!"); + this->Name.push_back(Name.str()); + } + + ArrayRef<std::string> getNamePieces() const { return Name; } + +private: + llvm::SmallVector<std::string, 1> Name; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h new file mode 100644 index 0000000000..0f85301197 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h @@ -0,0 +1,91 @@ +//===--- SymbolOccurrences.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { +namespace tooling { + +class SymbolName; + +/// An occurrence of a symbol in the source. +/// +/// Occurrences can have difference kinds, that describe whether this occurrence +/// is an exact semantic match, or whether this is a weaker textual match that's +/// not guaranteed to represent the exact declaration. +/// +/// A single occurrence of a symbol can span more than one source range. For +/// example, Objective-C selectors can contain multiple argument labels: +/// +/// \code +/// [object selectorPiece1: ... selectorPiece2: ...]; +/// // ^~~ range 0 ~~ ^~~ range 1 ~~ +/// \endcode +/// +/// We have to replace the text in both range 0 and range 1 when renaming the +/// Objective-C method 'selectorPiece1:selectorPiece2'. +class SymbolOccurrence { +public: + enum OccurrenceKind { + /// This occurrence is an exact match and can be renamed automatically. + /// + /// Note: + /// Symbol occurrences in macro arguments that expand to different + /// declarations get marked as exact matches, and thus the renaming engine + /// will rename them e.g.: + /// + /// \code + /// #define MACRO(x) x + ns::x + /// int foo(int var) { + /// return MACRO(var); // var is renamed automatically here when + /// // either var or ns::var is renamed. + /// }; + /// \endcode + /// + /// The user will have to fix their code manually after performing such a + /// rename. + /// FIXME: The rename verifier should notify user about this issue. + MatchingSymbol + }; + + SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, + ArrayRef<SourceLocation> Locations); + + SymbolOccurrence(SymbolOccurrence &&) = default; + SymbolOccurrence &operator=(SymbolOccurrence &&) = default; + + OccurrenceKind getKind() const { return Kind; } + + ArrayRef<SourceRange> getNameRanges() const { + if (MultipleRanges) { + return llvm::makeArrayRef(MultipleRanges.get(), + RangeOrNumRanges.getBegin().getRawEncoding()); + } + return RangeOrNumRanges; + } + +private: + OccurrenceKind Kind; + std::unique_ptr<SourceRange[]> MultipleRanges; + SourceRange RangeOrNumRanges; +}; + +using SymbolOccurrences = std::vector<SymbolOccurrence>; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H diff --git a/include/clang/Tooling/Refactoring/Rename/USRFinder.h b/include/clang/Tooling/Refactoring/Rename/USRFinder.h new file mode 100644 index 0000000000..b74a5d7f70 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/USRFinder.h @@ -0,0 +1,50 @@ +//===--- USRFinder.h - Clang refactoring library --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Methods for determining the USR of a symbol at a location in source +/// code. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H + +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include <string> +#include <vector> + +namespace clang { + +class ASTContext; +class Decl; +class SourceLocation; +class NamedDecl; + +namespace tooling { + +// Given an AST context and a point, returns a NamedDecl identifying the symbol +// at the point. Returns null if nothing is found at the point. +const NamedDecl *getNamedDeclAt(const ASTContext &Context, + const SourceLocation Point); + +// Given an AST context and a fully qualified name, returns a NamedDecl +// identifying the symbol with a matching name. Returns null if nothing is +// found for the name. +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name); + +// Converts a Decl into a USR. +std::string getUSRForDecl(const Decl *Decl); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H diff --git a/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h new file mode 100644 index 0000000000..f1c5ae60f8 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h @@ -0,0 +1,68 @@ +//===--- USRFindingAction.h - Clang refactoring library -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to find all relevant USRs at a point. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" + +#include <string> +#include <vector> + +namespace clang { +class ASTConsumer; +class ASTContext; +class CompilerInstance; +class NamedDecl; + +namespace tooling { + +/// Returns the canonical declaration that best represents a symbol that can be +/// renamed. +/// +/// The following canonicalization rules are currently used: +/// +/// - A constructor is canonicalized to its class. +/// - A destructor is canonicalized to its class. +const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl); + +/// Returns the set of USRs that correspond to the given declaration. +std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND, + ASTContext &Context); + +struct USRFindingAction { + USRFindingAction(ArrayRef<unsigned> SymbolOffsets, + ArrayRef<std::string> QualifiedNames, bool Force) + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames), + ErrorOccurred(false), Force(Force) {} + std::unique_ptr<ASTConsumer> newASTConsumer(); + + ArrayRef<std::string> getUSRSpellings() { return SpellingNames; } + ArrayRef<std::vector<std::string>> getUSRList() { return USRList; } + bool errorOccurred() { return ErrorOccurred; } + +private: + std::vector<unsigned> SymbolOffsets; + std::vector<std::string> QualifiedNames; + std::vector<std::string> SpellingNames; + std::vector<std::vector<std::string>> USRList; + bool ErrorOccurred; + bool Force; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H diff --git a/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h new file mode 100644 index 0000000000..801a8ad9e9 --- /dev/null +++ b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h @@ -0,0 +1,53 @@ +//===--- USRLocFinder.h - Clang refactoring library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides functionality for finding all instances of a USR in a given +/// AST. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H + +#include "clang/AST/AST.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// Create atomic changes for renaming all symbol references which are +/// identified by the USRs set to a given new name. +/// +/// \param USRs The set containing USRs of a particular old symbol. +/// \param NewName The new name to replace old symbol name. +/// \param TranslationUnitDecl The translation unit declaration. +/// +/// \return Atomic changes for renaming. +std::vector<tooling::AtomicChange> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, + llvm::StringRef NewName, Decl *TranslationUnitDecl); + +/// Finds the symbol occurrences for the symbol that's identified by the given +/// USR set. +/// +/// \return SymbolOccurrences that can be converted to AtomicChanges when +/// renaming. +SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, + StringRef PrevName, Decl *Decl); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H diff --git a/include/clang/Tooling/RefactoringCallbacks.h b/include/clang/Tooling/RefactoringCallbacks.h index 6ef9ea11f0..9862951149 100644 --- a/include/clang/Tooling/RefactoringCallbacks.h +++ b/include/clang/Tooling/RefactoringCallbacks.h @@ -47,6 +47,33 @@ protected: Replacements Replace; }; +/// \brief Adaptor between \c ast_matchers::MatchFinder and \c +/// tooling::RefactoringTool. +/// +/// Runs AST matchers and stores the \c tooling::Replacements in a map. +class ASTMatchRefactorer { +public: + explicit ASTMatchRefactorer( + std::map<std::string, Replacements> &FileToReplaces); + + template <typename T> + void addMatcher(const T &Matcher, RefactoringCallback *Callback) { + MatchFinder.addMatcher(Matcher, Callback); + Callbacks.push_back(Callback); + } + + void addDynamicMatcher(const ast_matchers::internal::DynTypedMatcher &Matcher, + RefactoringCallback *Callback); + + std::unique_ptr<ASTConsumer> newASTConsumer(); + +private: + friend class RefactoringASTConsumer; + std::vector<RefactoringCallback *> Callbacks; + ast_matchers::MatchFinder MatchFinder; + std::map<std::string, Replacements> &FileToReplaces; +}; + /// \brief Replace the text of the statement bound to \c FromId with the text in /// \c ToText. class ReplaceStmtWithText : public RefactoringCallback { @@ -59,6 +86,29 @@ private: std::string ToText; }; +/// \brief Replace the text of an AST node bound to \c FromId with the result of +/// evaluating the template in \c ToTemplate. +/// +/// Expressions of the form ${NodeName} in \c ToTemplate will be +/// replaced by the text of the node bound to ${NodeName}. The string +/// "$$" will be replaced by "$". +class ReplaceNodeWithTemplate : public RefactoringCallback { +public: + static llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>> + create(StringRef FromId, StringRef ToTemplate); + void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + struct TemplateElement { + enum { Literal, Identifier } Type; + std::string Value; + }; + ReplaceNodeWithTemplate(llvm::StringRef FromId, + std::vector<TemplateElement> Template); + std::string FromId; + std::vector<TemplateElement> Template; +}; + /// \brief Replace the text of the statement bound to \c FromId with the text of /// the statement bound to \c ToId. class ReplaceStmtWithStmt : public RefactoringCallback { diff --git a/include/clang/Tooling/StandaloneExecution.h b/include/clang/Tooling/StandaloneExecution.h new file mode 100644 index 0000000000..f5f32d737a --- /dev/null +++ b/include/clang/Tooling/StandaloneExecution.h @@ -0,0 +1,97 @@ +//===--- StandaloneExecution.h - Standalone execution. -*- C++ ----------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines standalone execution of clang tools. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H +#define LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H + +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Tooling/Execution.h" + +namespace clang { +namespace tooling { + +/// \brief A standalone executor that runs FrontendActions on a given set of +/// TUs in sequence. +/// +/// By default, this executor uses the following arguments adjusters (as defined +/// in `clang/Tooling/ArgumentsAdjusters.h`): +/// - `getClangStripOutputAdjuster()` +/// - `getClangSyntaxOnlyAdjuster()` +/// - `getClangStripDependencyFileAdjuster()` +class StandaloneToolExecutor : public ToolExecutor { +public: + static const char *ExecutorName; + + /// \brief Init with \p CompilationDatabase and the paths of all files to be + /// proccessed. + StandaloneToolExecutor( + const CompilationDatabase &Compilations, + llvm::ArrayRef<std::string> SourcePaths, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + /// \brief Init with \p CommonOptionsParser. This is expected to be used by + /// `createExecutorFromCommandLineArgs` based on commandline options. + /// + /// The executor takes ownership of \p Options. + StandaloneToolExecutor( + CommonOptionsParser Options, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + StringRef getExecutorName() const override { return ExecutorName; } + + using ToolExecutor::execute; + + llvm::Error + execute(llvm::ArrayRef< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions) override; + + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { + Tool.setDiagnosticConsumer(DiagConsumer); + } + + ExecutionContext *getExecutionContext() override { return &Context; }; + + ToolResults *getToolResults() override { return &Results; } + + llvm::ArrayRef<std::string> getSourcePaths() const { + return Tool.getSourcePaths(); + } + + void mapVirtualFile(StringRef FilePath, StringRef Content) override { + Tool.mapVirtualFile(FilePath, Content); + } + + /// \brief Returns the file manager used in the tool. + /// + /// The file manager is shared between all translation units. + FileManager &getFiles() { return Tool.getFiles(); } + +private: + // Used to store the parser when the executor is initialized with parser. + llvm::Optional<CommonOptionsParser> OptionsParser; + // FIXME: The standalone executor is currently just a wrapper of `ClangTool`. + // Merge `ClangTool` implementation into the this. + ClangTool Tool; + ExecutionContext Context; + InMemoryToolResults Results; + ArgumentsAdjuster ArgsAdjuster; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H diff --git a/include/clang/Tooling/ToolExecutorPluginRegistry.h b/include/clang/Tooling/ToolExecutorPluginRegistry.h new file mode 100644 index 0000000000..11ba89546e --- /dev/null +++ b/include/clang/Tooling/ToolExecutorPluginRegistry.h @@ -0,0 +1,24 @@ +//===--- ToolExecutorPluginRegistry.h - -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H +#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H + +#include "clang/Tooling/Execution.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +typedef llvm::Registry<ToolExecutorPlugin> ToolExecutorPluginRegistry; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index 10e26ac25d..e64be07d9a 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -31,12 +31,12 @@ #define LLVM_CLANG_TOOLING_TOOLING_H #include "clang/AST/ASTConsumer.h" -#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Util.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -116,7 +116,7 @@ public: /// \brief Called before a source file is processed by a FrontEndAction. /// \see clang::FrontendAction::BeginSourceFileAction - virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) { + virtual bool handleBeginSource(CompilerInstance &CI) { return true; } @@ -202,12 +202,15 @@ buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc", /// \param PCHContainerOps The PCHContainerOperations for loading and creating /// clang modules. /// +/// \param Adjuster A function to filter the command line arguments as specified. +/// /// \return The resulting AST or null if an error occurred. std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( const Twine &Code, const std::vector<std::string> &Args, const Twine &FileName = "input.cc", const Twine &ToolName = "clang-tool", std::shared_ptr<PCHContainerOperations> PCHContainerOps = - std::make_shared<PCHContainerOperations>()); + std::make_shared<PCHContainerOperations>(), + ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster()); /// \brief Utility to run a FrontendAction in a single clang invocation. class ToolInvocation { @@ -334,7 +337,9 @@ class ClangTool { /// The file manager is shared between all translation units. FileManager &getFiles() { return *Files; } - private: + llvm::ArrayRef<std::string> getSourcePaths() const { return SourcePaths; } + +private: const CompilationDatabase &Compilations; std::vector<std::string> SourcePaths; std::shared_ptr<PCHContainerOperations> PCHContainerOps; @@ -388,12 +393,11 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory( } protected: - bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) override { - if (!clang::ASTFrontendAction::BeginSourceFileAction(CI, Filename)) + bool BeginSourceFileAction(CompilerInstance &CI) override { + if (!clang::ASTFrontendAction::BeginSourceFileAction(CI)) return false; if (Callbacks) - return Callbacks->handleBeginSource(CI, Filename); + return Callbacks->handleBeginSource(CI); return true; } void EndSourceFileAction() override { diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap index 3b42381100..41cf73d910 100644 --- a/include/clang/module.modulemap +++ b/include/clang/module.modulemap @@ -33,6 +33,7 @@ module Clang_Basic { textual header "Basic/BuiltinsLe64.def" textual header "Basic/BuiltinsMips.def" textual header "Basic/BuiltinsNEON.def" + textual header "Basic/BuiltinsNios2.def" textual header "Basic/BuiltinsNVPTX.def" textual header "Basic/BuiltinsPPC.def" textual header "Basic/BuiltinsSystemZ.def" @@ -68,9 +69,9 @@ module Clang_Diagnostics { module Frontend { header "Frontend/FrontendDiagnostic.h" export * } module Lex { header "Lex/LexDiagnostic.h" export * } module Parse { header "Parse/ParseDiagnostic.h" export * } - // FIXME: This breaks the build of Clang_Sema, for unknown reasons. - //module Sema { header "Sema/SemaDiagnostic.h" export * } + module Sema { header "Sema/SemaDiagnostic.h" export * } module Serialization { header "Serialization/SerializationDiagnostic.h" export * } + module Refactoring { header "Tooling/Refactoring/RefactoringDiagnostic.h" export * } } module Clang_Driver { @@ -89,7 +90,6 @@ module Clang_Frontend { requires cplusplus umbrella "Frontend" - textual header "Frontend/CodeGenOptions.def" textual header "Frontend/LangStandards.def" module * { export * } @@ -98,11 +98,20 @@ module Clang_Frontend { exclude header "Frontend/PCHContainerOperations.h" } +// Used in clangBasic +module Clang_Frontend_CodeGenOptions { + requires cplusplus + header "Frontend/CodeGenOptions.h" + textual header "Frontend/CodeGenOptions.def" + export * +} + module Clang_FrontendTool { requires cplusplus umbrella "FrontendTool" module * { export * } } module Clang_Index { requires cplusplus umbrella "Index" module * { export * } } module Clang_Lex { requires cplusplus umbrella "Lex" module * { export * } } module Clang_Parse { requires cplusplus umbrella "Parse" module * { export * } } -module Clang_Rewrite { requires cplusplus umbrella "Rewrite" module * { export * } } +module Clang_Rewrite { requires cplusplus umbrella "Rewrite/Core" module * { export * } } +module Clang_RewriteFrontend { requires cplusplus umbrella "Rewrite/Frontend" module * { export * } } module Clang_Sema { requires cplusplus umbrella "Sema" module * { export * } } module Clang_Serialization { requires cplusplus umbrella "Serialization" module * { export * } } @@ -132,9 +141,14 @@ module Clang_StaticAnalyzer_Frontend { module Clang_Tooling { requires cplusplus umbrella "Tooling" module * { export * } - // FIXME: Exclude this header to avoid pulling all of the AST matchers + // FIXME: Exclude these headers to avoid pulling all of the AST matchers // library into clang-format. Due to inline key functions in the headers, // importing the AST matchers library gives a link dependency on the AST // matchers (and thus the AST), which clang-format should not have. exclude header "Tooling/RefactoringCallbacks.h" } + +module Clang_ToolingCore { + requires cplusplus + umbrella "Tooling/Core" module * { export * } +} |