diff options
440 files changed, 17512 insertions, 3076 deletions
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index ab7bd872ca28..031daeeaa123 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -275,6 +275,9 @@ the configuration (without a prefix: ``Auto``). * ``BS_Linux`` (in configuration: ``Linux``) Like ``Attach``, but break before braces on function, namespace and class definitions. + * ``BS_Mozilla`` (in configuration: ``Mozilla``) + Like ``Attach``, but break before braces on enum, function, and record + definitions. * ``BS_Stroustrup`` (in configuration: ``Stroustrup``) Like ``Attach``, but break before function definitions, and 'else'. * ``BS_Allman`` (in configuration: ``Allman``) @@ -394,6 +397,12 @@ the configuration (without a prefix: ``Auto``). (https://developers.google.com/protocol-buffers/). +**MacroBlockBegin** (``std::string``) + A regular expression matching macros that start a block. + +**MacroBlockEnd** (``std::string``) + A regular expression matching macros that end a block. + **MaxEmptyLinesToKeep** (``unsigned``) The maximum number of consecutive empty lines to keep. diff --git a/docs/CrossCompilation.rst b/docs/CrossCompilation.rst index d3a775b4fd44..8a8027117372 100644 --- a/docs/CrossCompilation.rst +++ b/docs/CrossCompilation.rst @@ -92,7 +92,7 @@ will be assumed, which sets the defaults for the specified architecture. The system name is generally the OS (linux, darwin), but could be special like the bare-metal "none". -When a parameter is not important, they can be omitted, or you can +When a parameter is not important, it can be omitted, or you can choose ``unknown`` and the defaults will be used. If you choose a parameter that Clang doesn't know, like ``blerg``, it'll ignore and assume ``unknown``, which is not always desired, so be careful. diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index 0b4775ba6ad4..6a4dd5ccbf3c 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -1991,10 +1991,10 @@ compile time. Partial unrolling replicates the loop body within the loop and reduces the trip count. If ``unroll(full)`` is specified the unroller will attempt to fully unroll the -loop if the trip count is known at compile time. If the loop count is not known -or the fully unrolled code size is greater than the limit specified by the -`-pragma-unroll-threshold` command line option the loop will be partially -unrolled subject to the same limit. +loop if the trip count is known at compile time. If the fully unrolled code size +is greater than an internal limit the loop will be partially unrolled up to this +limit. If the loop count is not known at compile time the loop will not be +unrolled. .. code-block:: c++ @@ -2006,7 +2006,7 @@ unrolled subject to the same limit. The unroll count can be specified explicitly with ``unroll_count(_value_)`` where _value_ is a positive integer. If this value is greater than the trip count the loop will be fully unrolled. Otherwise the loop is partially unrolled subject -to the `-pragma-unroll-threshold` limit. +to the same code size limit as with ``unroll(full)``. .. code-block:: c++ diff --git a/docs/PCHInternals.rst b/docs/PCHInternals.rst index a36e65c199c6..8f66ddf0e1d8 100644 --- a/docs/PCHInternals.rst +++ b/docs/PCHInternals.rst @@ -124,20 +124,30 @@ section <pchinternals-chained>`. AST File Contents ----------------- -Clang's AST files are organized into several different blocks, each of which -contains the serialized representation of a part of Clang's internal +An AST file produced by clang is an object file container with a ``clangast`` +(COFF) or ``__clangast`` (ELF and Mach-O) section containing the serialized AST. +Other target-specific sections in the object file container are used to hold +debug information for the data types defined in the AST. Tools built on top of +libclang that do not need debug information may also produce raw AST files that +only contain the serialized AST. + +The ``clangast`` section is organized into several different blocks, each of +which contains the serialized representation of a part of Clang's internal representation. Each of the blocks corresponds to either a block or a record within `LLVM's bitstream format <http://llvm.org/docs/BitCodeFormat.html>`_. The contents of each of these logical blocks are described below. .. image:: PCHLayout.png -For a given AST file, the `llvm-bcanalyzer -<http://llvm.org/docs/CommandGuide/llvm-bcanalyzer.html>`_ utility can be used -to examine the actual structure of the bitstream for the AST file. This -information can be used both to help understand the structure of the AST file -and to isolate areas where AST files can still be optimized, e.g., through the -introduction of abbreviations. +The ``llvm-objdump`` utility provides a ``-raw-clang-ast`` option to extract the +binary contents of the AST section from an object file container. + +The `llvm-bcanalyzer <http://llvm.org/docs/CommandGuide/llvm-bcanalyzer.html>`_ +utility can be used to examine the actual structure of the bitstream for the AST +section. This information can be used both to help understand the structure of +the AST section and to isolate areas where the AST representation can still be +optimized, e.g., through the introduction of abbreviations. + Metadata Block ^^^^^^^^^^^^^^ diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index cd1b2b3c341d..20ee5696e06a 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -1488,6 +1488,45 @@ instrumentation: profile. As you make changes to your code, clang may no longer be able to use the profile data. It will warn you when this happens. +Profile generation and use can also be controlled by the GCC-compatible flags +``-fprofile-generate`` and ``-fprofile-use``. Although these flags are +semantically equivalent to their GCC counterparts, they *do not* handle +GCC-compatible profiles. They are only meant to implement GCC's semantics +with respect to profile creation and use. + +.. option:: -fprofile-generate[=<dirname>] + + Without any other arguments, ``-fprofile-generate`` behaves identically to + ``-fprofile-instr-generate``. When given a directory name, it generates the + profile file ``default.profraw`` in the directory named ``dirname``. If + ``dirname`` does not exist, it will be created at runtime. The environment + variable ``LLVM_PROFILE_FILE`` can be used to override the directory and + filename for the profile file at runtime. For example, + + .. code-block:: console + + $ clang++ -O2 -fprofile-generate=yyy/zzz code.cc -o code + + When ``code`` is executed, the profile will be written to the file + ``yyy/zzz/default.profraw``. This can be altered at runtime via the + ``LLVM_PROFILE_FILE`` environment variable: + + .. code-block:: console + + $ LLVM_PROFILE_FILE=/tmp/myprofile/code.profraw ./code + + The above invocation will produce the profile file + ``/tmp/myprofile/code.profraw`` instead of ``yyy/zzz/default.profraw``. + Notice that ``LLVM_PROFILE_FILE`` overrides the directory *and* the file + name for the profile file. + +.. option:: -fprofile-use[=<pathname>] + + Without any other arguments, ``-fprofile-use`` behaves identically to + ``-fprofile-instr-use``. Otherwise, if ``pathname`` is the full path to a + profile file, it reads from that file. If ``pathname`` is a directory name, + it reads from ``pathname/default.profdata``. + Controlling Size of Debug Information ------------------------------------- diff --git a/include/clang-c/BuildSystem.h b/include/clang-c/BuildSystem.h index 7aa01914cf24..8d323a4e6cae 100644 --- a/include/clang-c/BuildSystem.h +++ b/include/clang-c/BuildSystem.h @@ -73,7 +73,7 @@ clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay, * * \param options is reserved, always pass 0. * \param out_buffer_ptr pointer to receive the buffer pointer, which should be - * disposed using \c free(). + * disposed using \c clang_free(). * \param out_buffer_size pointer to receive the buffer size. * \returns 0 for success, non-zero to indicate an error. */ @@ -83,6 +83,14 @@ clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay, unsigned options, unsigned *out_buffer_size); /** + * \brief free memory allocated by libclang, such as the buffer returned by + * \c CXVirtualFileOverlay() or \c clang_ModuleMapDescriptor_writeToBuffer(). + * + * \param buffer memory pointer to free. + */ +CINDEX_LINKAGE void clang_free(void *buffer); + +/** * \brief Dispose a \c CXVirtualFileOverlay object. */ CINDEX_LINKAGE void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay); @@ -122,7 +130,7 @@ clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor, * * \param options is reserved, always pass 0. * \param out_buffer_ptr pointer to receive the buffer pointer, which should be - * disposed using \c free(). + * disposed using \c clang_free(). * \param out_buffer_size pointer to receive the buffer size. * \returns 0 for success, non-zero to indicate an error. */ diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 682be3d41513..a2bd55a089ed 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -236,6 +236,12 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType ObjCClassRedefinitionType; QualType ObjCSelRedefinitionType; + /// The identifier 'NSObject'. + IdentifierInfo *NSObjectName = nullptr; + + /// The identifier 'NSCopying'. + IdentifierInfo *NSCopyingName = nullptr; + QualType ObjCConstantStringType; mutable RecordDecl *CFConstantStringTypeDecl; @@ -1189,9 +1195,15 @@ public: QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceDecl *PrevDecl = nullptr) const; + /// Legacy interface: cannot provide type arguments or __kindof. QualType getObjCObjectType(QualType Base, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const; + + QualType getObjCObjectType(QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) const; bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in @@ -1351,6 +1363,24 @@ public: ObjCSelRedefinitionType = RedefType; } + /// Retrieve the identifier 'NSObject'. + IdentifierInfo *getNSObjectName() { + if (!NSObjectName) { + NSObjectName = &Idents.get("NSObject"); + } + + return NSObjectName; + } + + /// Retrieve the identifier 'NSCopying'. + IdentifierInfo *getNSCopyingName() { + if (!NSCopyingName) { + NSCopyingName = &Idents.get("NSCopying"); + } + + return NSCopyingName; + } + /// \brief Retrieve the Objective-C "instancetype" type, if already known; /// otherwise, returns a NULL type; QualType getObjCInstanceType() { diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 923d98fb1664..dd167fe27c02 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -940,6 +940,9 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { // type is itself. if (T->getBaseType().getTypePtr() != T) TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) { + TRY_TO(TraverseType(typeArg)); + } }) DEF_TRAVERSE_TYPE(ObjCObjectPointerType, @@ -1166,6 +1169,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { // type is itself. if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); }) DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, @@ -1307,7 +1312,13 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement }) DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement - }) + if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + return true; +}) DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement }) @@ -1316,7 +1327,16 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement }) DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement - }) + if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } +}) DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement }) @@ -1335,6 +1355,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, { return true; }) +DEF_TRAVERSE_DECL(ObjCTypeParamDecl, { + if (D->hasExplicitBound()) { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. + } +}) + DEF_TRAVERSE_DECL(ObjCPropertyDecl, { if (D->getTypeSourceInfo()) TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index c3fb57770245..c42764b6f3bf 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -332,10 +332,14 @@ public: SourceRange getReturnTypeSourceRange() const; /// \brief Determine the type of an expression that sends a message to this - /// function. - QualType getSendResultType() const { - return getReturnType().getNonLValueExprType(getASTContext()); - } + /// function. This replaces the type parameters with the types they would + /// get if the receiver was parameterless (e.g. it may replace the type + /// parameter with 'id'). + QualType getSendResultType() const; + + /// Determine the type of an expression that sends a message to this + /// function with the given receiver type. + QualType getSendResultType(QualType receiverType) const; TypeSourceInfo *getReturnTypeSourceInfo() const { return ReturnTInfo; } void setReturnTypeSourceInfo(TypeSourceInfo *TInfo) { ReturnTInfo = TInfo; } @@ -399,6 +403,11 @@ public: /// have already been created. void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID); + /// \return the type for \c self and set \arg selfIsPseudoStrong and + /// \arg selfIsConsumed accordingly. + QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID, + bool &selfIsPseudoStrong, bool &selfIsConsumed); + ImplicitParamDecl * getSelfDecl() const { return SelfDecl; } void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; } ImplicitParamDecl * getCmdDecl() const { return CmdDecl; } @@ -501,6 +510,183 @@ public: friend class ASTDeclWriter; }; +/// Describes the variance of a given generic parameter. +enum class ObjCTypeParamVariance : uint8_t { + /// The parameter is invariant: must match exactly. + Invariant, + /// The parameter is covariant, e.g., X<T> is a subtype of X<U> when + /// the type parameter is covariant and T is a subtype of U. + Covariant, + /// The parameter is contravariant, e.g., X<T> is a subtype of X<U> + /// when the type parameter is covariant and U is a subtype of T. + Contravariant, +}; + +/// Represents the declaration of an Objective-C type parameter. +/// +/// \code +/// @interface NSDictionary<Key : id<NSCopying>, Value> +/// @end +/// \endcode +/// +/// In the example above, both \c Key and \c Value are represented by +/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>, +/// while \c Value gets an implicit bound of \c id. +/// +/// Objective-C type parameters are typedef-names in the grammar, +class ObjCTypeParamDecl : public TypedefNameDecl { + void anchor() override; + + /// Index of this type parameter in the type parameter list. + unsigned Index : 14; + + /// The variance of the type parameter. + unsigned Variance : 2; + + /// The location of the variance, if any. + SourceLocation VarianceLoc; + + /// The location of the ':', which will be valid when the bound was + /// explicitly specified. + SourceLocation ColonLoc; + + ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, IdentifierInfo *name, + SourceLocation colonLoc, TypeSourceInfo *boundInfo) + : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name, + boundInfo), + Index(index), Variance(static_cast<unsigned>(variance)), + VarianceLoc(varianceLoc), ColonLoc(colonLoc) { } + +public: + static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, + IdentifierInfo *name, + SourceLocation colonLoc, + TypeSourceInfo *boundInfo); + static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Determine the variance of this type parameter. + ObjCTypeParamVariance getVariance() const { + return static_cast<ObjCTypeParamVariance>(Variance); + } + + /// Set the variance of this type parameter. + void setVariance(ObjCTypeParamVariance variance) { + Variance = static_cast<unsigned>(variance); + } + + /// Retrieve the location of the variance keyword. + SourceLocation getVarianceLoc() const { return VarianceLoc; } + + /// Retrieve the index into its type parameter list. + unsigned getIndex() const { return Index; } + + /// Whether this type parameter has an explicitly-written type bound, e.g., + /// "T : NSView". + bool hasExplicitBound() const { return ColonLoc.isValid(); } + + /// Retrieve the location of the ':' separating the type parameter name + /// from the explicitly-specified bound. + SourceLocation getColonLoc() const { return ColonLoc; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCTypeParam; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Stores a list of Objective-C type parameters for a parameterized class +/// or a category/extension thereof. +/// +/// \code +/// @interface NSArray<T> // stores the <T> +/// @end +/// \endcode +class ObjCTypeParamList { + /// Stores the components of a SourceRange as a POD. + struct PODSourceRange { + unsigned Begin; + unsigned End; + }; + + union { + /// Location of the left and right angle brackets. + PODSourceRange Brackets; + + // Used only for alignment. + ObjCTypeParamDecl *AlignmentHack; + }; + + /// The number of parameters in the list, which are tail-allocated. + unsigned NumParams; + + ObjCTypeParamList(SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc); + +public: + /// Create a new Objective-C type parameter list. + static ObjCTypeParamList *create(ASTContext &ctx, + SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc); + + /// Iterate through the type parameters in the list. + typedef ObjCTypeParamDecl **iterator; + + iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); } + + iterator end() { return begin() + size(); } + + /// Determine the number of type parameters in this list. + unsigned size() const { return NumParams; } + + // Iterate through the type parameters in the list. + typedef ObjCTypeParamDecl * const *const_iterator; + + const_iterator begin() const { + return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1); + } + + const_iterator end() const { + return begin() + size(); + } + + ObjCTypeParamDecl *front() const { + assert(size() > 0 && "empty Objective-C type parameter list"); + return *begin(); + } + + ObjCTypeParamDecl *back() const { + assert(size() > 0 && "empty Objective-C type parameter list"); + return *(end() - 1); + } + + SourceLocation getLAngleLoc() const { + return SourceLocation::getFromRawEncoding(Brackets.Begin); + } + SourceLocation getRAngleLoc() const { + return SourceLocation::getFromRawEncoding(Brackets.End); + } + SourceRange getSourceRange() const { + return SourceRange(getLAngleLoc(), getRAngleLoc()); + } + + /// Gather the default set of type arguments to be substituted for + /// these type parameters when dealing with an unspecialized type. + void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const; +}; + /// ObjCContainerDecl - Represents a container for method declarations. /// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, /// ObjCProtocolDecl, and ObjCImplDecl. @@ -676,9 +862,9 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// declaration. ObjCInterfaceDecl *Definition; - /// Class's super class. - ObjCInterfaceDecl *SuperClass; - + /// When non-null, this is always an ObjCObjectType. + TypeSourceInfo *SuperClassTInfo; + /// Protocols referenced in the \@interface declaration ObjCProtocolList ReferencedProtocols; @@ -719,16 +905,13 @@ class ObjCInterfaceDecl : public ObjCContainerDecl }; /// One of the \c InheritedDesignatedInitializersState enumeratos. mutable unsigned InheritedDesignatedInitializers : 2; - - /// \brief The location of the superclass, if any. - SourceLocation SuperClassLoc; /// \brief The location of the last location in this declaration, before /// the properties/methods. For example, this will be the '>', '}', or /// identifier, SourceLocation EndLoc; - DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), + DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(), ExternallyCompleted(), IvarListMissingImplementation(true), HasDesignatedInitializers(), @@ -736,11 +919,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl }; ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, - IdentifierInfo *Id, SourceLocation CLoc, - ObjCInterfaceDecl *PrevDecl, bool IsInternal); + IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, + bool IsInternal); void LoadExternalDefinition() const; + /// The type parameters associated with this class, if any. + ObjCTypeParamList *TypeParamList; + /// \brief Contains a pointer to the data associated with this class, /// which will be NULL if this class has not yet been defined. /// @@ -771,12 +958,33 @@ public: static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + /// Retrieve the type parameters of this class. + /// + /// This function looks for a type parameter list for the given + /// class; if the class has been declared (with \c \@class) but not + /// defined (with \c \@interface), it will search for a declaration that + /// has type parameters, skipping any declarations that do not. + ObjCTypeParamList *getTypeParamList() const; + + /// Set the type parameters of this class. + /// + /// This function is used by the AST importer, which must import the type + /// parameters after creating their DeclContext to avoid loops. + void setTypeParamList(ObjCTypeParamList *TPL); + + /// Retrieve the type parameters written on this particular declaration of + /// the class. + ObjCTypeParamList *getTypeParamListAsWritten() const { + return TypeParamList; + } + SourceRange getSourceRange() const override LLVM_READONLY { if (isThisDeclarationADefinition()) return ObjCContainerDecl::getSourceRange(); @@ -1023,7 +1231,16 @@ public: /// a forward declaration (\@class) to a definition (\@interface). void startDefinition(); - ObjCInterfaceDecl *getSuperClass() const { + /// Retrieve the superclass type. + const ObjCObjectType *getSuperClassType() const { + if (TypeSourceInfo *TInfo = getSuperClassTInfo()) + return TInfo->getType()->castAs<ObjCObjectType>(); + + return nullptr; + } + + // Retrieve the type source information for the superclass. + TypeSourceInfo *getSuperClassTInfo() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1031,13 +1248,15 @@ public: if (data().ExternallyCompleted) LoadExternalDefinition(); - return data().SuperClass; + return data().SuperClassTInfo; } - void setSuperClass(ObjCInterfaceDecl * superCls) { - data().SuperClass = - (superCls && superCls->hasDefinition()) ? superCls->getDefinition() - : superCls; + // Retrieve the declaration for the superclass of this class, which + // does not include any type arguments that apply to the superclass. + ObjCInterfaceDecl *getSuperClass() const; + + void setSuperClass(TypeSourceInfo *superClass) { + data().SuperClassTInfo = superClass; } /// \brief Iterator that walks over the list of categories, filtering out @@ -1329,8 +1548,8 @@ public: void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; } - void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; } - SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; } + /// Retrieve the starting location of the superclass. + SourceLocation getSuperClassLoc() const; /// isImplicitInterfaceDecl - check that this is an implicitly declared /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation @@ -1438,6 +1657,10 @@ public: void setSynthesize(bool synth) { Synthesized = synth; } bool getSynthesize() const { return Synthesized; } + /// Retrieve the type of this instance variable when viewed as a member of a + /// specific object type. + QualType getUsageType(QualType objectType) const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCIvar; } @@ -1719,6 +1942,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl { /// Interface belonging to this category ObjCInterfaceDecl *ClassInterface; + /// The type parameters associated with this category, if any. + ObjCTypeParamList *TypeParamList; + /// referenced protocols in this category. ObjCProtocolList ReferencedProtocols; @@ -1736,13 +1962,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl { ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc=SourceLocation(), - SourceLocation IvarRBraceLoc=SourceLocation()) - : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), - ClassInterface(IDecl), NextClassCategory(nullptr), - CategoryNameLoc(CategoryNameLoc), - IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { - } + SourceLocation IvarRBraceLoc=SourceLocation()); public: @@ -1752,6 +1974,7 @@ public: SourceLocation CategoryNameLoc, IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc=SourceLocation(), SourceLocation IvarRBraceLoc=SourceLocation()); static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -1759,6 +1982,17 @@ public: ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + /// Retrieve the type parameter list associated with this category or + /// extension. + ObjCTypeParamList *getTypeParamList() const { return TypeParamList; } + + /// Set the type parameters of this category. + /// + /// This function is used by the AST importer, which must import the type + /// parameters after creating their DeclContext to avoid loops. + void setTypeParamList(ObjCTypeParamList *TPL); + + ObjCCategoryImplDecl *getImplementation() const; void setImplementation(ObjCCategoryImplDecl *ImplD); @@ -2275,6 +2509,10 @@ public: DeclTypeSourceInfo = TSI; } + /// Retrieve the type when this property is used with a specific base object + /// type. + QualType getUsageType(QualType objectType) const; + PropertyAttributeKind getPropertyAttributes() const { return PropertyAttributeKind(PropertyAttributes); } diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 899e6487f737..f28e5196c7a4 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -687,40 +687,7 @@ public: QualType getSuperReceiverType() const { return QualType(Receiver.get<const Type*>(), 0); } - QualType getGetterResultType() const { - QualType ResultType; - if (isExplicitProperty()) { - const ObjCPropertyDecl *PDecl = getExplicitProperty(); - if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl()) - ResultType = Getter->getReturnType(); - else - ResultType = PDecl->getType(); - } else { - const ObjCMethodDecl *Getter = getImplicitPropertyGetter(); - if (Getter) - ResultType = Getter->getReturnType(); // with reference! - } - return ResultType; - } - - QualType getSetterArgType() const { - QualType ArgType; - if (isImplicitProperty()) { - const ObjCMethodDecl *Setter = getImplicitPropertySetter(); - ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); - ArgType = (*P)->getType(); - } else { - if (ObjCPropertyDecl *PDecl = getExplicitProperty()) - if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) { - ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); - ArgType = (*P)->getType(); - } - if (ArgType.isNull()) - ArgType = getType(); - } - return ArgType; - } - + ObjCInterfaceDecl *getClassReceiver() const { return Receiver.get<ObjCInterfaceDecl*>(); } @@ -728,6 +695,9 @@ public: bool isSuperReceiver() const { return Receiver.is<const Type*>(); } bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } + /// Determine the type of the base, regardless of the kind of receiver. + QualType getReceiverType(const ASTContext &ctx) const; + SourceLocation getLocStart() const LLVM_READONLY { return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation(); } diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index b118503b674b..1017656b662c 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1008,6 +1008,9 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { // type is itself. if (T->getBaseType().getTypePtr() != T) TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) { + TRY_TO(TraverseType(typeArg)); + } }) DEF_TRAVERSE_TYPE(ObjCObjectPointerType, @@ -1234,6 +1237,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { // type is itself. if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); }) DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, @@ -1382,7 +1387,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement }) DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement - }) + if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } +}) DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement }) @@ -1391,7 +1401,16 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement }) DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement - }) + if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } +}) DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement }) @@ -1410,6 +1429,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, { return true; }) +DEF_TRAVERSE_DECL(ObjCTypeParamDecl, { + if (D->hasExplicitBound()) { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. + } +}) + DEF_TRAVERSE_DECL(ObjCPropertyDecl, { if (D->getTypeSourceInfo()) TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 97f13313b339..632d4b95e376 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -533,6 +533,24 @@ struct SplitQualType { } }; +/// The kind of type we are substituting Objective-C type arguments into. +/// +/// The kind of substitution affects the replacement of type parameters when +/// no concrete type information is provided, e.g., when dealing with an +/// unspecialized type. +enum class ObjCSubstitutionContext { + /// An ordinary type. + Ordinary, + /// The result type of a method or function. + Result, + /// The parameter type of a method or function. + Parameter, + /// The type of a property. + Property, + /// The superclass of a type. + Superclass, +}; + /// QualType - For efficiency, we don't store CV-qualified types as nodes on /// their own: instead each reference to a type stores the qualifiers. This /// greatly reduces the number of nodes we need to allocate for types (for @@ -994,6 +1012,51 @@ public: /// type other than void. bool isCForbiddenLValueType() const; + /// Substitute type arguments for the Objective-C type parameters used in the + /// subject type. + /// + /// \param ctx ASTContext in which the type exists. + /// + /// \param typeArgs The type arguments that will be substituted for the + /// Objective-C type parameters in the subject type, which are generally + /// computed via \c Type::getObjCSubstitutions. If empty, the type + /// parameters will be replaced with their bounds or id/Class, as appropriate + /// for the context. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the resulting type. + QualType substObjCTypeArgs(ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const; + + /// Substitute type arguments from an object type for the Objective-C type + /// parameters used in the subject type. + /// + /// This operation combines the computation of type arguments for + /// substitution (\c Type::getObjCSubstitutions) with the actual process of + /// substitution (\c QualType::substObjCTypeArgs) for the convenience of + /// callers that need to perform a single substitution in isolation. + /// + /// \param objectType The type of the object whose member type we're + /// substituting into. For example, this might be the receiver of a message + /// or the base of a property access. + /// + /// \param dc The declaration context from which the subject type was + /// retrieved, which indicates (for example) which type parameters should + /// be substituted. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the subject type after replacing all of the Objective-C type + /// parameters with their corresponding arguments. + QualType substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const; + + /// Strip Objective-C "__kindof" types from the given type. + QualType stripObjCKindOfType(const ASTContext &ctx) const; + private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the @@ -1288,10 +1351,17 @@ protected: unsigned : NumTypeBits; + /// The number of type arguments stored directly on this object type. + unsigned NumTypeArgs : 7; + /// NumProtocols - The number of protocols stored directly on this /// object type. - unsigned NumProtocols : 32 - NumTypeBits; + unsigned NumProtocols : 6; + + /// Whether this is a "kindof" type. + unsigned IsKindOf : 1; }; + static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned"); class ReferenceTypeBitfields { friend class ReferenceType; @@ -1585,7 +1655,28 @@ public: bool isObjCQualifiedClassType() const; // Class<foo> bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id + + /// Whether the type is Objective-C 'id' or a __kindof type of an + /// object type, e.g., __kindof NSView * or __kindof id + /// <NSCopying>. + /// + /// \param bound Will be set to the bound on non-id subtype types, + /// which will be (possibly specialized) Objective-C class type, or + /// null for 'id. + bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, + const ObjCObjectType *&bound) const; + bool isObjCClassType() const; // Class + + /// Whether the type is Objective-C 'Class' or a __kindof type of an + /// Class type, e.g., __kindof Class <NSCopying>. + /// + /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound + /// here because Objective-C's type system cannot express "a class + /// object for a subclass of NSFoo". + bool isObjCClassOrClassKindOfType() const; + + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isObjCARCBridgableType() const; @@ -1697,6 +1788,7 @@ public: /// NOTE: getAs*ArrayType are methods on ASTContext. const RecordType *getAsUnionType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. + const ObjCObjectType *getAsObjCInterfaceType() const; // The following is a convenience method that returns an ObjCObjectPointerType // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; @@ -1832,6 +1924,28 @@ public: /// pointer type. bool canHaveNullability() const; + /// Retrieve the set of substitutions required when accessing a member + /// of the Objective-C receiver type that is declared in the given context. + /// + /// \c *this is the type of the object we're operating on, e.g., the + /// receiver for a message send or the base of a property access, and is + /// expected to be of some object or object pointer type. + /// + /// \param dc The declaration context for which we are building up a + /// substitution mapping, which should be an Objective-C class, extension, + /// category, or method within. + /// + /// \returns an array of type arguments that can be substituted for + /// the type parameters of the given declaration context in any type described + /// within that context, or an empty optional to indicate that no + /// substitution is required. + Optional<ArrayRef<QualType>> + getObjCSubstitutions(const DeclContext *dc) const; + + /// Determines if this is an ObjC interface type that may accept type + /// parameters. + bool acceptsObjCTypeParams() const; + const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { @@ -3497,6 +3611,7 @@ public: attr_nonnull, attr_nullable, attr_null_unspecified, + attr_objc_kindof, }; private: @@ -4369,19 +4484,25 @@ public: }; /// ObjCObjectType - Represents a class type in Objective C. -/// Every Objective C type is a combination of a base type and a -/// list of protocols. +/// +/// Every Objective C type is a combination of a base type, a set of +/// type arguments (optional, for parameterized classes) and a list of +/// protocols. /// /// Given the following declarations: /// \code -/// \@class C; +/// \@class C<T>; /// \@protocol P; /// \endcode /// /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType /// with base C and no protocols. /// -/// 'C<P>' is an ObjCObjectType with base C and protocol list [P]. +/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P]. +/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no +/// protocol list. +/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*', +/// and protocol list [P]. /// /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType @@ -4391,8 +4512,10 @@ public: /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type { - // ObjCObjectType.NumProtocols - the number of protocols stored + // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the type arguments of ObjCObjectPointerType node. // // These protocols are those written directly on the type. If // protocol qualifiers ever become additive, the iterators will need @@ -4404,23 +4527,38 @@ class ObjCObjectType : public Type { /// Either a BuiltinType or an InterfaceType or sugar for either. QualType BaseType; + /// Cached superclass type. + mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool> + CachedSuperClassType; + ObjCProtocolDecl * const *getProtocolStorage() const { return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); } + QualType *getTypeArgStorage(); + const QualType *getTypeArgStorage() const { + return const_cast<ObjCObjectType *>(this)->getTypeArgStorage(); + } + ObjCProtocolDecl **getProtocolStorage(); protected: ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, unsigned NumProtocols); + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf); enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; + ObjCObjectTypeBits.NumTypeArgs = 0; + ObjCObjectTypeBits.IsKindOf = 0; } + void computeSuperClassTypeSlow() const; + public: /// getBaseType - Gets the base type of this object type. This is /// always (possibly sugar for) one of: @@ -4452,6 +4590,33 @@ public: /// really is an interface. ObjCInterfaceDecl *getInterface() const; + /// Determine whether this object type is "specialized", meaning + /// that it has type arguments. + bool isSpecialized() const; + + /// Determine whether this object type was written with type arguments. + bool isSpecializedAsWritten() const { + return ObjCObjectTypeBits.NumTypeArgs > 0; + } + + /// Determine whether this object type is "unspecialized", meaning + /// that it has no type arguments. + bool isUnspecialized() const { return !isSpecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments of this object type (semantically). + ArrayRef<QualType> getTypeArgs() const; + + /// Retrieve the type arguments of this object type as they were + /// written. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return ArrayRef<QualType>(getTypeArgStorage(), + ObjCObjectTypeBits.NumTypeArgs); + } + typedef ObjCProtocolDecl * const *qual_iterator; typedef llvm::iterator_range<qual_iterator> qual_range; @@ -4471,6 +4636,35 @@ public: return qual_begin()[I]; } + /// Retrieve all of the protocol qualifiers. + ArrayRef<ObjCProtocolDecl *> getProtocols() const { + return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols()); + } + + /// Whether this is a "__kindof" type as written. + bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } + + /// Whether this ia a "__kindof" type (semantically). + bool isKindOfType() const; + + /// Retrieve the type of the superclass of this object type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// specialization of the superclass type. Produces a null type if + /// there is no superclass. + QualType getSuperClassType() const { + if (!CachedSuperClassType.getInt()) + computeSuperClassTypeSlow(); + + assert(CachedSuperClassType.getInt() && "Superclass not set?"); + return QualType(CachedSuperClassType.getPointer(), 0); + } + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -4491,21 +4685,27 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { // will need to be modified. ObjCObjectTypeImpl(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) - : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {} + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) + : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, - ObjCProtocolDecl *const *protocols, - unsigned NumProtocols); + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf); }; +inline QualType *ObjCObjectType::getTypeArgStorage() { + return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1); +} + inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { - return reinterpret_cast<ObjCProtocolDecl**>( - static_cast<ObjCObjectTypeImpl*>(this) + 1); + return reinterpret_cast<ObjCProtocolDecl**>( + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); } /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for @@ -4556,9 +4756,14 @@ public: }; inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { - if (const ObjCInterfaceType *T = - getBaseType()->getAs<ObjCInterfaceType>()) - return T->getDecl(); + QualType baseType = getBaseType(); + while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) { + if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT)) + return T->getDecl(); + + baseType = ObjT->getBaseType(); + } + return nullptr; } @@ -4575,7 +4780,11 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, false, false, false, false), + : Type(ObjCObjectPointer, Canonical, + Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} friend class ASTContext; // ASTContext creates these. @@ -4617,9 +4826,7 @@ public: /// qualifiers on the interface are ignored. /// /// \return null if the base type for this pointer is 'id' or 'Class' - const ObjCInterfaceType *getInterfaceType() const { - return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>(); - } + const ObjCInterfaceType *getInterfaceType() const; /// getInterfaceDecl - If this pointer points to an Objective \@interface /// type, gets the declaration for that interface. @@ -4641,6 +4848,12 @@ public: return getObjectType()->isObjCUnqualifiedClass(); } + /// isObjCIdOrClassType - True if this is equivalent to the 'id' or + /// 'Class' type, + bool isObjCIdOrClassType() const { + return getObjectType()->isObjCUnqualifiedIdOrClass(); + } + /// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some /// non-empty set of protocols. bool isObjCQualifiedIdType() const { @@ -4653,6 +4866,34 @@ public: return getObjectType()->isObjCQualifiedClass(); } + /// Whether this is a "__kindof" type. + bool isKindOfType() const { return getObjectType()->isKindOfType(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecialized() const { return getObjectType()->isSpecialized(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecializedAsWritten() const { + return getObjectType()->isSpecializedAsWritten(); + } + + /// Whether this type is unspecialized, meaning that is has no type arguments. + bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgs() const { + return getObjectType()->getTypeArgs(); + } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return getObjectType()->getTypeArgsAsWritten(); + } + /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. @@ -4683,6 +4924,19 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + /// Retrieve the type of the superclass of this object pointer type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// pointer to a specialization of the superclass type. Produces a + /// null type if there is no superclass. + QualType getSuperClassType() const; + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const; + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index e29fa4903282..f4d20b8d526a 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -177,6 +177,9 @@ public: memcpy(getOpaqueData(), Other.getOpaqueData(), Size); } + /// Copies the other type loc into this one. + void copy(TypeLoc other); + friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data; } @@ -185,6 +188,10 @@ public: return !(LHS == RHS); } + /// Find the location of the nullability specifier (__nonnull, + /// __nullable, or __null_unspecifier), if there is one. + SourceLocation findNullabilityLoc() const; + private: static bool isKind(const TypeLoc&) { return true; @@ -249,6 +256,10 @@ public: // do nothing } + void copyLocal(TypeLoc other) { + // do nothing + } + TypeLoc getNextTypeLoc() const { return getUnqualifiedLoc(); } @@ -339,6 +350,20 @@ public: return size; } + void copyLocal(Derived other) { + // Some subclasses have no data to copy. + if (asDerived()->getLocalDataSize() == 0) return; + + // Copy the fixed-sized local data. + memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData)); + + // Copy the variable-sized local data. We need to do this + // separately because the padding in the source and the padding in + // the destination might be different. + memcpy(getExtraLocalData(), other.getExtraLocalData(), + asDerived()->getExtraLocalDataSize()); + } + TypeLoc getNextTypeLoc() const { return getNextTypeLoc(asDerived()->getInnerType()); } @@ -799,9 +824,11 @@ public: }; -struct ObjCProtocolListLocInfo { - SourceLocation LAngleLoc; - SourceLocation RAngleLoc; +struct ObjCObjectTypeLocInfo { + SourceLocation TypeArgsLAngleLoc; + SourceLocation TypeArgsRAngleLoc; + SourceLocation ProtocolLAngleLoc; + SourceLocation ProtocolRAngleLoc; bool HasBaseTypeAsWritten; }; @@ -813,25 +840,59 @@ struct ObjCProtocolListLocInfo { class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, ObjCObjectTypeLoc, ObjCObjectType, - ObjCProtocolListLocInfo> { - // SourceLocations are stored after Info, one for each Protocol. + ObjCObjectTypeLocInfo> { + // TypeSourceInfo*'s are stored after Info, one for each type argument. + TypeSourceInfo **getTypeArgLocArray() const { + return (TypeSourceInfo**)this->getExtraLocalData(); + } + + // SourceLocations are stored after the type argument information, one for + // each Protocol. SourceLocation *getProtocolLocArray() const { - return (SourceLocation*) this->getExtraLocalData(); + return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs()); } public: - SourceLocation getLAngleLoc() const { - return this->getLocalData()->LAngleLoc; + SourceLocation getTypeArgsLAngleLoc() const { + return this->getLocalData()->TypeArgsLAngleLoc; } - void setLAngleLoc(SourceLocation Loc) { - this->getLocalData()->LAngleLoc = Loc; + void setTypeArgsLAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsLAngleLoc = Loc; } - SourceLocation getRAngleLoc() const { - return this->getLocalData()->RAngleLoc; + SourceLocation getTypeArgsRAngleLoc() const { + return this->getLocalData()->TypeArgsRAngleLoc; } - void setRAngleLoc(SourceLocation Loc) { - this->getLocalData()->RAngleLoc = Loc; + void setTypeArgsRAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsRAngleLoc = Loc; + } + + unsigned getNumTypeArgs() const { + return this->getTypePtr()->getTypeArgsAsWritten().size(); + } + + TypeSourceInfo *getTypeArgTInfo(unsigned i) const { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + return getTypeArgLocArray()[i]; + } + + void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + getTypeArgLocArray()[i] = TInfo; + } + + SourceLocation getProtocolLAngleLoc() const { + return this->getLocalData()->ProtocolLAngleLoc; + } + void setProtocolLAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolLAngleLoc = Loc; + } + + SourceLocation getProtocolRAngleLoc() const { + return this->getLocalData()->ProtocolRAngleLoc; + } + void setProtocolRAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolRAngleLoc = Loc; } unsigned getNumProtocols() const { @@ -852,6 +913,11 @@ public: return *(this->getTypePtr()->qual_begin() + i); } + + ArrayRef<SourceLocation> getProtocolLocs() const { + return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols()); + } + bool hasBaseTypeAsWritten() const { return getLocalData()->HasBaseTypeAsWritten; } @@ -865,23 +931,27 @@ public: } SourceRange getLocalSourceRange() const { - return SourceRange(getLAngleLoc(), getRAngleLoc()); + SourceLocation start = getTypeArgsLAngleLoc(); + if (start.isInvalid()) + start = getProtocolLAngleLoc(); + SourceLocation end = getProtocolRAngleLoc(); + if (end.isInvalid()) + end = getTypeArgsRAngleLoc(); + return SourceRange(start, end); } - void initializeLocal(ASTContext &Context, SourceLocation Loc) { - setHasBaseTypeAsWritten(true); - setLAngleLoc(Loc); - setRAngleLoc(Loc); - for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) - setProtocolLoc(i, Loc); - } + void initializeLocal(ASTContext &Context, SourceLocation Loc); unsigned getExtraLocalDataSize() const { - return this->getNumProtocols() * sizeof(SourceLocation); + return this->getNumTypeArgs() * sizeof(TypeSourceInfo *) + + this->getNumProtocols() * sizeof(SourceLocation); } unsigned getExtraLocalDataAlignment() const { - return llvm::alignOf<SourceLocation>(); + assert(llvm::alignOf<ObjCObjectTypeLoc>() + >= llvm::alignOf<TypeSourceInfo *>() && + "not enough alignment for tail-allocated data"); + return llvm::alignOf<TypeSourceInfo *>(); } QualType getInnerType() const { diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index e7a97a7ff745..281d6370e5c8 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -112,7 +112,7 @@ private: /// /// FIXME: Do we want to support this now that we have bind()? template <typename T> -internal::Matcher<T> id(const std::string &ID, +internal::Matcher<T> id(StringRef ID, const internal::BindableMatcher<T> &InnerMatcher) { return InnerMatcher.bind(ID); } diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index cbaa4ba27ce7..b494647d79bc 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -140,8 +140,7 @@ public: }; /// \brief Add a binding from an id to a node. - void setBinding(const std::string &Id, - const ast_type_traits::DynTypedNode &DynNode) { + void setBinding(StringRef Id, const ast_type_traits::DynTypedNode &DynNode) { if (Bindings.empty()) Bindings.emplace_back(); for (BoundNodesMap &Binding : Bindings) diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index 78aa9dc82a98..c391b24a3330 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -242,7 +242,7 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { /// /// Supported types: /// - \c unsigned -/// - \c std::string +/// - \c llvm::StringRef /// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>) class VariantValue { public: @@ -254,7 +254,7 @@ public: /// \brief Specific constructors for each supported type. VariantValue(unsigned Unsigned); - VariantValue(const std::string &String); + VariantValue(StringRef String); VariantValue(const VariantMatcher &Matchers); /// \brief Returns true iff this is not an empty value. @@ -269,7 +269,7 @@ public: /// \brief String value functions. bool isString() const; const std::string &getString() const; - void setString(const std::string &String); + void setString(StringRef String); /// \brief Matcher value functions. bool isMatcher() const; diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 2bbce37e57bb..fb1eb58dcc70 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -976,6 +976,11 @@ def TypeNullUnspecified : TypeAttr { let Documentation = [TypeNullUnspecifiedDocs]; } +def ObjCKindOf : TypeAttr { + let Spellings = [Keyword<"__kindof">]; + let Documentation = [Undocumented]; +} + def AssumeAligned : InheritableAttr { let Spellings = [GCC<"assume_aligned">]; let Subjects = SubjectList<[ObjCMethod, Function]>; @@ -1276,9 +1281,8 @@ def Pascal : InheritableAttr { def Target : InheritableAttr { let Spellings = [GCC<"target">]; let Args = [StringArgument<"features">]; - let Subjects = - SubjectList<[Function], ErrorDiag, "ExpectedFunctionMethodOrClass">; - let Documentation = [Undocumented]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [TargetDocs]; } def TransparentUnion : InheritableAttr { diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 107458e46145..e4ca0cb4778e 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -678,6 +678,25 @@ The semantics are as follows: }]; } +def TargetDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute. +This attribute may be attached to a function definition and instructs +the backend to use different code generation options than were passed on the +command line. + +The current set of options correspond to the existing "subtarget features" for +the target with or without a "-mno-" in front corresponding to the absence +of the feature, as well as ``arch="CPU"`` which will change the default "CPU" +for the function. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. +}]; +} + def DocCatAMDGPURegisterAttributes : DocumentationCategory<"AMD GPU Register Attributes"> { let Content = [{ diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index 02e52947ed6c..fdf1cb0b5a40 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -248,6 +248,11 @@ BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "") BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "") BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "") +BUILTIN(__builtin_altivec_vclzb, "V16UcV16Uc", "") +BUILTIN(__builtin_altivec_vclzh, "V8UsV8Us", "") +BUILTIN(__builtin_altivec_vclzw, "V4UiV4Ui", "") +BUILTIN(__builtin_altivec_vclzd, "V2ULLiV2ULLi", "") + // VSX built-ins. BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "") @@ -279,6 +284,47 @@ BUILTIN(__builtin_vsx_xvcmpgesp, "V4UiV4fV4f", "") BUILTIN(__builtin_vsx_xvcmpgtdp, "V2ULLiV2dV2d", "") BUILTIN(__builtin_vsx_xvcmpgtsp, "V4UiV4fV4f", "") +BUILTIN(__builtin_vsx_xvrdpim, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspim, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpi, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspi, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpic, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspic, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrdpiz, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrspiz, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvmaddadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmaddasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvmsubadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmsubasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvmuldp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmulsp, "V4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvnmaddadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvnmaddasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvnmsubadp, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvnmsubasp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_vsx_xvredp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvresp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvrsqrtedp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvrsqrtesp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xvsqrtdp, "V2dV2d", "") +BUILTIN(__builtin_vsx_xvsqrtsp, "V4fV4f", "") + +BUILTIN(__builtin_vsx_xxleqv, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_vsx_xvcpsgndp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvcpsgnsp, "V4fV4fV4f", "") + // HTM builtins BUILTIN(__builtin_tbegin, "UiUIi", "") BUILTIN(__builtin_tend, "UiUIi", "") diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index aaf279f3713f..1cd8973cbd6d 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -1157,5 +1157,65 @@ BUILTIN(__builtin_ia32_vpconflictdi_512_mask, "V8LLiV8LLiV8LLiUc", "") BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "") BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "") BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_blendmb_128_mask, "V16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_blendmb_256_mask, "V32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_blendmw_128_mask, "V8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_blendmw_256_mask, "V16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pabsb128_mask, "V16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pabsb256_mask, "V32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pabsw128_mask, "V8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pabsw256_mask, "V16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_packssdw128_mask, "V8sV4iV4iV8sUc", "") +BUILTIN(__builtin_ia32_packssdw256_mask, "V16sV8iV8iV16sUs", "") +BUILTIN(__builtin_ia32_packsswb128_mask, "V16cV8sV8sV16cUs", "") +BUILTIN(__builtin_ia32_packsswb256_mask, "V32cV16sV16sV32cUi", "") +BUILTIN(__builtin_ia32_packusdw128_mask, "V8sV4iV4iV8sUc", "") +BUILTIN(__builtin_ia32_packusdw256_mask, "V16sV8iV8iV16sUs", "") +BUILTIN(__builtin_ia32_packuswb128_mask, "V16cV8sV8sV16cUs", "") +BUILTIN(__builtin_ia32_packuswb256_mask, "V32cV16sV16sV32cUi", "") +BUILTIN(__builtin_ia32_paddsb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_paddsb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_paddsw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_paddsw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_paddusb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_paddusb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_paddusw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_paddusw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pavgb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pavgb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pavgw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pavgw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pmaxsb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pmaxsb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pmaxsw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pmaxsw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pmaxub128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pmaxub256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pmaxuw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pmaxuw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pminsb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pminsb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pminsw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pminsw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pminub128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pminub256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_pminuw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_pminuw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_pshufb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_pshufb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_psubsb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_psubsb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_psubsw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_psubsw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_psubusb128_mask, "V16cV16cV16cV16cUs", "") +BUILTIN(__builtin_ia32_psubusb256_mask, "V32cV32cV32cV32cUi", "") +BUILTIN(__builtin_ia32_psubusw128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_psubusw256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_vpermt2varhi128_maskz, "V8sV8sV8sV8sUc", "") +BUILTIN(__builtin_ia32_vpermt2varhi256_mask, "V16sV16sV16sV16sUs", "") +BUILTIN(__builtin_ia32_vpermt2varhi256_maskz, "V16sV16sV16sV16sUs", "") #undef BUILTIN diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index dece8f9ed2ec..e1a23120c186 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -21,6 +21,7 @@ def Named : Decl<1>; def TypedefName : DDecl<Type, 1>; def Typedef : DDecl<TypedefName>; def TypeAlias : DDecl<TypedefName>; + def ObjCTypeParam : DDecl<TypedefName>; def UnresolvedUsingTypename : DDecl<Type>; def Tag : DDecl<Type, 1>, DeclContext; def Enum : DDecl<Tag>; diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 24813c67c2f5..ff42683ecdde 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -179,6 +179,8 @@ def err_target_unsupported_fpmath : Error< "the '%0' unit is not supported with this instruction set">; def err_target_unsupported_unaligned : Error< "the %0 sub-architecture does not support unaligned accesses">; +def err_opt_not_valid_with_opt : Error< + "option '%0' cannot be specified with '%1'">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 7c0696a1b922..f7f09da4ea6e 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -69,8 +69,6 @@ def err_drv_no_module_support : Error< "'%0': unable to use module files with this tool">; def err_drv_clang_unsupported : Error< "the clang compiler does not support '%0'">; -def err_drv_clang_unsupported_per_platform : Error< - "the clang compiler does not support '%0' on this platform">; 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_command_failed : Error< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 85796cc0d325..4ecd5d5e1842 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -280,6 +280,7 @@ def FunctionDefInObjCContainer : DiagGroup<"function-def-in-objc-container">; def BadFunctionCast : DiagGroup<"bad-function-cast">; def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">; +def ObjCProtocolQualifiers : DiagGroup<"objc-protocol-qualifiers">; def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">; def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 6a11d240c63c..1364b982ecf1 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -1004,10 +1004,6 @@ def err_pragma_invalid_keyword : Error< def warn_pragma_unroll_cuda_value_in_parens : Warning< "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">, InGroup<CudaCompat>; - -def err_empty_attribute_block : Error< - "Microsoft attribute block cannot be empty">; - } // end of Parse Issue category. let CategoryName = "Modules Issue" in { @@ -1017,4 +1013,16 @@ def err_module_expected_semi : Error< "expected ';' after module name">; } +let CategoryName = "Generics Issue" in { + +def err_objc_expected_type_parameter : Error< + "expected type parameter name">; + +def err_objc_parameterized_implementation : Error< + "@implementation cannot have type parameters">; + +def err_objc_type_args_after_protocols : Error< + "protocol qualifiers must precede type arguments">; +} + } // end of Parser diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 750219483c6c..fb1e3f1cb46e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -188,6 +188,8 @@ def ext_flexible_array_init : Extension< "flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>; // Declarations. +def err_redeclaration_different_type : Error< + "redeclaration of %0 with a different type%diff{: $ vs $|}1,2">; def err_bad_variable_name : Error< "%0 cannot be the name of a variable or data member">; def err_bad_parameter_name : Error< @@ -978,6 +980,12 @@ def warning_multiple_selectors: Warning< "several methods with selector %0 of mismatched types are found " "for the @selector expression">, InGroup<SelectorTypeMismatch>, DefaultIgnore; + +def err_objc_kindof_nonobject : Error< + "'__kindof' specifier cannot be applied to non-object type %0">; +def err_objc_kindof_wrong_position : Error< + "'__kindof' type specifier must precede the declarator">; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; @@ -2131,6 +2139,11 @@ def warn_concatenated_nsarray_literal : Warning< InGroup<ObjCStringConcatenation>; def note_objc_literal_comparison_isequal : Note< "use 'isEqual:' instead">; +def warn_objc_collection_literal_element : Warning< + "object of type %0 is not compatible with " + "%select{array element type|dictionary key type|dictionary value type}1 %2">, + InGroup<ObjCLiteralConversion>; + def err_attribute_argument_is_zero : Error< "%0 attribute must be greater than 0">; def warn_attribute_argument_n_negative : Warning< @@ -2148,6 +2161,10 @@ def warn_objc_redundant_literal_use : Warning< def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">; +def err_tls_var_aligned_over_maximum : Error< + "alignment (%0) of thread-local variable %1 is greater than the maximum supported " + "alignment (%2) for a thread-local variable on this target">; + def err_only_annotate_after_access_spec : Error< "access specifier can only have annotation attributes">; @@ -4740,6 +4757,8 @@ def warn_division_by_zero : Warning<"division by zero is undefined">, InGroup<DivZero>; def warn_remainder_by_zero : Warning<"remainder by zero is undefined">, InGroup<DivZero>; +def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">, + InGroup<DiagGroup<"shift-negative-value">>; def warn_shift_negative : Warning<"shift count is negative">, InGroup<DiagGroup<"shift-count-negative">>; def warn_shift_gt_typewidth : Warning<"shift count >= width of type">, @@ -5576,6 +5595,8 @@ 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< "cannot use C++ 'try' in the same function as SEH '__try'">; +def err_seh_try_unsupported : Error< + "SEH '__try' is not supported on this target">; def note_conflicting_try_here : Note< "conflicting %0 here">; def warn_jump_out_of_seh_finally : Warning< @@ -7740,6 +7761,84 @@ def warn_nullability_missing : Warning< "type specifier (_Nonnull, _Nullable, or _Null_unspecified)">, InGroup<NullabilityCompleteness>; +def err_type_arg_explicit_nullability : Error< + "type argument %0 cannot explicitly specify nullability">; + +def err_type_param_bound_explicit_nullability : Error< + "type parameter %0 bound %1 cannot explicitly specify nullability">; + } +let CategoryName = "Generics Issue" in { + +def err_objc_type_param_bound_nonobject : Error< + "type bound %0 for type parameter %1 is not an Objective-C pointer type">; + +def err_objc_type_param_bound_missing_pointer : Error< + "missing '*' in type bound %0 for type parameter %1">; + +def err_objc_type_param_redecl : Error< + "redeclaration of type parameter %0">; + +def err_objc_type_param_arity_mismatch : Error< + "%select{forward class declaration|class definition|category|extension}0 has " + "too %select{few|many}1 type parameters (expected %2, have %3)">; + +def err_objc_type_param_bound_conflict : Error< + "type bound %0 for type parameter %1 conflicts with " + "%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">; + +def err_objc_type_param_variance_conflict : Error< + "%select{in|co|contra}0variant type parameter %1 conflicts with previous " + "%select{in|co|contra}2variant type parameter %3">; + +def note_objc_type_param_here : Note<"type parameter %0 declared here">; + +def err_objc_type_param_bound_missing : Error< + "missing type bound %0 for type parameter %1 in %select{@interface|@class}2">; + +def err_objc_parameterized_category_nonclass : Error< + "%select{extension|category}0 of non-parameterized class %1 cannot have type " + "parameters">; + +def err_objc_parameterized_forward_class : Error< + "forward declaration of non-parameterized class %0 cannot have type " + "parameters">; + +def err_objc_parameterized_forward_class_first : Error< + "class %0 previously declared with type parameters">; + +def err_objc_type_arg_missing_star : Error< + "type argument %0 must be a pointer (requires a '*')">; + +def err_objc_type_arg_missing : Error< + "no type or protocol named %0">; + +def err_objc_type_args_and_protocols : Error< + "angle brackets contain both a %select{type|protocol}0 (%1) and a " + "%select{protocol|type}0 (%2)">; + +def err_objc_type_args_non_class : Error< + "type arguments cannot be applied to non-class type %0">; + +def err_objc_type_args_non_parameterized_class : Error< + "type arguments cannot be applied to non-parameterized class %0">; + +def err_objc_type_args_specialized_class : Error< + "type arguments cannot be applied to already-specialized class type %0">; + +def err_objc_type_args_wrong_arity : Error< + "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">; +} + +def err_objc_type_arg_not_id_compatible : Error< + "type argument %0 is neither an Objective-C object nor a block type">; + +def err_objc_type_arg_does_not_match_bound : Error< + "type argument %0 does not satisfy the bound (%1) of type parameter %2">; + +def warn_objc_redundant_qualified_class_type : Warning< + "parameterized class %0 already conforms to the protocols listed; did you " + "forget a '*'?">, InGroup<ObjCProtocolQualifiers>; + } // end of sema component. diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 33a8b747c62d..1785e04b91ca 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -49,7 +49,7 @@ class IdentifierInfo { // Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf). // First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values // are for builtins. - unsigned ObjCOrBuiltinID :11; + unsigned ObjCOrBuiltinID :13; bool HasMacro : 1; // True if there is a #define for this. bool HadMacro : 1; // True if there was a #define for this. bool IsExtension : 1; // True if identifier is a lang extension. @@ -69,7 +69,7 @@ class IdentifierInfo { // stored externally. bool IsModulesImport : 1; // True if this is the 'import' contextual // keyword. - // 32-bit word is filled. + // 30 bit left in 64-bit word. void *FETokenInfo; // Managed by the language front-end. llvm::StringMapEntry<IdentifierInfo*> *Entry; diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index b27605b15d28..8d606a12d046 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -161,6 +161,7 @@ LANGOPT(NativeHalfType , 1, 0, "Native half type support") LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns") LANGOPT(CUDA , 1, 0, "CUDA") LANGOPT(OpenMP , 1, 0, "OpenMP support") +LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls") LANGOPT(CUDAIsDevice , 1, 0, "Compiling for CUDA device") LANGOPT(CUDAAllowHostCallsFromHostDevice, 1, 0, "Allow host device functions to call host functions") LANGOPT(CUDADisableTargetCallChecks, 1, 0, "Disable checks for call targets (host, device, etc.)") diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h index 78c1ddb56f9b..98e70dee45e5 100644 --- a/include/clang/Basic/Sanitizers.h +++ b/include/clang/Basic/Sanitizers.h @@ -17,8 +17,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" - -#include <stdint.h> +#include "llvm/Support/MathExtras.h" namespace clang { @@ -47,22 +46,28 @@ enum SanitizerOrdinal : uint64_t { } struct SanitizerSet { - SanitizerSet(); + SanitizerSet() : Mask(0) {} /// \brief Check if a certain (single) sanitizer is enabled. - bool has(SanitizerMask K) const; + bool has(SanitizerMask K) const { + assert(llvm::isPowerOf2_64(K)); + return Mask & K; + } /// \brief Check if one or more sanitizers are enabled. - bool hasOneOf(SanitizerMask K) const; + bool hasOneOf(SanitizerMask K) const { return Mask & K; } /// \brief Enable or disable a certain (single) sanitizer. - void set(SanitizerMask K, bool Value); + void set(SanitizerMask K, bool Value) { + assert(llvm::isPowerOf2_64(K)); + Mask = Value ? (Mask | K) : (Mask & ~K); + } /// \brief Disable all sanitizers. - void clear(); + void clear() { Mask = 0; } /// \brief Returns true if at least one sanitizer is enabled. - bool empty() const; + bool empty() const { return Mask == 0; } /// \brief Bitmask of enabled sanitizers. SanitizerMask Mask; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index a3bb535fa26f..39f575f90ef8 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -70,6 +70,7 @@ protected: unsigned char MinGlobalAlign; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; unsigned short MaxVectorAlign; + unsigned short MaxTLSAlign; unsigned short SimdDefaultAlign; const char *DescriptionString; const char *UserLabelPrefix; @@ -809,6 +810,21 @@ public: return TLSSupported; } + /// \brief Return the maximum alignment (in bits) of a TLS variable + /// + /// Gets the maximum alignment (in bits) of a TLS variable on this target. + /// Returns zero if there is no such constraint. + unsigned short getMaxTLSAlign() const { + return MaxTLSAlign; + } + + /// \brief Whether the target supports SEH __try. + bool isSEHTrySupported() const { + return getTriple().isOSWindows() && + (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64); + } + /// \brief Return true if {|} are normal characters in the asm string. /// /// If this returns false (the default), then {abc|xyz} is syntax diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index ed2aa82d17e1..7a91c9f502b7 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -526,6 +526,11 @@ KEYWORD(__bridge_transfer , KEYARC) KEYWORD(__bridge_retained , KEYARC) KEYWORD(__bridge_retain , KEYARC) +// Objective-C keywords. +KEYWORD(__covariant , KEYOBJC2) +KEYWORD(__contravariant , KEYOBJC2) +KEYWORD(__kindof , KEYOBJC2) + // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. ALIAS("__alignof__" , __alignof , KEYALL) diff --git a/include/clang/CodeGen/ObjectFilePCHContainerOperations.h b/include/clang/CodeGen/ObjectFilePCHContainerOperations.h new file mode 100644 index 000000000000..4540efb29781 --- /dev/null +++ b/include/clang/CodeGen/ObjectFilePCHContainerOperations.h @@ -0,0 +1,43 @@ +//===-- CodeGen/ObjectFilePCHContainerOperations.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_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H +#define LLVM_CLANG_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H + +#include "clang/Frontend/PCHContainerOperations.h" + +namespace clang { + +/// \brief A PCHContainerOperations implementation that uses LLVM to +/// wraps Clang modules inside a COFF, ELF, or Mach-O container. +class ObjectFilePCHContainerOperations + : public PCHContainerOperations { + /// \brief Return an ASTConsumer that can be chained with a + /// PCHGenerator that produces a wrapper file format + /// that also contains full debug info for the module. + std::unique_ptr<ASTConsumer> + CreatePCHContainerGenerator( + DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO, + const PreprocessorOptions &PPO, const TargetOptions &TO, + const LangOptions &LO, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const override; + + /// \brief Initialize an llvm::BitstreamReader with the serialized + /// AST inside the PCH container Buffer. + void ExtractPCH(llvm::MemoryBufferRef Buffer, + llvm::BitstreamReader &StreamFile) const override; + + +}; + +} + + +#endif diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index dd0261c2f3a1..fddd15885e18 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -41,6 +41,8 @@ public: enum ActionClass { InputClass = 0, BindArchClass, + CudaDeviceClass, + CudaHostClass, PreprocessJobClass, PrecompileJobClass, AnalyzeJobClass, @@ -71,16 +73,16 @@ private: unsigned OwnsInputs : 1; protected: - Action(ActionClass _Kind, types::ID _Type) - : Kind(_Kind), Type(_Type), OwnsInputs(true) {} - Action(ActionClass _Kind, std::unique_ptr<Action> Input, types::ID _Type) - : Kind(_Kind), Type(_Type), Inputs(1, Input.release()), OwnsInputs(true) { + Action(ActionClass Kind, types::ID Type) + : Kind(Kind), Type(Type), OwnsInputs(true) {} + Action(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type) + : Kind(Kind), Type(Type), Inputs(1, Input.release()), OwnsInputs(true) { } - Action(ActionClass _Kind, std::unique_ptr<Action> Input) - : Kind(_Kind), Type(Input->getType()), Inputs(1, Input.release()), + Action(ActionClass Kind, std::unique_ptr<Action> Input) + : Kind(Kind), Type(Input->getType()), Inputs(1, Input.release()), OwnsInputs(true) {} - Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) - : Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {} + Action(ActionClass Kind, const ActionList &Inputs, types::ID Type) + : Kind(Kind), Type(Type), Inputs(Inputs), OwnsInputs(true) {} public: virtual ~Action(); @@ -108,7 +110,7 @@ class InputAction : public Action { const llvm::opt::Arg &Input; public: - InputAction(const llvm::opt::Arg &_Input, types::ID _Type); + InputAction(const llvm::opt::Arg &Input, types::ID Type); const llvm::opt::Arg &getInputArg() const { return Input; } @@ -124,7 +126,7 @@ class BindArchAction : public Action { const char *ArchName; public: - BindArchAction(std::unique_ptr<Action> Input, const char *_ArchName); + BindArchAction(std::unique_ptr<Action> Input, const char *ArchName); const char *getArchName() const { return ArchName; } @@ -133,6 +135,41 @@ public: } }; +class CudaDeviceAction : public Action { + virtual void anchor(); + /// GPU architecture to bind -- e.g 'sm_35'. + const char *GpuArchName; + /// True when action results are not consumed by the host action (e.g when + /// -fsyntax-only or --cuda-device-only options are used). + bool AtTopLevel; + +public: + CudaDeviceAction(std::unique_ptr<Action> Input, const char *ArchName, + bool AtTopLevel); + + const char *getGpuArchName() const { return GpuArchName; } + bool isAtTopLevel() const { return AtTopLevel; } + + static bool classof(const Action *A) { + return A->getKind() == CudaDeviceClass; + } +}; + +class CudaHostAction : public Action { + virtual void anchor(); + ActionList DeviceActions; + +public: + CudaHostAction(std::unique_ptr<Action> Input, + const ActionList &DeviceActions); + ~CudaHostAction() override; + + ActionList &getDeviceActions() { return DeviceActions; } + const ActionList &getDeviceActions() const { return DeviceActions; } + + static bool classof(const Action *A) { return A->getKind() == CudaHostClass; } +}; + class JobAction : public Action { virtual void anchor(); protected: diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index cf6b76bf29f2..907b16fd5caf 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -188,7 +188,7 @@ def _SLASH_EP : CLFlag<"EP">, def _SLASH_FA : CLFlag<"FA">, HelpText<"Output assembly code file during compilation">; def _SLASH_Fa : CLJoined<"Fa">, - HelpText<"Output assembly code to this file during compilation">, + HelpText<"Output assembly code to this file during compilation (with /FA)">, MetaVarName<"<file or directory>">; def _SLASH_fallback : CLCompileFlag<"fallback">, HelpText<"Fall back to cl.exe if clang-cl fails to compile">; @@ -198,10 +198,10 @@ def _SLASH_Fe : CLJoined<"Fe">, HelpText<"Set output executable file or directory (ends in / or \\)">, MetaVarName<"<file or directory>">; def _SLASH_Fi : CLCompileJoined<"Fi">, - HelpText<"Set preprocess output file name">, + HelpText<"Set preprocess output file name (with /P)">, MetaVarName<"<file>">; def _SLASH_Fo : CLCompileJoined<"Fo">, - HelpText<"Set output object file, or directory (ends in / or \\)">, + HelpText<"Set output object file, or directory (ends in / or \\) (with /c)">, MetaVarName<"<file or directory>">; def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">; def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">; diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 15c194b09848..4a67fdb6532a 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -405,12 +405,12 @@ public: bool IsUsingLTO(const llvm::opt::ArgList &Args) const; private: - /// \brief Retrieves a ToolChain for a particular target triple. + /// \brief Retrieves a ToolChain for a particular \p Target triple. /// /// Will cache ToolChains for the life of the driver object, and create them /// on-demand. const ToolChain &getToolChain(const llvm::opt::ArgList &Args, - StringRef DarwinArchName = "") const; + const llvm::Triple &Target) const; /// @} diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index 8fc2e8d3a5b9..186244bacf31 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -106,6 +106,9 @@ public: const char *getExecutable() const { return Executable; } const llvm::opt::ArgStringList &getArguments() const { return Arguments; } + + /// Print a command argument, and optionally quote it. + static void printArg(llvm::raw_ostream &OS, const char *Arg, bool Quote); }; /// Like Command, but with a fallback which is executed in case diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 6a75b7c2c157..6e5dbf225bb6 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -351,6 +351,12 @@ def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>, MetaVarName<"<directory>">; def c : Flag<["-"], "c">, Flags<[DriverOption]>, HelpText<"Only run preprocess, compile, and assemble steps">; +def cuda_device_only : Flag<["--"], "cuda-device-only">, + HelpText<"Do device-side CUDA compilation only">; +def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, + Flags<[DriverOption, HelpHidden]>, HelpText<"CUDA GPU architecture">; +def cuda_host_only : Flag<["--"], "cuda-host-only">, + HelpText<"Do host-side CUDA compilation only">; def dA : Flag<["-"], "dA">, Group<d_Group>; def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>, HelpText<"Print macro definitions in -E mode in addition to normal output">; @@ -422,13 +428,24 @@ def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">, Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<file>">, HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">; -def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>; +def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>, + Flags<[DriverOption]>; def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use instrumentation data for profile-guided optimization">; def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Generate coverage mapping to enable code coverage analysis">; +def fprofile_generate : Flag<["-"], "fprofile-generate">, + Alias<fprofile_instr_generate>; +def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">, + HelpText<"Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">; +def fprofile_use : Flag<["-"], "fprofile-use">, Group<f_Group>, + Alias<fprofile_instr_use>; +def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<pathname>">, + HelpText<"Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profdata. Otherwise, it reads from file <pathname>.">; def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable the 'blocks' language feature">; @@ -522,7 +539,8 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>, 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>; +def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>, + Flags<[CoreOption]>; def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">, Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Path to blacklist file for sanitizers">; @@ -547,24 +565,29 @@ def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">, Group<f_clang_Group>, Flags<[CC1Option]>, HelpText<"Disable origins tracking in MemorySanitizer">; +def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">, + Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable use-after-destroy detection in MemorySanitizer">; def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">, Group<f_clang_Group>, Flags<[CC1Option]>, HelpText<"Level of field padding for AddressSanitizer">; -def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>; +def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>, + Flags<[CoreOption]>; def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, - Group<f_clang_Group>; + Group<f_clang_Group>, Flags<[CoreOption]>; def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">, Group<f_clang_Group>, - Flags<[CC1Option]>, + Flags<[CC1Option, CoreOption]>, HelpText<"Enable recovery for specified sanitizers">; def fno_sanitize_recover_EQ : CommaJoined<["-"], "fno-sanitize-recover=">, - Group<f_clang_Group>, + Group<f_clang_Group>, Flags<[CoreOption]>, 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]>, HelpText<"Disable trapping for specified sanitizers">; def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, Group<f_clang_Group>; @@ -641,7 +664,7 @@ 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=">, Group<clang_ignored_gcc_optimization_f_Group>; -def flto : Flag<["-"], "flto">, Group<f_Group>; +def flto : Flag<["-"], "flto">, Flags<[CC1Option]>, Group<f_Group>; def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group<f_Group>, Flags<[DriverOption, CoreOption]>; @@ -879,6 +902,8 @@ def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>; def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>; def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>; +def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; 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">; @@ -904,7 +929,6 @@ def fpie : Flag<["-"], "fpie">, Group<f_Group>; def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>; def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>; def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>; -def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>; def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>; def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, Flags<[CC1Option]>, @@ -1518,7 +1542,8 @@ def print_libgcc_file_name : Flag<["-", "--"], "print-libgcc-file-name">, HelpText<"Print the library path for \"libgcc.a\"">; def print_multi_directory : Flag<["-", "--"], "print-multi-directory">; def print_multi_lib : Flag<["-", "--"], "print-multi-lib">; -def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">; +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_search_dirs : Flag<["-", "--"], "print-search-dirs">, @@ -1527,6 +1552,7 @@ def private__bundle : Flag<["-"], "private_bundle">; def pthreads : Flag<["-"], "pthreads">; def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>, HelpText<"Support POSIX threads in generated code">; +def no_pthread : Flag<["-"], "no-pthread">, Flags<[CC1Option]>; def p : Flag<["-"], "p">; def pie : Flag<["-"], "pie">; def read__only__relocs : Separate<["-"], "read_only_relocs">; @@ -1793,8 +1819,6 @@ defm : BooleanFFlag<"keep-inline-functions">, Group<clang_ignored_gcc_optimizati def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>; -defm profile_use : BooleanFFlag<"profile-use">, Group<clang_ignored_gcc_optimization_f_Group>; -def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group<clang_ignored_gcc_optimization_f_Group>; def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>; defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>; diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h index 11bfd417e1ea..82b668ac883a 100644 --- a/include/clang/Driver/SanitizerArgs.h +++ b/include/clang/Driver/SanitizerArgs.h @@ -29,6 +29,7 @@ class SanitizerArgs { std::vector<std::string> BlacklistFiles; int CoverageFeatures; int MsanTrackOrigins; + bool MsanUseAfterDtor; int AsanFieldPadding; bool AsanZeroBaseShadow; bool AsanSharedRuntime; diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index 4b696ae5e053..d1b69151b062 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -44,6 +44,7 @@ TYPE("c", C, PP_C, "c", "u") TYPE("cl", CL, PP_C, "cl", "u") TYPE("cuda-cpp-output", PP_CUDA, INVALID, "cui", "u") TYPE("cuda", CUDA, PP_CUDA, "cu", "u") +TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", "") TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u") TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u") TYPE("objective-c", ObjC, PP_ObjC, "m", "u") diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h index 34442eb6379f..dd95d6599156 100644 --- a/include/clang/Driver/Types.h +++ b/include/clang/Driver/Types.h @@ -63,6 +63,9 @@ namespace types { /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers). bool isCXX(ID Id); + /// isCuda - Is this a CUDA input. + bool isCuda(ID Id); + /// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers). bool isObjC(ID Id); diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 6f9523cdc1ba..f8c8c373e143 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -166,6 +166,9 @@ struct FormatStyle { /// Like \c Attach, but break before braces on function, namespace and /// class definitions. BS_Linux, + /// Like ``Attach``, but break before braces on enum, function, and record + /// definitions. + BS_Mozilla, /// Like \c Attach, but break before function definitions, and 'else'. BS_Stroustrup, /// Always break before braces. @@ -290,6 +293,12 @@ struct FormatStyle { /// \brief Language, this format style is targeted at. LanguageKind Language; + /// \brief A regular expression matching macros that start a block. + 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. unsigned MaxEmptyLinesToKeep; @@ -479,6 +488,8 @@ struct FormatStyle { IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && KeepEmptyLinesAtTheStartOfBlocks == R.KeepEmptyLinesAtTheStartOfBlocks && + MacroBlockBegin == R.MacroBlockBegin && + MacroBlockEnd == R.MacroBlockEnd && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && NamespaceIndentation == R.NamespaceIndentation && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index d34cf0cad1c9..803d0233046d 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -67,6 +67,8 @@ CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to ///< be generated. +CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the + ///< compile step. CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants. CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled. CODEGENOPT(MSVolatile , 1, 0) ///< Set when /volatile:ms is enabled. @@ -110,6 +112,8 @@ CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero ///< offset in AddressSanitizer. CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in ///< MemorySanitizer +CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection + ///< in MemorySanitizer CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage ///< instrumentation. CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index 66597bd0af8e..53246bcf22c1 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -155,6 +155,7 @@ public: std::vector<std::string> DependentLibraries; /// Name of the profile file to use as output for -fprofile-instr-generate + /// and -fprofile-generate. std::string InstrProfileOutput; /// Name of the profile file to use with -fprofile-sample-use. diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 9cd806c99b85..2f3e1b6cebb1 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -30,6 +30,7 @@ namespace llvm { class raw_fd_ostream; class Timer; +class TimerGroup; } namespace clang { @@ -101,7 +102,10 @@ class CompilerInstance : public ModuleLoader { /// \brief The semantic analysis object. std::unique_ptr<Sema> TheSema; - /// \brief The frontend timer + /// \brief The frontend timer group. + std::unique_ptr<llvm::TimerGroup> FrontendTimerGroup; + + /// \brief The frontend timer. std::unique_ptr<llvm::Timer> FrontendTimer; /// \brief The ASTReader, if one exists. @@ -157,9 +161,10 @@ class CompilerInstance : public ModuleLoader { std::string TempFilename; std::unique_ptr<raw_ostream> OS; - OutputFile(const std::string &filename, const std::string &tempFilename, + OutputFile(std::string filename, std::string tempFilename, std::unique_ptr<raw_ostream> OS) - : Filename(filename), TempFilename(tempFilename), OS(std::move(OS)) {} + : Filename(std::move(filename)), TempFilename(std::move(tempFilename)), + OS(std::move(OS)) {} OutputFile(OutputFile &&O) : Filename(std::move(O.Filename)), TempFilename(std::move(O.TempFilename)), OS(std::move(O.OS)) {} @@ -614,7 +619,7 @@ public: /// /// \return - The new object on success, or null on failure. static IntrusiveRefCntPtr<ASTReader> createPCHExternalASTSource( - StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + StringRef Path, StringRef Sysroot, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerOperations &PCHContainerOps, void *DeserializationListener, bool OwnDeserializationListener, @@ -627,11 +632,9 @@ public: /// Create a code completion consumer to print code completion results, at /// \p Filename, \p Line, and \p Column, to the given output stream \p OS. - static CodeCompleteConsumer * - createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, - unsigned Line, unsigned Column, - const CodeCompleteOptions &Opts, - raw_ostream &OS); + static CodeCompleteConsumer *createCodeCompletionConsumer( + Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column, + const CodeCompleteOptions &Opts, raw_ostream &OS); /// \brief Create the Sema object to be used for parsing. void createSema(TranslationUnitKind TUKind, diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 2b18a7df53dd..0b03c4aa1cd7 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -452,9 +452,13 @@ public: /// \param HomeDir The directory in which relative paths within this module /// map file will be resolved. /// + /// \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, + SourceLocation ExternModuleLoc = SourceLocation()); /// \brief Dump the contents of the module map, for debugging purposes. void dump(); diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index bba0c38cec77..b2f58ead0e75 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -786,6 +786,22 @@ public: (!getLangOpts().Modules || (bool)getMacroDefinition(II)); } + /// \brief Determine whether II is defined as a macro within the module M, + /// if that is a module that we've already preprocessed. Does not check for + /// macros imported into M. + bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) { + if (!II->hasMacroDefinition()) + return false; + auto I = Submodules.find(M); + if (I == Submodules.end()) + return false; + auto J = I->second.Macros.find(II); + if (J == I->second.Macros.end()) + return false; + auto *MD = J->second.getLatest(); + return MD && MD->isDefined(); + } + MacroDefinition getMacroDefinition(const IdentifierInfo *II) { if (!II->hasMacroDefinition()) return MacroDefinition(); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 97a0aa482d2b..fb9eb8ff5af8 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -46,6 +46,8 @@ namespace clang { class PoisonSEHIdentifiersRAIIObject; class VersionTuple; class OMPClause; + class ObjCTypeParamList; + class ObjCTypeParameter; /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has @@ -1246,6 +1248,13 @@ private: DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParsedAttributes &prefixAttrs); + ObjCTypeParamList *parseObjCTypeParamList(); + ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs( + SourceLocation &lAngleLoc, + SmallVectorImpl<IdentifierLocPair> &protocolIdents, + SourceLocation &rAngleLoc, + bool mayBeProtocolList = true); + void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls, @@ -1258,8 +1267,48 @@ private: bool WarnOnDeclarations, bool ForObjCContainer, SourceLocation &LAngleLoc, - SourceLocation &EndProtoLoc); - bool ParseObjCProtocolQualifiers(DeclSpec &DS); + SourceLocation &EndProtoLoc, + bool consumeLastToken); + + /// Parse the first angle-bracket-delimited clause for an + /// Objective-C object or object pointer type, which may be either + /// type arguments or protocol qualifiers. + void parseObjCTypeArgsOrProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken, + bool warnOnIncompleteProtocols); + + /// Parse either Objective-C type arguments or protocol qualifiers; if the + /// former, also parse protocol qualifiers afterward. + void parseObjCTypeArgsAndProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken); + + /// Parse a protocol qualifier type such as '<NSCopying>', which is + /// an anachronistic way of writing 'id<NSCopying>'. + TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc); + + /// Parse Objective-C type arguments and protocol qualifiers, extending the + /// current type with the parsed result. + TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc, + ParsedType type, + bool consumeLastToken, + SourceLocation &endLoc); + void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Decl *CDecl); DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, @@ -2469,7 +2518,8 @@ private: typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList; bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, - bool ConsumeLastToken); + bool ConsumeLastToken, + bool ObjCGenericList); bool ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, const CXXScopeSpec &SS, diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index de65c43c76b2..97022738d03e 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -765,11 +765,13 @@ public: /// \param Allocator The allocator that will be used to allocate the /// string itself. CodeCompletionString *CreateCodeCompletionString(Sema &S, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments); CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx, Preprocessor &PP, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments); diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index d375ec303785..41d490063299 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -373,14 +373,6 @@ private: // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; - // List of protocol qualifiers for objective-c classes. Used for - // protocol-qualified interfaces "NString<foo>" and protocol-qualified id - // "id<foo>". - Decl * const *ProtocolQualifiers; - unsigned NumProtocolQualifiers; - SourceLocation ProtocolLAngleLoc; - SourceLocation *ProtocolLocs; - // SourceLocation info. These are null if the item wasn't specified or if // the setting was synthesized. SourceRange Range; @@ -442,16 +434,10 @@ public: Constexpr_specified(false), Concept_specified(false), Attrs(attrFactory), - ProtocolQualifiers(nullptr), - NumProtocolQualifiers(0), - ProtocolLocs(nullptr), writtenBS(), ObjCQualifiers(nullptr) { } - ~DeclSpec() { - delete [] ProtocolQualifiers; - delete [] ProtocolLocs; - } + // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } TSCS getThreadStorageClassSpec() const { @@ -490,6 +476,8 @@ public: bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } bool isTypeAltiVecBool() const { return TypeAltiVecBool; } bool isTypeSpecOwned() const { return TypeSpecOwned; } + bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + ParsedType getRepAsType() const { assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); return TypeRep; @@ -751,19 +739,6 @@ public: Attrs.takeAllFrom(attrs); } - typedef Decl * const *ProtocolQualifierListTy; - ProtocolQualifierListTy getProtocolQualifiers() const { - return ProtocolQualifiers; - } - SourceLocation *getProtocolLocs() const { return ProtocolLocs; } - unsigned getNumProtocolQualifiers() const { - return NumProtocolQualifiers; - } - SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; } - void setProtocolQualifiers(Decl * const *Protos, unsigned NP, - SourceLocation *ProtoLocs, - SourceLocation LAngleLoc); - /// Finish - This does final analysis of the declspec, issuing diagnostics for /// things like "_Imaginary" (lacking an FP type). After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 72a0e0b19e3d..db7b6f954c1b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1387,7 +1387,8 @@ public: /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. - bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested); + bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete = false); bool hasVisibleDefinition(const NamedDecl *D) { NamedDecl *Hidden; return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden); @@ -1848,7 +1849,7 @@ public: bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, - const IdentifierInfo &Name); + const IdentifierInfo *Name); enum TagUseKind { TUK_Reference, // Reference to a tag: 'struct foo *X;' @@ -2187,6 +2188,7 @@ public: void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); + void maybeExtendBlockObject(ExprResult &E); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, @@ -7088,16 +7090,44 @@ public: }; ObjCContainerKind getObjCContainerKind() const; - Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + DeclResult actOnObjCTypeParam(Scope *S, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + IdentifierInfo *paramName, + SourceLocation paramLoc, + SourceLocation colonLoc, + ParsedType typeBound); + + ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, + ArrayRef<Decl *> typeParams, + SourceLocation rAngleLoc); + void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); + + Decl *ActOnStartClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); + + void ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, IdentifierInfo *SuperName, @@ -7124,6 +7154,7 @@ public: Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, @@ -7147,9 +7178,10 @@ public: ArrayRef<Decl *> Decls); DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, - IdentifierInfo **IdentList, - SourceLocation *IdentLocs, - unsigned NumElts); + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + ArrayRef<ObjCTypeParamList *> TypeParamLists, + unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, const IdentifierLocPair *IdentList, @@ -7161,6 +7193,61 @@ public: unsigned NumProtocols, SmallVectorImpl<Decl *> &Protocols); + /// Given a list of identifiers (and their locations), resolve the + /// names to either Objective-C protocol qualifiers or type + /// arguments, as appropriate. + void actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + ParsedType baseType, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SourceLocation &protocolRAngleLoc, + bool warnOnIncompleteProtocols); + + /// Build a an Objective-C protocol-qualified 'id' type where no + /// base type was specified. + TypeResult actOnObjCProtocolQualifierType( + SourceLocation lAngleLoc, + ArrayRef<Decl *> protocols, + ArrayRef<SourceLocation> protocolLocs, + SourceLocation rAngleLoc); + + /// Build a specialized and/or protocol-qualified Objective-C type. + TypeResult actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<ParsedType> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<Decl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// Build an Objective-C object pointer type. + QualType BuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError = false); + + /// Check the application of the Objective-C '__kindof' qualifier to + /// the given type. + bool checkObjCKindOfType(QualType &type, SourceLocation loc); + /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. @@ -7610,13 +7697,13 @@ private: void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind); - /// \brief Checks if the specified variable is used in one of the private +public: + /// \brief Check if the specified variable is used in a private clause in + /// Checks if the specified variable is used in one of the private /// clauses in OpenMP constructs. bool IsOpenMPCapturedVar(VarDecl *VD); -public: - /// \brief Check if the specified variable is used in one of the private - /// clauses in OpenMP constructs. + /// OpenMP constructs. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level); diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index b822b11126ea..416ef7b1a682 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -413,6 +413,7 @@ namespace clang { #define LINKAGESPEC(DERIVED, BASE) #define OBJCCOMPATIBLEALIAS(DERIVED, BASE) #define OBJCMETHOD(DERIVED, BASE) +#define OBJCTYPEPARAM(DERIVED, BASE) #define OBJCIVAR(DERIVED, BASE) #define OBJCPROPERTY(DERIVED, BASE) #define OBJCPROPERTYIMPL(DERIVED, BASE) diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index ee8e3f4c6712..4b662077c3c8 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1105,7 +1105,9 @@ namespace clang { /// \brief An OMPThreadPrivateDecl record. DECL_OMP_THREADPRIVATE, /// \brief An EmptyDecl record. - DECL_EMPTY + DECL_EMPTY, + /// \brief An ObjCTypeParamDecl record. + DECL_OBJC_TYPE_PARAM, }; /// \brief Record codes for each kind of statement or expression. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index ef5b107a2fda..9377dfac99cc 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -42,6 +42,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Timer.h" #include <deque> #include <map> #include <memory> @@ -380,6 +381,9 @@ private: /// \brief The module manager which manages modules and their dependencies ModuleManager ModuleMgr; + /// \brief A timer used to track the time spent deserializing. + std::unique_ptr<llvm::Timer> ReadTimer; + /// \brief The location where the module file will be considered as /// imported from. For non-module AST types it should be invalid. SourceLocation CurrentImportLoc; @@ -976,12 +980,14 @@ private: MergedLookups; typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> > - MergedDeclsMap; + KeyDeclsMap; - /// \brief A mapping from canonical declarations to the set of additional - /// (global, previously-canonical) declaration IDs that have been merged with - /// that canonical declaration. - MergedDeclsMap MergedDecls; + /// \brief A mapping from canonical declarations to the set of global + /// declaration IDs for key declaration that have been merged with that + /// canonical declaration. A key declaration is a formerly-canonical + /// declaration whose module did not import any other key declaration for that + /// entity. These are the IDs that we use as keys when finding redecl chains. + KeyDeclsMap KeyDecls; /// \brief A mapping from DeclContexts to the semantic DeclContext that we /// are treating as the definition of the entity. This is used, for instance, @@ -1054,6 +1060,36 @@ public: void ResolveImportedPath(ModuleFile &M, std::string &Filename); static void ResolveImportedPath(std::string &Filename, StringRef Prefix); + /// \brief Returns the first key declaration for the given declaration. This + /// is one that is formerly-canonical (or still canonical) and whose module + /// did not import any other key declaration of the entity. + Decl *getKeyDeclaration(Decl *D) { + D = D->getCanonicalDecl(); + if (D->isFromASTFile()) + return D; + + auto I = KeyDecls.find(D); + if (I == KeyDecls.end() || I->second.empty()) + return D; + return GetExistingDecl(I->second[0]); + } + const Decl *getKeyDeclaration(const Decl *D) { + return getKeyDeclaration(const_cast<Decl*>(D)); + } + + /// \brief Run a callback on each imported key declaration of \p D. + template <typename Fn> + void forEachImportedKeyDecl(const Decl *D, Fn Visit) { + D = D->getCanonicalDecl(); + if (D->isFromASTFile()) + Visit(D); + + auto It = KeyDecls.find(const_cast<Decl*>(D)); + if (It != KeyDecls.end()) + for (auto ID : It->second) + Visit(GetExistingDecl(ID)); + } + private: struct ImportedModule { ModuleFile *Mod; @@ -1124,18 +1160,6 @@ private: /// merged into its redecl chain. Decl *getMostRecentExistingDecl(Decl *D); - template <typename Fn> - void forEachFormerlyCanonicalImportedDecl(const Decl *D, Fn Visit) { - D = D->getCanonicalDecl(); - if (D->isFromASTFile()) - Visit(D); - - auto It = MergedDecls.find(const_cast<Decl*>(D)); - if (It != MergedDecls.end()) - for (auto ID : It->second) - Visit(GetExistingDecl(ID)); - } - RecordLocation DeclCursorForID(serialization::DeclID ID, unsigned &RawLocation); void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); @@ -1261,12 +1285,16 @@ public: /// /// \param UseGlobalIndex If true, the AST reader will try to load and use /// the global module index. + /// + /// \param ReadTimer If non-null, a timer used to track the time spent + /// deserializing. ASTReader(Preprocessor &PP, ASTContext &Context, const PCHContainerOperations &PCHContainerOps, StringRef isysroot = "", bool DisableValidation = false, bool AllowASTWithCompilerErrors = false, bool AllowConfigurationMismatch = false, - bool ValidateSystemInputs = false, bool UseGlobalIndex = true); + bool ValidateSystemInputs = false, bool UseGlobalIndex = true, + std::unique_ptr<llvm::Timer> ReadTimer = {}); ~ASTReader() override; @@ -1690,7 +1718,7 @@ public: /// \brief Notify ASTReader that we started deserialization of /// a decl or type so until FinishedDeserializing is called there may be /// decls that are initializing. Must be paired with FinishedDeserializing. - void StartedDeserializing() override { ++NumCurrentElementsDeserializing; } + void StartedDeserializing() override; /// \brief Notify ASTReader that we finished the deserialization of /// a decl or type. Must be paired with StartedDeserializing. diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index c966d3edeb9f..e830fdcf8f20 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -398,7 +398,7 @@ private: /// \brief The set of declarations that may have redeclaration chains that /// need to be serialized. - llvm::SmallSetVector<Decl *, 4> Redeclarations; + llvm::SmallVector<const Decl *, 16> Redeclarations; /// \brief Statements that we've encountered while serializing a /// declaration or type. diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h index ca68a74fef96..c9724c08da2d 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h +++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -64,6 +64,9 @@ #endif namespace clang { +class DiagnosticsEngine; +class AnalyzerOptions; + namespace ento { class CheckerOptInfo; @@ -118,6 +121,10 @@ public: void initializeManager(CheckerManager &mgr, SmallVectorImpl<CheckerOptInfo> &opts) const; + /// Check if every option corresponds to a specific checker or package. + void validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const; + /// Prints the name and description of all checkers in this registry. /// This output is not intended to be machine-parseable. void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5a91f074c4e1..fb9630180dca 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1917,11 +1917,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, // We can use protocol_iterator here instead of // all_referenced_protocol_iterator since we are walking all categories. for (auto *Proto : OI->all_referenced_protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (auto *P : Proto->protocols()) { - Protocols.insert(P->getCanonicalDecl()); - CollectInheritedProtocols(P, Protocols); - } + CollectInheritedProtocols(Proto, Protocols); } // Categories of this Interface. @@ -1935,16 +1931,16 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { for (auto *Proto : OC->protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (const auto *P : Proto->protocols()) - CollectInheritedProtocols(P, Protocols); + CollectInheritedProtocols(Proto, Protocols); } } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (auto *Proto : OP->protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (const auto *P : Proto->protocols()) - CollectInheritedProtocols(P, Protocols); - } + // Insert the protocol. + if (!Protocols.insert( + const_cast<ObjCProtocolDecl *>(OP->getCanonicalDecl())).second) + return; + + for (auto *Proto : OP->protocols()) + CollectInheritedProtocols(Proto, Protocols); } } @@ -3618,45 +3614,89 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { - // If the base type is an interface and there aren't any protocols - // to add, then the interface type will do just fine. - if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) - return BaseType; + return getObjCObjectType(BaseType, { }, + llvm::makeArrayRef(Protocols, NumProtocols), + /*isKindOf=*/false); +} + +QualType ASTContext::getObjCObjectType( + QualType baseType, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) const { + // If the base type is an interface and there aren't any protocols or + // type arguments to add, then the interface type will do just fine. + if (typeArgs.empty() && protocols.empty() && !isKindOf && + isa<ObjCInterfaceType>(baseType)) + return baseType; // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; - ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); + ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf); void *InsertPos = nullptr; if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // Build the canonical type, which has the canonical base type and - // a sorted-and-uniqued list of protocols. - QualType Canonical; - bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); - if (!ProtocolsSorted || !BaseType.isCanonical()) { - if (!ProtocolsSorted) { - SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, - Protocols + NumProtocols); - unsigned UniqueCount = NumProtocols; - - SortAndUniqueProtocols(&Sorted[0], UniqueCount); - Canonical = getObjCObjectType(getCanonicalType(BaseType), - &Sorted[0], UniqueCount); + // Determine the type arguments to be used for canonicalization, + // which may be explicitly specified here or written on the base + // type. + ArrayRef<QualType> effectiveTypeArgs = typeArgs; + if (effectiveTypeArgs.empty()) { + if (auto baseObject = baseType->getAs<ObjCObjectType>()) + effectiveTypeArgs = baseObject->getTypeArgs(); + } + + // Build the canonical type, which has the canonical base type and a + // sorted-and-uniqued list of protocols and the type arguments + // canonicalized. + QualType canonical; + bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), + effectiveTypeArgs.end(), + [&](QualType type) { + return type.isCanonical(); + }); + bool protocolsSorted = areSortedAndUniqued(protocols.data(), + protocols.size()); + if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { + // Determine the canonical type arguments. + ArrayRef<QualType> canonTypeArgs; + SmallVector<QualType, 4> canonTypeArgsVec; + if (!typeArgsAreCanonical) { + canonTypeArgsVec.reserve(effectiveTypeArgs.size()); + for (auto typeArg : effectiveTypeArgs) + canonTypeArgsVec.push_back(getCanonicalType(typeArg)); + canonTypeArgs = canonTypeArgsVec; } else { - Canonical = getObjCObjectType(getCanonicalType(BaseType), - Protocols, NumProtocols); + canonTypeArgs = effectiveTypeArgs; } + ArrayRef<ObjCProtocolDecl *> canonProtocols; + SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec; + if (!protocolsSorted) { + canonProtocolsVec.insert(canonProtocolsVec.begin(), + protocols.begin(), + protocols.end()); + unsigned uniqueCount = protocols.size(); + SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount); + canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount); + } else { + canonProtocols = protocols; + } + + canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs, + canonProtocols, isKindOf); + // Regenerate InsertPos. ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } - unsigned Size = sizeof(ObjCObjectTypeImpl); - Size += NumProtocols * sizeof(ObjCProtocolDecl *); - void *Mem = Allocate(Size, TypeAlignment); + unsigned size = sizeof(ObjCObjectTypeImpl); + size += typeArgs.size() * sizeof(QualType); + size += protocols.size() * sizeof(ObjCProtocolDecl *); + void *mem = Allocate(size, TypeAlignment); ObjCObjectTypeImpl *T = - new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); + new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols, + isKindOf); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); @@ -5623,13 +5663,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::ObjCInterface: { // Ignore protocol qualifiers when mangling at this level. - T = T->castAs<ObjCObjectType>()->getBaseType(); - - // The assumption seems to be that this assert will succeed - // because nested levels will have filtered out 'id' and 'Class'. - const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>(); // @encode(class_name) - ObjCInterfaceDecl *OI = OIT->getDecl(); + ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface(); S += '{'; S += OI->getObjCRuntimeNameAsString(); S += '='; @@ -5921,7 +5956,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, TypedefDecl *ASTContext::getObjCIdDecl() const { if (!ObjCIdDecl) { - QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { }); T = getObjCObjectPointerType(T); ObjCIdDecl = buildImplicitTypedef(T, "id"); } @@ -5938,7 +5973,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const { TypedefDecl *ASTContext::getObjCClassDecl() const { if (!ObjCClassDecl) { - QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { }); T = getObjCObjectPointerType(T); ObjCClassDecl = buildImplicitTypedef(T, "Class"); } @@ -5951,6 +5986,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const { = ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), &Idents.get("Protocol"), + /*typeParamList=*/nullptr, /*PrevDecl=*/nullptr, SourceLocation(), true); } @@ -6743,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, RHS->isObjCUnqualifiedIdOrClass()) return true; - if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) - return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0), - false); + // Function object that propagates a successful result or handles + // __kindof types. + auto finish = [&](bool succeeded) -> bool { + if (succeeded) + return true; + + if (!RHS->isKindOfType()) + return false; + + // Strip off __kindof and protocol qualifiers, then check whether + // we can assign the other way. + return canAssignObjCInterfaces(RHSOPT->stripObjCKindOfTypeAndQuals(*this), + LHSOPT->stripObjCKindOfTypeAndQuals(*this)); + }; + + if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) { + return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false)); + } - if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) - return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0)); + if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) { + return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0))); + } // If we have 2 user-defined types, fall into that path. - if (LHS->getInterface() && RHS->getInterface()) - return canAssignObjCInterfaces(LHS, RHS); + if (LHS->getInterface() && RHS->getInterface()) { + return finish(canAssignObjCInterfaces(LHS, RHS)); + } return false; } @@ -6768,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT, bool BlockReturnType) { + + // Function object that propagates a successful result or handles + // __kindof types. + auto finish = [&](bool succeeded) -> bool { + if (succeeded) + return true; + + const ObjCObjectPointerType *Expected = BlockReturnType ? RHSOPT : LHSOPT; + if (!Expected->isKindOfType()) + return false; + + // Strip off __kindof and protocol qualifiers, then check whether + // we can assign the other way. + return canAssignObjCInterfacesInBlockPointer( + RHSOPT->stripObjCKindOfTypeAndQuals(*this), + LHSOPT->stripObjCKindOfTypeAndQuals(*this), + BlockReturnType); + }; + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { - return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); + return finish(RHSOPT->isObjCBuiltinType() || + RHSOPT->isObjCQualifiedIdType()); } if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) - return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0), - false); + return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false)); const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); if (LHS && RHS) { // We have 2 user-defined types. if (LHS != RHS) { if (LHS->getDecl()->isSuperClassOf(RHS->getDecl())) - return BlockReturnType; + return finish(BlockReturnType); if (RHS->getDecl()->isSuperClassOf(LHS->getDecl())) - return !BlockReturnType; + return finish(!BlockReturnType); } else return true; @@ -6795,78 +6869,253 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( return false; } +/// Comparison routine for Objective-C protocols to be used with +/// llvm::array_pod_sort. +static int compareObjCProtocolsByName(ObjCProtocolDecl * const *lhs, + ObjCProtocolDecl * const *rhs) { + return (*lhs)->getName().compare((*rhs)->getName()); + +} + /// getIntersectionOfProtocols - This routine finds the intersection of set -/// of protocols inherited from two distinct objective-c pointer objects. +/// of protocols inherited from two distinct objective-c pointer objects with +/// the given common base. /// It is used to build composite qualifier list of the composite type of /// the conditional expression involving two objective-c pointer objects. static void getIntersectionOfProtocols(ASTContext &Context, + const ObjCInterfaceDecl *CommonBase, const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT, - SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + SmallVectorImpl<ObjCProtocolDecl *> &IntersectionSet) { const ObjCObjectType* LHS = LHSOPT->getObjectType(); const ObjCObjectType* RHS = RHSOPT->getObjectType(); assert(LHS->getInterface() && "LHS must have an interface base"); assert(RHS->getInterface() && "RHS must have an interface base"); - - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; - unsigned LHSNumProtocols = LHS->getNumProtocols(); - if (LHSNumProtocols > 0) - InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); - else { - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; - Context.CollectInheritedProtocols(LHS->getInterface(), - LHSInheritedProtocols); - InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), - LHSInheritedProtocols.end()); + + // Add all of the protocols for the LHS. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet; + + // Start with the protocol qualifiers. + for (auto proto : LHS->quals()) { + Context.CollectInheritedProtocols(proto, LHSProtocolSet); } - - unsigned RHSNumProtocols = RHS->getNumProtocols(); - if (RHSNumProtocols > 0) { - ObjCProtocolDecl **RHSProtocols = - const_cast<ObjCProtocolDecl **>(RHS->qual_begin()); - for (unsigned i = 0; i < RHSNumProtocols; ++i) - if (InheritedProtocolSet.count(RHSProtocols[i])) - IntersectionOfProtocols.push_back(RHSProtocols[i]); - } else { - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; - Context.CollectInheritedProtocols(RHS->getInterface(), - RHSInheritedProtocols); - for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols) - if (InheritedProtocolSet.count(ProtDecl)) - IntersectionOfProtocols.push_back(ProtDecl); + + // Also add the protocols associated with the LHS interface. + Context.CollectInheritedProtocols(LHS->getInterface(), LHSProtocolSet); + + // Add all of the protocls for the RHS. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet; + + // Start with the protocol qualifiers. + for (auto proto : RHS->quals()) { + Context.CollectInheritedProtocols(proto, RHSProtocolSet); + } + + // Also add the protocols associated with the RHS interface. + Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet); + + // Compute the intersection of the collected protocol sets. + for (auto proto : LHSProtocolSet) { + if (RHSProtocolSet.count(proto)) + IntersectionSet.push_back(proto); } + + // Compute the set of protocols that is implied by either the common type or + // the protocols within the intersection. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ImpliedProtocols; + Context.CollectInheritedProtocols(CommonBase, ImpliedProtocols); + + // Remove any implied protocols from the list of inherited protocols. + if (!ImpliedProtocols.empty()) { + IntersectionSet.erase( + std::remove_if(IntersectionSet.begin(), + IntersectionSet.end(), + [&](ObjCProtocolDecl *proto) -> bool { + return ImpliedProtocols.count(proto) > 0; + }), + IntersectionSet.end()); + } + + // Sort the remaining protocols by name. + llvm::array_pod_sort(IntersectionSet.begin(), IntersectionSet.end(), + compareObjCProtocolsByName); +} + +/// Determine whether the first type is a subtype of the second. +static bool canAssignObjCObjectTypes(ASTContext &ctx, QualType lhs, + QualType rhs) { + // Common case: two object pointers. + const ObjCObjectPointerType *lhsOPT = lhs->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + if (lhsOPT && rhsOPT) + return ctx.canAssignObjCInterfaces(lhsOPT, rhsOPT); + + // Two block pointers. + const BlockPointerType *lhsBlock = lhs->getAs<BlockPointerType>(); + const BlockPointerType *rhsBlock = rhs->getAs<BlockPointerType>(); + if (lhsBlock && rhsBlock) + return ctx.typesAreBlockPointerCompatible(lhs, rhs); + + // If either is an unqualified 'id' and the other is a block, it's + // acceptable. + if ((lhsOPT && lhsOPT->isObjCIdType() && rhsBlock) || + (rhsOPT && rhsOPT->isObjCIdType() && lhsBlock)) + return true; + + return false; +} + +// Check that the given Objective-C type argument lists are equivalent. +static bool sameObjCTypeArgs(ASTContext &ctx, + const ObjCInterfaceDecl *iface, + ArrayRef<QualType> lhsArgs, + ArrayRef<QualType> rhsArgs, + bool stripKindOf) { + if (lhsArgs.size() != rhsArgs.size()) + return false; + + ObjCTypeParamList *typeParams = iface->getTypeParamList(); + for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) { + if (ctx.hasSameType(lhsArgs[i], rhsArgs[i])) + continue; + + switch (typeParams->begin()[i]->getVariance()) { + case ObjCTypeParamVariance::Invariant: + if (!stripKindOf || + !ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx), + rhsArgs[i].stripObjCKindOfType(ctx))) { + return false; + } + break; + + case ObjCTypeParamVariance::Covariant: + if (!canAssignObjCObjectTypes(ctx, lhsArgs[i], rhsArgs[i])) + return false; + break; + + case ObjCTypeParamVariance::Contravariant: + if (!canAssignObjCObjectTypes(ctx, rhsArgs[i], lhsArgs[i])) + return false; + break; + } + } + + return true; } -/// areCommonBaseCompatible - Returns common base class of the two classes if -/// one found. Note that this is O'2 algorithm. But it will be called as the -/// last type comparison in a ?-exp of ObjC pointer types before a -/// warning is issued. So, its invokation is extremely rare. QualType ASTContext::areCommonBaseCompatible( - const ObjCObjectPointerType *Lptr, - const ObjCObjectPointerType *Rptr) { + const ObjCObjectPointerType *Lptr, + const ObjCObjectPointerType *Rptr) { const ObjCObjectType *LHS = Lptr->getObjectType(); const ObjCObjectType *RHS = Rptr->getObjectType(); const ObjCInterfaceDecl* LDecl = LHS->getInterface(); const ObjCInterfaceDecl* RDecl = RHS->getInterface(); - if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl))) + + if (!LDecl || !RDecl) return QualType(); - - do { - LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); - if (canAssignObjCInterfaces(LHS, RHS)) { + + // Follow the left-hand side up the class hierarchy until we either hit a + // root or find the RHS. Record the ancestors in case we don't find it. + llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4> + LHSAncestors; + while (true) { + // Record this ancestor. We'll need this if the common type isn't in the + // path from the LHS to the root. + LHSAncestors[LHS->getInterface()->getCanonicalDecl()] = LHS; + + if (declaresSameEntity(LHS->getInterface(), RDecl)) { + // Get the type arguments. + ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgsAsWritten(); + bool anyChanges = false; + if (LHS->isSpecialized() && RHS->isSpecialized()) { + // Both have type arguments, compare them. + if (!sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHS->getTypeArgs(), + /*stripKindOf=*/true)) + return QualType(); + } else if (LHS->isSpecialized() != RHS->isSpecialized()) { + // If only one has type arguments, the result will not have type + // arguments. + LHSTypeArgs = { }; + anyChanges = true; + } + + // Compute the intersection of protocols. SmallVector<ObjCProtocolDecl *, 8> Protocols; - getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); + getIntersectionOfProtocols(*this, LHS->getInterface(), Lptr, Rptr, + Protocols); + if (!Protocols.empty()) + anyChanges = true; + + // If anything in the LHS will have changed, build a new result type. + if (anyChanges) { + QualType Result = getObjCInterfaceType(LHS->getInterface()); + Result = getObjCObjectType(Result, LHSTypeArgs, Protocols, + LHS->isKindOfType()); + return getObjCObjectPointerType(Result); + } + + return getObjCObjectPointerType(QualType(LHS, 0)); + } + + // Find the superclass. + QualType LHSSuperType = LHS->getSuperClassType(); + if (LHSSuperType.isNull()) + break; - QualType Result = QualType(LHS, 0); + LHS = LHSSuperType->castAs<ObjCObjectType>(); + } + + // We didn't find anything by following the LHS to its root; now check + // the RHS against the cached set of ancestors. + while (true) { + auto KnownLHS = LHSAncestors.find(RHS->getInterface()->getCanonicalDecl()); + if (KnownLHS != LHSAncestors.end()) { + LHS = KnownLHS->second; + + // Get the type arguments. + ArrayRef<QualType> RHSTypeArgs = RHS->getTypeArgsAsWritten(); + bool anyChanges = false; + if (LHS->isSpecialized() && RHS->isSpecialized()) { + // Both have type arguments, compare them. + if (!sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHS->getTypeArgs(), + /*stripKindOf=*/true)) + return QualType(); + } else if (LHS->isSpecialized() != RHS->isSpecialized()) { + // If only one has type arguments, the result will not have type + // arguments. + RHSTypeArgs = { }; + anyChanges = true; + } + + // Compute the intersection of protocols. + SmallVector<ObjCProtocolDecl *, 8> Protocols; + getIntersectionOfProtocols(*this, RHS->getInterface(), Lptr, Rptr, + Protocols); if (!Protocols.empty()) - Result = getObjCObjectType(Result, Protocols.data(), Protocols.size()); - Result = getObjCObjectPointerType(Result); - return Result; + anyChanges = true; + + if (anyChanges) { + QualType Result = getObjCInterfaceType(RHS->getInterface()); + Result = getObjCObjectType(Result, RHSTypeArgs, Protocols, + RHS->isKindOfType()); + return getObjCObjectPointerType(Result); + } + + return getObjCObjectPointerType(QualType(RHS, 0)); } - } while ((LDecl = LDecl->getSuperClass())); - + + // Find the superclass of the RHS. + QualType RHSSuperType = RHS->getSuperClassType(); + if (RHSSuperType.isNull()) + break; + + RHS = RHSSuperType->castAs<ObjCObjectType>(); + } + return QualType(); } @@ -6877,21 +7126,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. - if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface())) + ObjCInterfaceDecl *LHSInterface = LHS->getInterface(); + bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface()); + if (!IsSuperClass) return false; - // RHS must have a superset of the protocols in the LHS. If the LHS is not - // protocol qualified at all, then we are good. - if (LHS->getNumProtocols() == 0) - return true; - - // Okay, we know the LHS has protocol qualifiers. But RHS may or may not. - // More detailed analysis is required. - // OK, if LHS is same or a superclass of RHS *and* - // this LHS, or as RHS's super class is assignment compatible with LHS. - bool IsSuperClass = - LHS->getInterface()->isSuperClassOf(RHS->getInterface()); - if (IsSuperClass) { + // If the LHS has protocol qualifiers, determine whether all of them are + // satisfied by the RHS (i.e., the RHS has a superset of the protocols in the + // LHS). + if (LHS->getNumProtocols() > 0) { // OK if conversion of LHS to SuperClass results in narrowing of types // ; i.e., SuperClass may implement at least one of the protocols // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. @@ -6901,7 +7144,7 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, // Also, if RHS has explicit quelifiers, include them for comparing with LHS's // qualifiers. for (auto *RHSPI : RHS->quals()) - SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl()); + CollectInheritedProtocols(RHSPI, SuperClassInheritedProtocols); // If there is no protocols associated with RHS, it is not a match. if (SuperClassInheritedProtocols.empty()) return false; @@ -6916,9 +7159,26 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, if (!SuperImplementsProtocol) return false; } - return true; } - return false; + + // If the LHS is specialized, we may need to check type arguments. + if (LHS->isSpecialized()) { + // Follow the superclass chain until we've matched the LHS class in the + // hierarchy. This substitutes type arguments through. + const ObjCObjectType *RHSSuper = RHS; + while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface)) + RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>(); + + // If the RHS is specializd, compare type arguments. + if (RHSSuper->isSpecialized() && + !sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHSSuper->getTypeArgs(), + /*stripKindOf=*/true)) { + return false; + } + } + + return true; } bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 000588face96..dddaa5af6fb0 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -125,12 +125,23 @@ break; \ if (const PointerType *Ty = QT->getAs<PointerType>()) { QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { + QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) { + if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) { + QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA); + QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(), + llvm::makeArrayRef(Ty->qual_begin(), + Ty->getNumProtocols()), + Ty->isKindOfTypeAsWritten()); + } } return QC.apply(Context, QT); @@ -181,8 +192,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, if (CompareCanTy == CanTy) continue; // Same canonical types std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy()); - bool aka; - QualType CompareDesugar = Desugar(Context, CompareTy, aka); + bool ShouldAKA = false; + QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA); std::string CompareDesugarStr = CompareDesugar.getAsString(Context.getPrintingPolicy()); if (CompareS != S && CompareDesugarStr != S) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 90da4167197a..c95922b141e0 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -240,6 +240,9 @@ namespace { void dumpTemplateArgument(const TemplateArgument &A, SourceRange R = SourceRange()); + // Objective-C utilities. + void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams); + // Types void VisitComplexType(const ComplexType *T) { dumpTypeAsChild(T->getElementType()); @@ -463,6 +466,7 @@ namespace { // ObjC Decls void VisitObjCIvarDecl(const ObjCIvarDecl *D); void VisitObjCMethodDecl(const ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); @@ -955,6 +959,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { } //===----------------------------------------------------------------------===// +// Objective-C Utilities +//===----------------------------------------------------------------------===// +void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { + if (!typeParams) + return; + + for (auto typeParam : *typeParams) { + dumpDecl(typeParam); + } +} + +//===----------------------------------------------------------------------===// // Decl dumping methods. //===----------------------------------------------------------------------===// @@ -1457,9 +1473,30 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { dumpStmt(D->getBody()); } +void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { + dumpName(D); + switch (D->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + + case ObjCTypeParamVariance::Covariant: + OS << " covariant"; + break; + + case ObjCTypeParamVariance::Contravariant: + OS << " contravariant"; + break; + } + + if (D->hasExplicitBound()) + OS << " bounded"; + dumpType(D->getUnderlyingType()); +} + void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); + dumpObjCTypeParamList(D->getTypeParamList()); dumpDeclRef(D->getImplementation()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); @@ -1482,6 +1519,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { dumpName(D); + dumpObjCTypeParamList(D->getTypeParamListAsWritten()); dumpDeclRef(D->getSuperClass(), "super"); dumpDeclRef(D->getImplementation()); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 76e4e1191501..35c0f690db82 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -150,9 +150,12 @@ namespace clang { Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); Decl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); + Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D); + + ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); @@ -1841,6 +1844,15 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { if (ToBaseType.isNull()) return QualType(); + SmallVector<QualType, 4> TypeArgs; + for (auto TypeArg : T->getTypeArgsAsWritten()) { + QualType ImportedTypeArg = Importer.Import(TypeArg); + if (ImportedTypeArg.isNull()) + return QualType(); + + TypeArgs.push_back(ImportedTypeArg); + } + SmallVector<ObjCProtocolDecl *, 4> Protocols; for (auto *P : T->quals()) { ObjCProtocolDecl *Protocol @@ -1850,9 +1862,9 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { Protocols.push_back(Protocol); } - return Importer.getToContext().getObjCObjectType(ToBaseType, - Protocols.data(), - Protocols.size()); + return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs, + Protocols, + T->isKindOfTypeAsWritten()); } QualType @@ -3423,6 +3435,35 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { return ToMethod; } +Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + // Import the major distinguishing characteristics of a category. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo()); + if (!BoundInfo) + return nullptr; + + ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create( + Importer.getToContext(), DC, + D->getVariance(), + Importer.Import(D->getVarianceLoc()), + D->getIndex(), + Importer.Import(D->getLocation()), + Name.getAsIdentifierInfo(), + Importer.Import(D->getColonLoc()), + BoundInfo); + Importer.Imported(D, Result); + Result->setLexicalDeclContext(LexicalDC); + return Result; +} + Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // Import the major distinguishing characteristics of a category. DeclContext *DC, *LexicalDC; @@ -3450,11 +3491,16 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Importer.Import(D->getCategoryNameLoc()), Name.getAsIdentifierInfo(), ToInterface, + /*TypeParamList=*/nullptr, Importer.Import(D->getIvarLBraceLoc()), Importer.Import(D->getIvarRBraceLoc())); ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToCategory); Importer.Imported(D, ToCategory); + // Import the type parameter list after calling Imported, to avoid + // loops when bringing in their DeclContext. + ToCategory->setTypeParamList(ImportObjCTypeParamList( + D->getTypeParamList())); // Import protocols SmallVector<ObjCProtocolDecl *, 4> Protocols; @@ -3663,13 +3709,11 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // If this class has a superclass, import it. if (From->getSuperClass()) { - ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>( - Importer.Import(From->getSuperClass())); - if (!Super) + TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo()); + if (!SuperTInfo) return true; - - To->setSuperClass(Super); - To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc())); + + To->setSuperClass(SuperTInfo); } // Import protocols @@ -3716,6 +3760,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, return false; } +ObjCTypeParamList * +ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) { + if (!list) + return nullptr; + + SmallVector<ObjCTypeParamDecl *, 4> toTypeParams; + for (auto fromTypeParam : *list) { + auto toTypeParam = cast_or_null<ObjCTypeParamDecl>( + Importer.Import(fromTypeParam)); + if (!toTypeParam) + return nullptr; + + toTypeParams.push_back(toTypeParam); + } + + return ObjCTypeParamList::create(Importer.getToContext(), + Importer.Import(list->getLAngleLoc()), + toTypeParams, + Importer.Import(list->getRAngleLoc())); +} + Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // If this class has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the @@ -3756,13 +3821,18 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { if (!ToIface) { ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, Importer.Import(D->getAtStartLoc()), - Name.getAsIdentifierInfo(), + Name.getAsIdentifierInfo(), + /*TypeParamList=*/nullptr, /*PrevDecl=*/nullptr, Loc, D->isImplicitInterfaceDecl()); ToIface->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIface); } Importer.Imported(D, ToIface); + // Import the type parameter list after calling Imported, to avoid + // loops when bringing in their DeclContext. + ToIface->setTypeParamList(ImportObjCTypeParamList( + D->getTypeParamListAsWritten())); if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface)) return nullptr; @@ -5313,7 +5383,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { return nullptr; return ToContext.getTrivialTypeSourceInfo(T, - FromTSI->getTypeLoc().getLocStart()); + Import(FromTSI->getTypeLoc().getLocStart())); } Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d9a3389c58f3..ea4b2f517cd0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1803,15 +1803,19 @@ void VarDecl::setStorageClass(StorageClass SC) { VarDecl::TLSKind VarDecl::getTLSKind() const { switch (VarDeclBits.TSCSpec) { case TSCS_unspecified: - if (!hasAttr<ThreadAttr>()) + if (!hasAttr<ThreadAttr>() && + !(getASTContext().getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported() && + hasAttr<OMPThreadPrivateDeclAttr>())) return TLS_None; - return getASTContext().getLangOpts().isCompatibleWithMSVC( - LangOptions::MSVC2015) + return ((getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2015)) || + hasAttr<OMPThreadPrivateDeclAttr>()) ? TLS_Dynamic : TLS_Static; case TSCS___thread: // Fall through. case TSCS__Thread_local: - return TLS_Static; + return TLS_Static; case TSCS_thread_local: return TLS_Dynamic; } @@ -2712,7 +2716,7 @@ bool FunctionDecl::isMSExternInline() const { for (const FunctionDecl *FD = getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) - if (FD->getStorageClass() == SC_Extern) + if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return true; return false; @@ -2724,7 +2728,7 @@ static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) { for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD; FD = FD->getPreviousDecl()) - if (FD->getStorageClass() == SC_Extern) + if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return false; return true; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d20451d1badc..4fcec53d6eb9 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case TypeAliasTemplate: case UnresolvedUsingTypename: case TemplateTypeParm: + case ObjCTypeParam: return IDNS_Ordinary | IDNS_Type; case UsingShadow: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b00b8a0ea9cc..d905fcf13a45 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1272,7 +1272,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { break; CTD = NewCTD; } - return CTD->getTemplatedDecl(); + return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { @@ -1281,7 +1281,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { break; CTPSD = NewCTPSD; } - return CTPSD; + return CTPSD->getDefinition(); } } @@ -1290,7 +1290,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { const CXXRecordDecl *RD = this; while (auto *NewRD = RD->getInstantiatedFromMemberClass()) RD = NewRD; - return RD; + return RD->getDefinition(); } } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index a1600cb11014..280c412ae8ff 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -239,6 +239,62 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( void ObjCInterfaceDecl::anchor() { } +ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { + // If this particular declaration has a type parameter list, return it. + if (ObjCTypeParamList *written = getTypeParamListAsWritten()) + return written; + + // If there is a definition, return its type parameter list. + if (const ObjCInterfaceDecl *def = getDefinition()) + return def->getTypeParamListAsWritten(); + + // Otherwise, look at previous declarations to determine whether any + // of them has a type parameter list, skipping over those + // declarations that do not. + for (auto decl = getMostRecentDecl(); decl; decl = decl->getPreviousDecl()) { + if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten()) + return written; + } + + return nullptr; +} + +void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) { + TypeParamList = TPL; + if (!TPL) + return; + // Set the declaration context of each of the type parameters. + for (auto typeParam : *TypeParamList) + typeParam->setDeclContext(this); +} + +ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return nullptr; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + if (const ObjCObjectType *superType = getSuperClassType()) { + if (ObjCInterfaceDecl *superDecl = superType->getInterface()) { + if (ObjCInterfaceDecl *superDef = superDecl->getDefinition()) + return superDef; + + return superDecl; + } + } + + return nullptr; +} + +SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { + if (TypeSourceInfo *superTInfo = getSuperClassTInfo()) + return superTInfo->getTypeLoc().getLocStart(); + + return SourceLocation(); +} + /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols /// (direct or indirect) used by the primary class. @@ -889,9 +945,13 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { return family; } -void ObjCMethodDecl::createImplicitParams(ASTContext &Context, - const ObjCInterfaceDecl *OID) { +QualType ObjCMethodDecl::getSelfType(ASTContext &Context, + const ObjCInterfaceDecl *OID, + bool &selfIsPseudoStrong, + bool &selfIsConsumed) { QualType selfTy; + selfIsPseudoStrong = false; + selfIsConsumed = false; if (isInstanceMethod()) { // There may be no interface context due to error in declaration // of the interface (which has been reported). Recover gracefully. @@ -904,9 +964,6 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, } else // we have a factory method. selfTy = Context.getObjCClassType(); - bool selfIsPseudoStrong = false; - bool selfIsConsumed = false; - if (Context.getLangOpts().ObjCAutoRefCount) { if (isInstanceMethod()) { selfIsConsumed = hasAttr<NSConsumesSelfAttr>(); @@ -930,7 +987,14 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, selfIsPseudoStrong = true; } } + return selfTy; +} +void ObjCMethodDecl::createImplicitParams(ASTContext &Context, + const ObjCInterfaceDecl *OID) { + bool selfIsPseudoStrong, selfIsConsumed; + QualType selfTy = + getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed); ImplicitParamDecl *self = ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy); @@ -966,6 +1030,20 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const { return SourceRange(); } +QualType ObjCMethodDecl::getSendResultType() const { + ASTContext &Ctx = getASTContext(); + return getReturnType().getNonLValueExprType(Ctx) + .substObjCTypeArgs(Ctx, {}, ObjCSubstitutionContext::Result); +} + +QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const { + // FIXME: Handle related result types here. + + return getReturnType().getNonLValueExprType(getASTContext()) + .substObjCMemberType(receiverType, getDeclContext(), + ObjCSubstitutionContext::Result); +} + static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, const ObjCMethodDecl *Method, SmallVectorImpl<const ObjCMethodDecl *> &Methods, @@ -1137,6 +1215,81 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { } //===----------------------------------------------------------------------===// +// ObjCTypeParamDecl +//===----------------------------------------------------------------------===// + +void ObjCTypeParamDecl::anchor() { } + +ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, + IdentifierInfo *name, + SourceLocation colonLoc, + TypeSourceInfo *boundInfo) { + return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index, + nameLoc, name, colonLoc, boundInfo); +} + +ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, + unsigned ID) { + return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, + ObjCTypeParamVariance::Invariant, + SourceLocation(), 0, SourceLocation(), + nullptr, SourceLocation(), nullptr); +} + +SourceRange ObjCTypeParamDecl::getSourceRange() const { + SourceLocation startLoc = VarianceLoc; + if (startLoc.isInvalid()) + startLoc = getLocation(); + + if (hasExplicitBound()) { + return SourceRange(startLoc, + getTypeSourceInfo()->getTypeLoc().getEndLoc()); + } + + return SourceRange(startLoc); +} + +//===----------------------------------------------------------------------===// +// ObjCTypeParamList +//===----------------------------------------------------------------------===// +ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc) + : NumParams(typeParams.size()) +{ + Brackets.Begin = lAngleLoc.getRawEncoding(); + Brackets.End = rAngleLoc.getRawEncoding(); + std::copy(typeParams.begin(), typeParams.end(), begin()); +} + + +ObjCTypeParamList *ObjCTypeParamList::create( + ASTContext &ctx, + SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc) { + unsigned size = sizeof(ObjCTypeParamList) + + sizeof(ObjCTypeParamDecl *) * typeParams.size(); + static_assert(llvm::AlignOf<ObjCTypeParamList>::Alignment >= + llvm::AlignOf<ObjCTypeParamDecl *>::Alignment, + "type parameter list needs greater alignment"); + unsigned align = llvm::alignOf<ObjCTypeParamList>(); + void *mem = ctx.Allocate(size, align); + return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc); +} + +void ObjCTypeParamList::gatherDefaultTypeArgs( + SmallVectorImpl<QualType> &typeArgs) const { + typeArgs.reserve(size()); + for (auto typeParam : *this) + typeArgs.push_back(typeParam->getUnderlyingType()); +} + +//===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -1144,11 +1297,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal){ ObjCInterfaceDecl *Result = new (C, DC) - ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal); + ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl, + isInternal); Result->Data.setInt(!C.getLangOpts().Modules); C.getObjCInterfaceType(Result, PrevDecl); return Result; @@ -1159,6 +1314,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, + nullptr, SourceLocation(), nullptr, false); Result->Data.setInt(!C.getLangOpts().Modules); @@ -1167,11 +1323,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal) : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc), - redeclarable_base(C), TypeForDecl(nullptr), Data() { + redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr), + Data() { setPreviousDecl(PrevDecl); // Copy the 'data' pointer over. @@ -1179,6 +1337,8 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, Data = PrevDecl->Data; setImplicit(IsInternal); + + setTypeParamList(typeParamList); } void ObjCInterfaceDecl::LoadExternalDefinition() const { @@ -1492,6 +1652,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { } } +QualType ObjCIvarDecl::getUsageType(QualType objectType) const { + return getType().substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// @@ -1648,17 +1813,34 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const { void ObjCCategoryDecl::anchor() { } +ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) + : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), + ClassInterface(IDecl), TypeParamList(nullptr), + NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) +{ + setTypeParamList(typeParamList); +} + ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) { ObjCCategoryDecl *CatDecl = new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, - IDecl, IvarLBraceLoc, IvarRBraceLoc); + IDecl, typeParamList, IvarLBraceLoc, + IvarRBraceLoc); if (IDecl) { // Link this category into its class's category list. CatDecl->NextClassCategory = IDecl->getCategoryListRaw(); @@ -1676,7 +1858,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(), SourceLocation(), SourceLocation(), - nullptr, nullptr); + nullptr, nullptr, nullptr); } ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { @@ -1688,6 +1870,15 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { getASTContext().setObjCImplementation(this, ImplD); } +void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { + TypeParamList = TPL; + if (!TPL) + return; + // Set the declaration context of each of the type parameters. + for (auto typeParam : *TypeParamList) + typeParam->setDeclContext(this); +} + //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl @@ -1876,6 +2067,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C, QualType(), nullptr, None); } +QualType ObjCPropertyDecl::getUsageType(QualType objectType) const { + return DeclType.substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCPropertyImplDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d33093b8b5e1..3202d8c75436 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -44,6 +44,8 @@ namespace { void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals, QualType T); + void PrintObjCTypeParams(ObjCTypeParamList *Params); + public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) @@ -962,6 +964,38 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx, Out << ')'; } +void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) { + Out << "<"; + unsigned First = true; + for (auto *Param : *Params) { + if (First) { + First = false; + } else { + Out << ", "; + } + + switch (Param->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + + case ObjCTypeParamVariance::Covariant: + Out << "__covariant "; + break; + + case ObjCTypeParamVariance::Contravariant: + Out << "__contravariant "; + break; + } + + Out << Param->getDeclName().getAsString(); + + if (Param->hasExplicitBound()) { + Out << " : " << Param->getUnderlyingType().getAsString(Policy); + } + } + Out << ">"; +} + void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isInstanceMethod()) Out << "- "; @@ -1037,14 +1071,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (!OID->isThisDeclarationADefinition()) { - Out << "@class " << I << ";"; + Out << "@class " << I; + + if (auto TypeParams = OID->getTypeParamListAsWritten()) { + PrintObjCTypeParams(TypeParams); + } + + Out << ";"; return; } bool eolnOut = false; + Out << "@interface " << I; + + if (auto TypeParams = OID->getTypeParamListAsWritten()) { + PrintObjCTypeParams(TypeParams); + } + if (SID) - Out << "@interface " << I << " : " << *SID; - else - Out << "@interface " << I; + Out << " : " << OID->getSuperClass()->getName(); // Protocols? const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); @@ -1107,7 +1151,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n"; + Out << "@interface " << *PID->getClassInterface(); + if (auto TypeParams = PID->getTypeParamList()) { + PrintObjCTypeParams(TypeParams); + } + Out << "(" << *PID << ")\n"; if (PID->ivar_size() > 0) { Out << "{\n"; Indentation += Policy.Indentation; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 87f9ffba78e3..2e066b2c42c6 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return nullptr; } +QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const { + if (isClassReceiver()) + return ctx.getObjCInterfaceType(getClassReceiver()); + + if (isSuperReceiver()) + return getSuperReceiverType(); + + return getBase()->getType(); +} + StringRef ObjCBridgedCastExpr::getBridgeKindName() const { switch (getBridgeKind()) { case OBC_Bridge: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0134c090d67e..dac803e5d2ff 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2379,6 +2379,10 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { } void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // Treat __kindof as a vendor extended type qualifier. + if (T->isKindOfType()) + Out << "U8__kindof"; + if (!T->qual_empty()) { // Mangle protocol qualifiers. SmallString<64> QualStr; @@ -2391,7 +2395,16 @@ void CXXNameMangler::mangleType(const ObjCObjectType *T) { QualOS.flush(); Out << 'U' << QualStr.size() << QualStr; } + mangleType(T->getBaseType()); + + if (T->isSpecialized()) { + // Mangle type arguments as I <type>+ E + Out << 'I'; + for (auto typeArg : T->getTypeArgs()) + mangleType(typeArg); + Out << 'E'; + } } void CXXNameMangler::mangleType(const BlockPointerType *T) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 541bd1ebdf88..cee5fee83913 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -466,18 +466,976 @@ const RecordType *Type::getAsUnionType() const { return nullptr; } +bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx, + const ObjCObjectType *&bound) const { + bound = nullptr; + + const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + if (!OPT) + return false; + + // Easy case: id. + if (OPT->isObjCIdType()) + return true; + + // If it's not a __kindof type, reject it now. + if (!OPT->isKindOfType()) + return false; + + // If it's Class or qualified Class, it's not an object type. + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) + return false; + + // Figure out the type bound for the __kindof type. + bound = OPT->getObjectType()->stripObjCKindOfTypeAndQuals(ctx) + ->getAs<ObjCObjectType>(); + return true; +} + +bool Type::isObjCClassOrClassKindOfType() const { + const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + if (!OPT) + return false; + + // Easy case: Class. + if (OPT->isObjCClassType()) + return true; + + // If it's not a __kindof type, reject it now. + if (!OPT->isKindOfType()) + return false; + + // If it's Class or qualified Class, it's a class __kindof type. + return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType(); +} + ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) - : Type(ObjCObject, Canonical, false, false, false, false), + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) + : Type(ObjCObject, Canonical, Base->isDependentType(), + Base->isInstantiationDependentType(), + Base->isVariablyModifiedType(), + Base->containsUnexpandedParameterPack()), BaseType(Base) { - ObjCObjectTypeBits.NumProtocols = NumProtocols; - assert(getNumProtocols() == NumProtocols && + ObjCObjectTypeBits.IsKindOf = isKindOf; + + ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); + assert(getTypeArgsAsWritten().size() == typeArgs.size() && + "bitfield overflow in type argument count"); + ObjCObjectTypeBits.NumProtocols = protocols.size(); + assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); - if (NumProtocols) - memcpy(getProtocolStorage(), Protocols, - NumProtocols * sizeof(ObjCProtocolDecl*)); + if (!typeArgs.empty()) + memcpy(getTypeArgStorage(), typeArgs.data(), + typeArgs.size() * sizeof(QualType)); + if (!protocols.empty()) + memcpy(getProtocolStorage(), protocols.data(), + protocols.size() * sizeof(ObjCProtocolDecl*)); + + for (auto typeArg : typeArgs) { + if (typeArg->isDependentType()) + setDependent(); + else if (typeArg->isInstantiationDependentType()) + setInstantiationDependent(); + + if (typeArg->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + } +} + +bool ObjCObjectType::isSpecialized() const { + // If we have type arguments written here, the type is specialized. + if (ObjCObjectTypeBits.NumTypeArgs > 0) + return true; + + // Otherwise, check whether the base type is specialized. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return false; + + return objcObject->isSpecialized(); + } + + // Not specialized. + return false; +} + +ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { + // We have type arguments written on this type. + if (isSpecializedAsWritten()) + return getTypeArgsAsWritten(); + + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return { }; + + return objcObject->getTypeArgs(); + } + + // No type arguments. + return { }; +} + +bool ObjCObjectType::isKindOfType() const { + if (isKindOfTypeAsWritten()) + return true; + + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return false; + + return objcObject->isKindOfType(); + } + + // Not a "__kindof" type. + return false; +} + +QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const { + if (!isKindOfType() && qual_empty()) + return QualType(this, 0); + + // Recursively strip __kindof. + SplitQualType splitBaseType = getBaseType().split(); + QualType baseType(splitBaseType.Ty, 0); + if (const ObjCObjectType *baseObj + = splitBaseType.Ty->getAs<ObjCObjectType>()) { + baseType = baseObj->stripObjCKindOfTypeAndQuals(ctx); + } + + return ctx.getObjCObjectType(ctx.getQualifiedType(baseType, + splitBaseType.Quals), + getTypeArgsAsWritten(), + /*protocols=*/{ }, + /*isKindOf=*/false); +} + +const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const { + if (!isKindOfType() && qual_empty()) + return this; + + QualType obj = getObjectType()->stripObjCKindOfTypeAndQuals(ctx); + return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>(); +} + +namespace { + +template<typename F> +QualType simpleTransform(ASTContext &ctx, QualType type, F &&f); + +/// Visitor used by simpleTransform() to perform the transformation. +template<typename F> +struct SimpleTransformVisitor + : public TypeVisitor<SimpleTransformVisitor<F>, QualType> { + ASTContext &Ctx; + F &&TheFunc; + + QualType recurse(QualType type) { + return simpleTransform(Ctx, type, std::move(TheFunc)); + } + +public: + SimpleTransformVisitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { } + + // None of the clients of this transformation can occur where + // there are dependent types, so skip dependent types. +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } +#include "clang/AST/TypeNodes.def" + +#define TRIVIAL_TYPE_CLASS(Class) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } + + TRIVIAL_TYPE_CLASS(Builtin) + + QualType VisitComplexType(const ComplexType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getComplexType(elementType); + } + + QualType VisitPointerType(const PointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getPointerType(pointeeType); + } + + QualType VisitBlockPointerType(const BlockPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getBlockPointerType(pointeeType); + } + + QualType VisitLValueReferenceType(const LValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue()); + } + + QualType VisitRValueReferenceType(const RValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getRValueReferenceType(pointeeType); + } + + QualType VisitMemberPointerType(const MemberPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getMemberPointerType(pointeeType, T->getClass()); + } + + QualType VisitConstantArrayType(const ConstantArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getConstantArrayType(elementType, T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVariableArrayType(const VariableArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVariableArrayType(elementType, T->getSizeExpr(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + } + + QualType VisitIncompleteArrayType(const IncompleteArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVectorType(const VectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVectorType(elementType, T->getNumElements(), + T->getVectorKind()); + } + + QualType VisitExtVectorType(const ExtVectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getExtVectorType(elementType, T->getNumElements()); + } + + QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo()); + } + + QualType VisitFunctionProtoType(const FunctionProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : T->getParamTypes()) { + QualType newParamType = recurse(paramType); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = recurse(exceptionType); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = Ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return QualType(T, 0); + + return Ctx.getFunctionType(returnType, paramTypes, info); + } + + QualType VisitParenType(const ParenType *T) { + QualType innerType = recurse(T->getInnerType()); + if (innerType.isNull()) + return QualType(); + + if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getParenType(innerType); + } + + TRIVIAL_TYPE_CLASS(Typedef) + + QualType VisitAdjustedType(const AdjustedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + QualType adjustedType = recurse(T->getAdjustedType()); + if (adjustedType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr() && + adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAdjustedType(originalType, adjustedType); + } + + QualType VisitDecayedType(const DecayedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getDecayedType(originalType); + } + + TRIVIAL_TYPE_CLASS(TypeOfExpr) + TRIVIAL_TYPE_CLASS(TypeOf) + TRIVIAL_TYPE_CLASS(Decltype) + TRIVIAL_TYPE_CLASS(UnaryTransform) + TRIVIAL_TYPE_CLASS(Record) + TRIVIAL_TYPE_CLASS(Enum) + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(Elaborated) + + QualType VisitAttributedType(const AttributedType *T) { + QualType modifiedType = recurse(T->getModifiedType()); + if (modifiedType.isNull()) + return QualType(); + + QualType equivalentType = recurse(T->getEquivalentType()); + if (equivalentType.isNull()) + return QualType(); + + if (modifiedType.getAsOpaquePtr() + == T->getModifiedType().getAsOpaquePtr() && + equivalentType.getAsOpaquePtr() + == T->getEquivalentType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAttributedType(T->getAttrKind(), modifiedType, + equivalentType); + } + + QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + QualType replacementType = recurse(T->getReplacementType()); + if (replacementType.isNull()) + return QualType(); + + if (replacementType.getAsOpaquePtr() + == T->getReplacementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(), + replacementType); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(TemplateSpecialization) + + QualType VisitAutoType(const AutoType *T) { + if (!T->isDeduced()) + return QualType(T, 0); + + QualType deducedType = recurse(T->getDeducedType()); + if (deducedType.isNull()) + return QualType(); + + if (deducedType.getAsOpaquePtr() + == T->getDeducedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAutoType(deducedType, T->isDecltypeAuto(), + T->isDependentType()); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(PackExpansion) + + QualType VisitObjCObjectType(const ObjCObjectType *T) { + QualType baseType = recurse(T->getBaseType()); + if (baseType.isNull()) + return QualType(); + + // Transform type arguments. + bool typeArgChanged = false; + SmallVector<QualType, 4> typeArgs; + for (auto typeArg : T->getTypeArgsAsWritten()) { + QualType newTypeArg = recurse(typeArg); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) + typeArgChanged = true; + + typeArgs.push_back(newTypeArg); + } + + if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() && + !typeArgChanged) + return QualType(T, 0); + + return Ctx.getObjCObjectType(baseType, typeArgs, + llvm::makeArrayRef(T->qual_begin(), + T->getNumProtocols()), + T->isKindOfTypeAsWritten()); + } + + TRIVIAL_TYPE_CLASS(ObjCInterface) + + QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getObjCObjectPointerType(pointeeType); + } + + QualType VisitAtomicType(const AtomicType *T) { + QualType valueType = recurse(T->getValueType()); + if (valueType.isNull()) + return QualType(); + + if (valueType.getAsOpaquePtr() + == T->getValueType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAtomicType(valueType); + } + +#undef TRIVIAL_TYPE_CLASS +}; + +/// Perform a simple type transformation that does not change the +/// semantics of the type. +template<typename F> +QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { + // Transform the type. If it changed, return the transformed result. + QualType transformed = f(type); + if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr()) + return transformed; + + // Split out the qualifiers from the type. + SplitQualType splitType = type.split(); + + // Visit the type itself. + SimpleTransformVisitor<F> visitor(ctx, std::move(f)); + QualType result = visitor.Visit(splitType.Ty); + if (result.isNull()) + return result; + + // Reconstruct the transformed type by applying the local qualifiers + // from the split type. + return ctx.getQualifiedType(result, splitType.Quals); +} + +} // end anonymous namespace + +/// Substitute the given type arguments for Objective-C type +/// parameters within the given type, recursively. +QualType QualType::substObjCTypeArgs( + ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const { + return simpleTransform(ctx, *this, + [&](QualType type) -> QualType { + SplitQualType splitType = type.split(); + + // Replace an Objective-C type parameter reference with the corresponding + // type argument. + if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) { + if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) { + // If we have type arguments, use them. + if (!typeArgs.empty()) { + // FIXME: Introduce SubstObjCTypeParamType ? + QualType argType = typeArgs[typeParam->getIndex()]; + return ctx.getQualifiedType(argType, splitType.Quals); + } + + switch (context) { + case ObjCSubstitutionContext::Ordinary: + case ObjCSubstitutionContext::Parameter: + case ObjCSubstitutionContext::Superclass: + // Substitute the bound. + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + case ObjCSubstitutionContext::Result: + case ObjCSubstitutionContext::Property: { + // Substitute the __kindof form of the underlying type. + const auto *objPtr = typeParam->getUnderlyingType() + ->castAs<ObjCObjectPointerType>(); + + // __kindof types, id, and Class don't need an additional + // __kindof. + if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + // Add __kindof. + const auto *obj = objPtr->getObjectType(); + QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(), + obj->getTypeArgsAsWritten(), + obj->getProtocols(), + /*isKindOf=*/true); + + // Rebuild object pointer type. + resultTy = ctx.getObjCObjectPointerType(resultTy); + return ctx.getQualifiedType(resultTy, splitType.Quals); + } + } + } + } + + // If we have a function type, update the context appropriately. + if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) { + // Substitute result type. + QualType returnType = funcType->getReturnType().substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Result); + if (returnType.isNull()) + return QualType(); + + // Handle non-prototyped functions, which only substitute into the result + // type. + if (isa<FunctionNoProtoType>(funcType)) { + // If the return type was unchanged, do nothing. + if (returnType.getAsOpaquePtr() + == funcType->getReturnType().getAsOpaquePtr()) + return type; + + // Otherwise, build a new type. + return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); + } + + const auto *funcProtoType = cast<FunctionProtoType>(funcType); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : funcProtoType->getParamTypes()) { + QualType newParamType = paramType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Parameter); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = exceptionType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() + == funcProtoType->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return type; + + return ctx.getFunctionType(returnType, paramTypes, info); + } + + // Substitute into the type arguments of a specialized Objective-C object + // type. + if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) { + if (objcObjectType->isSpecializedAsWritten()) { + SmallVector<QualType, 4> newTypeArgs; + bool anyChanged = false; + for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { + QualType newTypeArg = typeArg.substObjCTypeArgs( + ctx, typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { + // If we're substituting based on an unspecialized context type, + // produce an unspecialized type. + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + if (typeArgs.empty() && + context != ObjCSubstitutionContext::Superclass) { + return ctx.getObjCObjectType( + objcObjectType->getBaseType(), { }, + protocols, + objcObjectType->isKindOfTypeAsWritten()); + } + + anyChanged = true; + } + + newTypeArgs.push_back(newTypeArg); + } + + if (anyChanged) { + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + return ctx.getObjCObjectType(objcObjectType->getBaseType(), + newTypeArgs, protocols, + objcObjectType->isKindOfTypeAsWritten()); + } + } + + return type; + } + + return type; + }); +} + +QualType QualType::substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const { + if (auto subs = objectType->getObjCSubstitutions(dc)) + return substObjCTypeArgs(dc->getParentASTContext(), *subs, context); + + return *this; +} + +QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { + // FIXME: Because ASTContext::getAttributedType() is non-const. + auto &ctx = const_cast<ASTContext &>(constCtx); + return simpleTransform(ctx, *this, + [&](QualType type) -> QualType { + SplitQualType splitType = type.split(); + if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) { + if (!objType->isKindOfType()) + return type; + + QualType baseType + = objType->getBaseType().stripObjCKindOfType(ctx); + return ctx.getQualifiedType( + ctx.getObjCObjectType(baseType, + objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/false), + splitType.Quals); + } + + return type; + }); +} + +Optional<ArrayRef<QualType>> Type::getObjCSubstitutions( + const DeclContext *dc) const { + // Look through method scopes. + if (auto method = dyn_cast<ObjCMethodDecl>(dc)) + dc = method->getDeclContext(); + + // Find the class or category in which the type we're substituting + // was declared. + const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc); + const ObjCCategoryDecl *dcCategoryDecl = nullptr; + ObjCTypeParamList *dcTypeParams = nullptr; + if (dcClassDecl) { + // If the class does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcClassDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + } else { + // If we are in neither a class mor a category, there's no + // substitution to perform. + dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc); + if (!dcCategoryDecl) + return None; + + // If the category does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcCategoryDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + + dcClassDecl = dcCategoryDecl->getClassInterface(); + if (!dcClassDecl) + return None; + } + assert(dcTypeParams && "No substitutions to perform"); + assert(dcClassDecl && "No class context"); + + // Find the underlying object type. + const ObjCObjectType *objectType; + if (const auto *objectPointerType = getAs<ObjCObjectPointerType>()) { + objectType = objectPointerType->getObjectType(); + } else if (getAs<BlockPointerType>()) { + ASTContext &ctx = dc->getParentASTContext(); + objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { }) + ->castAs<ObjCObjectType>();; + } else { + objectType = getAs<ObjCObjectType>(); + } + + /// Extract the class from the receiver object type. + ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface() + : nullptr; + if (!curClassDecl) { + // If we don't have a context type (e.g., this is "id" or some + // variant thereof), substitute the bounds. + return llvm::ArrayRef<QualType>(); + } + + // Follow the superclass chain until we've mapped the receiver type + // to the same class as the context. + while (curClassDecl != dcClassDecl) { + // Map to the superclass type. + QualType superType = objectType->getSuperClassType(); + if (superType.isNull()) { + objectType = nullptr; + break; + } + + objectType = superType->castAs<ObjCObjectType>(); + curClassDecl = objectType->getInterface(); + } + + // If we don't have a receiver type, or the receiver type does not + // have type arguments, substitute in the defaults. + if (!objectType || objectType->isUnspecialized()) { + return llvm::ArrayRef<QualType>(); + } + + // The receiver type has the type arguments we want. + return objectType->getTypeArgs(); +} + +bool Type::acceptsObjCTypeParams() const { + if (auto *IfaceT = getAsObjCInterfaceType()) { + if (auto *ID = IfaceT->getInterface()) { + if (ID->getTypeParamList()) + return true; + } + } + + return false; +} + +void ObjCObjectType::computeSuperClassTypeSlow() const { + // Retrieve the class declaration for this type. If there isn't one + // (e.g., this is some variant of "id" or "Class"), then there is no + // superclass type. + ObjCInterfaceDecl *classDecl = getInterface(); + if (!classDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // Extract the superclass type. + const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType(); + if (!superClassObjTy) { + CachedSuperClassType.setInt(true); + return; + } + + ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface(); + if (!superClassDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // If the superclass doesn't have type parameters, then there is no + // substitution to perform. + QualType superClassType(superClassObjTy, 0); + ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList(); + if (!superClassTypeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the superclass reference is unspecialized, return it. + if (superClassObjTy->isUnspecialized()) { + CachedSuperClassType.setPointerAndInt(superClassObjTy, true); + return; + } + + // If the subclass is not parameterized, there aren't any type + // parameters in the superclass reference to substitute. + ObjCTypeParamList *typeParams = classDecl->getTypeParamList(); + if (!typeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the subclass type isn't specialized, return the unspecialized + // superclass. + if (isUnspecialized()) { + QualType unspecializedSuper + = classDecl->getASTContext().getObjCInterfaceType( + superClassObjTy->getInterface()); + CachedSuperClassType.setPointerAndInt( + unspecializedSuper->castAs<ObjCObjectType>(), + true); + return; + } + + // Substitute the provided type arguments into the superclass type. + ArrayRef<QualType> typeArgs = getTypeArgs(); + assert(typeArgs.size() == typeParams->size()); + CachedSuperClassType.setPointerAndInt( + superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs, + ObjCSubstitutionContext::Superclass) + ->castAs<ObjCObjectType>(), + true); +} + +const ObjCInterfaceType *ObjCObjectPointerType::getInterfaceType() const { + if (auto interfaceDecl = getObjectType()->getInterface()) { + return interfaceDecl->getASTContext().getObjCInterfaceType(interfaceDecl) + ->castAs<ObjCInterfaceType>(); + } + + return nullptr; +} + +QualType ObjCObjectPointerType::getSuperClassType() const { + QualType superObjectType = getObjectType()->getSuperClassType(); + if (superObjectType.isNull()) + return superObjectType; + + ASTContext &ctx = getInterfaceDecl()->getASTContext(); + return ctx.getObjCObjectPointerType(superObjectType); } const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { @@ -514,6 +1472,13 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { return nullptr; } +const ObjCObjectType *Type::getAsObjCInterfaceType() const { + if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) { + if (OT->getInterface()) + return OT; + } + return nullptr; +} const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) @@ -1927,7 +2892,9 @@ bool AttributedType::isCallingConv() const { case attr_nonnull: case attr_nullable: case attr_null_unspecified: + case attr_objc_kindof: return false; + case attr_pcs: case attr_pcs_vfp: case attr_cdecl: @@ -2076,15 +3043,23 @@ QualifierCollector::apply(const ASTContext &Context, const Type *T) const { void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) { + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) { ID.AddPointer(BaseType.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(Protocols[i]); + ID.AddInteger(typeArgs.size()); + for (auto typeArg : typeArgs) + ID.AddPointer(typeArg.getAsOpaquePtr()); + ID.AddInteger(protocols.size()); + for (auto proto : protocols) + ID.AddPointer(proto); + ID.AddBoolean(isKindOf); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); + Profile(ID, getBaseType(), getTypeArgsAsWritten(), + llvm::makeArrayRef(qual_begin(), getNumProtocols()), + isKindOfTypeAsWritten()); } namespace { @@ -2495,6 +3470,39 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) { return None; } +bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { + const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>(); + if (!objcPtr) + return false; + + if (objcPtr->isObjCIdType()) { + // id is always okay. + return true; + } + + // Blocks are NSObjects. + if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) { + if (iface->getIdentifier() != ctx.getNSObjectName()) + return false; + + // Continue to check qualifiers, below. + } else if (objcPtr->isObjCQualifiedIdType()) { + // Continue to check qualifiers, below. + } else { + return false; + } + + // Check protocol qualifiers. + for (ObjCProtocolDecl *proto : objcPtr->quals()) { + // Blocks conform to NSObject and NSCopying. + if (proto->getIdentifier() != ctx.getNSObjectName() && + proto->getIdentifier() != ctx.getNSCopyingName()) + return false; + } + + return true; +} + Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { if (isObjCARCImplicitlyUnretainedType()) return Qualifiers::OCL_ExplicitNone; diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index c069eb061739..85bda6a06d97 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -19,6 +19,8 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>(); + //===----------------------------------------------------------------------===// // TypeLoc Implementation //===----------------------------------------------------------------------===// @@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, } } +namespace { + class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> { + TypeLoc Source; + public: + TypeLocCopier(TypeLoc source) : Source(source) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \ + dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +void TypeLoc::copy(TypeLoc other) { + assert(getFullDataSize() == other.getFullDataSize()); + + // If both data pointers are aligned to the maximum alignment, we + // can memcpy because getFullDataSize() accurately reflects the + // layout of the data. + if (reinterpret_cast<uintptr_t>(Data) + == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data), + TypeLocMaxDataAlign) && + reinterpret_cast<uintptr_t>(other.Data) + == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data), + TypeLocMaxDataAlign)) { + memcpy(Data, other.Data, getFullDataSize()); + return; + } + + // Copy each of the pieces. + TypeLoc TL(getType(), Data); + do { + TypeLocCopier(other).Visit(TL); + other = other.getNextTypeLoc(); + } while ((TL = TL.getNextTypeLoc())); +} + SourceLocation TypeLoc::getBeginLoc() const { TypeLoc Cur = *this; TypeLoc LeftMost = Cur; @@ -312,6 +354,33 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +SourceLocation TypeLoc::findNullabilityLoc() const { + if (auto attributedLoc = getAs<AttributedTypeLoc>()) { + if (attributedLoc.getAttrKind() == AttributedType::attr_nullable || + attributedLoc.getAttrKind() == AttributedType::attr_nonnull || + attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified) + return attributedLoc.getAttrNameLoc(); + } + + return SourceLocation(); +} + +void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setHasBaseTypeAsWritten(true); + setTypeArgsLAngleLoc(Loc); + setTypeArgsRAngleLoc(Loc); + for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) { + setTypeArgTInfo(i, + Context.getTrivialTypeSourceInfo( + getTypePtr()->getTypeArgsAsWritten()[i], Loc)); + } + setProtocolLAngleLoc(Loc); + setProtocolRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); +} + void TypeOfTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 9938170c321a..0bb50c6ba815 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1129,6 +1129,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, T->getAttrKind() == AttributedType::attr_objc_ownership) return printBefore(T->getEquivalentType(), OS); + if (T->getAttrKind() == AttributedType::attr_objc_kindof) + OS << "__kindof "; + printBefore(T->getModifiedType(), OS); if (T->isMSTypeSpec()) { @@ -1165,6 +1168,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, T->getAttrKind() == AttributedType::attr_objc_ownership) return printAfter(T->getEquivalentType(), OS); + if (T->getAttrKind() == AttributedType::attr_objc_kindof) + return; + // TODO: not all attributes are GCC-style attributes. if (T->isMSTypeSpec()) return; @@ -1310,59 +1316,61 @@ void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten() && + !T->isKindOfTypeAsWritten()) return printBefore(T->getBaseType(), OS); + if (T->isKindOfTypeAsWritten()) + OS << "__kindof "; + print(T->getBaseType(), OS, StringRef()); - OS << '<'; - bool isFirst = true; - for (const auto *I : T->quals()) { - if (isFirst) - isFirst = false; - else - OS << ','; - OS << I->getName(); + + if (T->isSpecializedAsWritten()) { + bool isFirst = true; + OS << '<'; + for (auto typeArg : T->getTypeArgsAsWritten()) { + if (isFirst) + isFirst = false; + else + OS << ","; + + print(typeArg, OS, StringRef()); + } + OS << '>'; } - OS << '>'; + + if (!T->qual_empty()) { + bool isFirst = true; + OS << '<'; + for (const auto *I : T->quals()) { + if (isFirst) + isFirst = false; + else + OS << ','; + OS << I->getName(); + } + OS << '>'; + } + spaceBeforePlaceHolder(OS); } void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten() && + !T->isKindOfTypeAsWritten()) return printAfter(T->getBaseType(), OS); } void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, raw_ostream &OS) { - T->getPointeeType().getLocalQualifiers().print(OS, Policy, - /*appendSpaceIfNonEmpty=*/true); - - assert(!T->isObjCSelType()); + printBefore(T->getPointeeType(), OS); - if (T->isObjCIdType() || T->isObjCQualifiedIdType()) - OS << "id"; - else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) - OS << "Class"; - else - OS << T->getInterfaceDecl()->getName(); - - if (!T->qual_empty()) { - OS << '<'; - for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); - I != E; ++I) { - OS << (*I)->getName(); - if (I+1 != E) - OS << ','; - } - OS << '>'; - } - + // If we need to print the pointer, print it now. if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() && !T->isObjCClassType() && !T->isObjCQualifiedClassType()) { - OS << " *"; // Don't forget the implicit pointer. - } else { - spaceBeforePlaceHolder(OS); + if (HasEmptyPlaceHolder) + OS << ' '; + OS << '*'; } } void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index b6ef8226a9a9..069fcba474b2 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -20,21 +20,21 @@ namespace clang { namespace ast_matchers { namespace internal { -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, +bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); @@ -51,7 +51,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { namespace { typedef bool (*VariadicOperatorFunction)( - const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); template <VariadicOperatorFunction Func> @@ -228,7 +228,7 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, +bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { if (InnerMatchers.size() != 1) @@ -248,7 +248,7 @@ bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, return !InnerMatchers[0].matches(DynNode, Finder, &Discard); } -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { @@ -262,7 +262,7 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, return true; } -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { @@ -279,7 +279,7 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, return Matched; } -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 9930c530c081..96a78cd9f8fa 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -216,7 +216,7 @@ private: if (Code[Length] == Marker) { Result->Kind = TokenInfo::TK_Literal; Result->Text = Code.substr(0, Length + 1); - Result->Value = Code.substr(1, Length - 1).str(); + Result->Value = Code.substr(1, Length - 1); Code = Code.drop_front(Length + 1); return; } diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index a88b70701234..9d8be4700581 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -249,7 +249,7 @@ VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { setUnsigned(Unsigned); } -VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { +VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { setString(String); } @@ -319,7 +319,7 @@ const std::string &VariantValue::getString() const { return *Value.String; } -void VariantValue::setString(const std::string &NewValue) { +void VariantValue::setString(StringRef NewValue) { reset(); Type = VT_String; Value.String = new std::string(NewValue); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index c46e2c7db380..1a636aefa639 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" +#include "clang/Frontend/PCHContainerOperations.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/FileSystem.h" @@ -585,3 +586,5 @@ void FileManager::PrintStats() const { //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; } + +PCHContainerOperations::~PCHContainerOperations() {} diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 36fba994f1e7..dcb7603bf5ab 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -109,7 +109,8 @@ namespace { WCHARSUPPORT = 0x04000, HALFSUPPORT = 0x08000, KEYCONCEPTS = 0x10000, - KEYALL = (0x1ffff & ~KEYNOMS18 & + KEYOBJC2 = 0x20000, + KEYALL = (0x3ffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. }; @@ -144,6 +145,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, // in non-arc mode. if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled; if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; + if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled; if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future; return KS_Disabled; } diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 1a48a6c6a8d1..3846fecebf5d 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -82,10 +82,6 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, return true; for (const Module *Current = this; Current; Current = Current->Parent) { - if (!Current->MissingHeaders.empty()) { - MissingHeader = Current->MissingHeaders.front(); - return false; - } for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) { if (hasFeature(Current->Requirements[I].first, LangOpts, Target) != Current->Requirements[I].second) { @@ -93,6 +89,10 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, return false; } } + if (!Current->MissingHeaders.empty()) { + MissingHeader = Current->MissingHeaders.front(); + return false; + } } llvm_unreachable("could not find a reason why module is unavailable"); @@ -184,7 +184,11 @@ void Module::addRequirement(StringRef Feature, bool RequiredState, } void Module::markUnavailable(bool MissingRequirement) { - if (!IsAvailable) + auto needUpdate = [MissingRequirement](Module *M) { + return M->IsAvailable || (!M->IsMissingRequirement && MissingRequirement); + }; + + if (!needUpdate(this)) return; SmallVector<Module *, 2> Stack; @@ -193,7 +197,7 @@ void Module::markUnavailable(bool MissingRequirement) { Module *Current = Stack.back(); Stack.pop_back(); - if (!Current->IsAvailable) + if (!needUpdate(Current)) continue; Current->IsAvailable = false; @@ -201,7 +205,7 @@ void Module::markUnavailable(bool MissingRequirement) { for (submodule_iterator Sub = Current->submodule_begin(), SubEnd = Current->submodule_end(); Sub != SubEnd; ++Sub) { - if ((*Sub)->IsAvailable) + if (needUpdate(*Sub)) Stack.push_back(*Sub); } } diff --git a/lib/Basic/Sanitizers.cpp b/lib/Basic/Sanitizers.cpp index d3676b6b465c..91b6b2dc74eb 100644 --- a/lib/Basic/Sanitizers.cpp +++ b/lib/Basic/Sanitizers.cpp @@ -14,34 +14,9 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/MathExtras.h" using namespace clang; -SanitizerSet::SanitizerSet() : Mask(0) {} - -bool SanitizerSet::has(SanitizerMask K) const { - assert(llvm::countPopulation(K) == 1); - return Mask & K; -} - -bool SanitizerSet::hasOneOf(SanitizerMask K) const { - return Mask & K; -} - -void SanitizerSet::set(SanitizerMask K, bool Value) { - assert(llvm::countPopulation(K) == 1); - Mask = Value ? (Mask | K) : (Mask & ~K); -} - -void SanitizerSet::clear() { - Mask = 0; -} - -bool SanitizerSet::empty() const { - return Mask == 0; -} - SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) #define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 856ad50d3782..dbd2f9ae9954 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; MaxVectorAlign = 0; + MaxTLSAlign = 0; SimdDefaultAlign = 0; SizeType = UnsignedLong; PtrDiffType = SignedLong; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 8f2bca051b67..3cf74bc84926 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -580,6 +580,8 @@ public: PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { this->WCharType = this->UnsignedShort; + // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). + this->MaxTLSAlign = 256; this->UserLabelPrefix = ""; switch (Triple.getArch()) { @@ -863,6 +865,8 @@ public: bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; bool hasFeature(StringRef Feature) const override; + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override; void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const override; @@ -1036,7 +1040,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, if (Feature == "power8-vector") { HasP8Vector = true; - HasVSX = true; continue; } @@ -1047,7 +1050,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, if (Feature == "direct-move") { HasDirectMove = true; - HasVSX = true; continue; } @@ -1064,6 +1066,15 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, // TODO: Finish this list and add an assert that we've handled them // all. } + if (!HasVSX && (HasP8Vector || HasDirectMove)) { + if (HasP8Vector) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" << + "-mno-vsx"; + else if (HasDirectMove) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" << + "-mno-vsx"; + return false; + } return true; } @@ -1285,6 +1296,11 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { .Case("ppc64le", true) .Case("pwr8", true) .Default(false); + Features["vsx"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { @@ -1301,6 +1317,39 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .Default(false); } +/* There is no clear way for the target to know which of the features in the + final feature vector came from defaults and which are actually specified by + the user. To that end, we use the fact that this function is not called on + default features - only user specified ones. By the first time this + function is called, the default features are populated. + We then keep track of the features that the user specified so that we + can ensure we do not override a user's request (only defaults). + For example: + -mcpu=pwr8 -mno-vsx (should disable vsx and everything that depends on it) + -mcpu=pwr8 -mdirect-move -mno-vsx (should actually be diagnosed) + +NOTE: Do not call this from PPCTargetInfo::getDefaultFeatures +*/ +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + static llvm::StringMap<bool> ExplicitFeatures; + ExplicitFeatures[Name] = Enabled; + + // At this point, -mno-vsx turns off the dependent features but we respect + // the user's requests. + if (!Enabled && Name == "vsx") { + Features["direct-move"] = ExplicitFeatures["direct-move"]; + Features["power8-vector"] = ExplicitFeatures["power8-vector"]; + } + if ((Enabled && Name == "power8-vector") || + (Enabled && Name == "direct-move")) { + if (ExplicitFeatures.find("vsx") == ExplicitFeatures.end()) { + Features["vsx"] = true; + } + } + Features[Name] = Enabled; +} + const char * const PPCTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", @@ -1472,7 +1521,7 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } - // PPC64 Linux-specifc ABI options. + // PPC64 Linux-specific ABI options. bool setABI(const std::string &Name) override { if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { ABI = Name; @@ -3996,14 +4045,8 @@ class ARMTargetInfo : public TargetInfo { FP_Neon } FPMath; - unsigned ArchISA; - unsigned ArchKind; - unsigned ArchProfile; - unsigned ArchVersion; - unsigned FPU : 5; - unsigned ShouldUseInlineAtomic : 1; unsigned IsAAPCS : 1; unsigned IsThumb : 1; unsigned HWDiv : 2; @@ -4025,6 +4068,37 @@ class ARMTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm || + T.getArch() == llvm::Triple::armeb) { + StringRef VersionStr; + if (ArchName.startswith("armv")) + VersionStr = ArchName.substr(4, 1); + else if (ArchName.startswith("armebv")) + VersionStr = ArchName.substr(6, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb || + T.getArch() == llvm::Triple::thumbeb); + StringRef VersionStr; + if (ArchName.startswith("thumbv")) + VersionStr = ArchName.substr(6, 1); + else if (ArchName.startswith("thumbebv")) + VersionStr = ArchName.substr(8, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + void setABIAAPCS() { IsAAPCS = true; @@ -4123,27 +4197,6 @@ class ARMTargetInfo : public TargetInfo { // FIXME: Override "preferred align" for double and long long. } - void setArchInfo(StringRef ArchName) { - ArchISA = llvm::ARMTargetParser::parseArchISA(ArchName); - ArchKind = llvm::ARMTargetParser::parseArch(ArchName); - ArchProfile = llvm::ARMTargetParser::parseArchProfile(ArchName); - ArchVersion = llvm::ARMTargetParser::parseArchVersion(ArchName); - } - - void setAtomic() { - // Cortex M does not support 8 byte atomics, while general Thumb2 does. - if (ArchProfile == llvm::ARM::PK_M) { - MaxAtomicPromoteWidth = 32; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 32; - } - else { - MaxAtomicPromoteWidth = 64; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 64; - } - } - public: ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian) : TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default), @@ -4159,27 +4212,12 @@ public: break; } - // if subArch is not specified Arc Info is based on the default CPU - if (Triple.getSubArch() == llvm::Triple::SubArchType::NoSubArch) { - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(CPU); - setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind)); - ShouldUseInlineAtomic = false; - } - else { - setArchInfo(Triple.getArchName()); - // FIXME: Should't this be updated also when calling setCPU() ? - // Doing so currently causes regressions - ShouldUseInlineAtomic = (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || - (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); - } - // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; - // FIXME: Should't this be updated also when calling setCPU() ? - // Doing so currently causes regressions - IsThumb = (ArchISA == llvm::ARM::IK_THUMB); + // FIXME: Should we just treat this as a feature? + IsThumb = getTriple().getArchName().startswith("thumb"); // FIXME: This duplicates code from the driver that sets the -target-abi // option - this code is used if -target-abi isn't passed and should @@ -4224,7 +4262,10 @@ public: // ARM targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericARM); - setAtomic(); + // ARM has atomics up to 8 bytes + MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 64; // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4255,6 +4296,11 @@ public: // FIXME: This should be based on Arch attributes, not CPU names. void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + StringRef ArchName = getTriple().getArchName(); + unsigned ArchKind = llvm::ARMTargetParser::parseArch(ArchName); + bool IsV8 = (ArchKind == llvm::ARM::AK_ARMV8A || + ArchKind == llvm::ARM::AK_ARMV8_1A); + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") Features["vfp2"] = true; else if (CPU == "cortex-a8" || CPU == "cortex-a9") { @@ -4279,7 +4325,7 @@ public: Features["hwdiv-arm"] = true; Features["crc"] = true; Features["crypto"] = true; - } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || ArchVersion == 8) { + } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || IsV8) { Features["hwdiv"] = true; Features["hwdiv-arm"] = true; } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" || @@ -4362,14 +4408,26 @@ public: .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); } - const char *getCPUAttr() const { - const char *CPUAttr; + const char *getCPUDefineSuffix(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "8_1A"; + default: + break; + } + } + + unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name); + if (ArchKind == llvm::ARM::AK_INVALID) + return ""; + // For most sub-arches, the build attribute CPU name is enough. // For Cortex variants, it's slightly different. switch(ArchKind) { default: - CPUAttr = llvm::ARMTargetParser::getCPUAttr(ArchKind); - return CPUAttr ? CPUAttr : "" ; + return llvm::ARMTargetParser::getCPUAttr(ArchKind); case llvm::ARM::AK_ARMV6M: case llvm::ARM::AK_ARMV6SM: return "6M"; @@ -4389,8 +4447,23 @@ public: return "8_1A"; } } - const char *getCPUProfile() const { - switch(ArchProfile) { + const char *getCPUProfile(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "A"; + default: + break; + } + } + + unsigned CPUArch = llvm::ARMTargetParser::parseCPUArch(Name); + if (CPUArch == llvm::ARM::AK_INVALID) + return ""; + + StringRef ArchName = llvm::ARMTargetParser::getArchName(CPUArch); + switch(llvm::ARMTargetParser::parseArchProfile(ArchName)) { case llvm::ARM::PK_A: return "A"; case llvm::ARM::PK_R: @@ -4402,26 +4475,35 @@ public: } } bool setCPU(const std::string &Name) override { - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name); - if (ArchKind == llvm::ARM::AK_INVALID) + if (!getCPUDefineSuffix(Name)) return false; - setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind)); - setAtomic(); + + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + StringRef Profile = getCPUProfile(Name); + if (Profile == "M" && MaxAtomicInlineWidth) { + MaxAtomicPromoteWidth = 32; + MaxAtomicInlineWidth = 32; + } + CPU = Name; return true; } bool setFPMath(StringRef Name) override; - bool supportsThumb(StringRef CPUAttr) const { - return CPUAttr.count('T') || ArchVersion >= 6; - } - bool supportsThumb2(StringRef CPUAttr) const { - return CPUAttr.equals("6T2") || ArchVersion >= 7; + bool supportsThumb(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + return CPUArchVer >= 7 || (CPUArch.find('T') != StringRef::npos) || + (CPUArch.find('M') != StringRef::npos); + } + bool supportsThumb2(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + // We check both CPUArchVer and ArchName because when only triple is + // specified, the default CPU is arm1136j-s. + return ArchName.endswith("v6t2") || ArchName.endswith("v7") || + ArchName.endswith("v8.1a") || + ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { - StringRef CPUAttr = getCPUAttr(); - StringRef CPUProfile = getCPUProfile(); - // Target identification. Builder.defineMacro("__arm"); Builder.defineMacro("__arm__"); @@ -4429,12 +4511,19 @@ public: // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); - Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + StringRef CPUArch = getCPUDefineSuffix(CPU); + unsigned int CPUArchVer; + if (CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer)) + llvm_unreachable("Invalid char for architecture version number"); + Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); // ACLE 6.4.1 ARM/Thumb instruction set architecture + StringRef CPUProfile = getCPUProfile(CPU); + StringRef ArchName = getTriple().getArchName(); + // __ARM_ARCH is defined as an integer value indicating the current ARM ISA - Builder.defineMacro("__ARM_ARCH", std::to_string(ArchVersion)); - if (ArchVersion >= 8) { + Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1)); + if (CPUArch[0] >= '8') { Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); } @@ -4448,9 +4537,9 @@ public: // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original // Thumb ISA (including v6-M). It is set to 2 if the core supports the // Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture. - if (supportsThumb2(CPUAttr)) + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); - else if (supportsThumb(CPUAttr)) + else if (supportsThumb(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit @@ -4475,7 +4564,7 @@ public: // FIXME: It's more complicated than this and we don't really support // interworking. // Windows on ARM does not "support" interworking - if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) + if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows()) Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { @@ -4498,7 +4587,7 @@ public: if (IsThumb) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); - if (supportsThumb2(CPUAttr)) + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__thumb2__"); } if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb)) @@ -4521,7 +4610,7 @@ public: // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. - if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { + if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7) { Builder.defineMacro("__ARM_NEON"); Builder.defineMacro("__ARM_NEON__"); } @@ -4538,18 +4627,18 @@ public: if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO"); - if (ArchVersion >= 6 && CPUAttr != "6M") { + if (CPUArchVer >= 6 && CPUArch != "6M") { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } - bool is5EOrAbove = (ArchVersion >= 6 || - (ArchVersion == 5 && CPUAttr.count('E'))); - // FIXME: We are not getting all 32-bit ARM architectures - bool is32Bit = (!IsThumb || supportsThumb2(CPUAttr)); - if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUAttr == "7EM")) + bool is5EOrAbove = (CPUArchVer >= 6 || + (CPUArchVer == 5 && + CPUArch.find('E') != StringRef::npos)); + bool is32Bit = (!IsThumb || supportsThumb2(ArchName, CPUArch, CPUArchVer)); + if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUArch == "7EM")) Builder.defineMacro("__ARM_FEATURE_DSP"); } void getTargetBuiltins(const Builtin::Info *&Records, @@ -6632,6 +6721,19 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, NumAliases = 0; } +// We attempt to use PNaCl (le32) frontend and Mips32EL backend. +class NaClMips32ELTargetInfo : public Mips32ELTargetInfo { +public: + NaClMips32ELTargetInfo(const llvm::Triple &Triple) : + Mips32ELTargetInfo(Triple) { + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } +}; + class Le64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; @@ -7002,7 +7104,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { case llvm::Triple::NetBSD: return new NetBSDTargetInfo<Mips32ELTargetInfo>(Triple); case llvm::Triple::NaCl: - return new NaClTargetInfo<Mips32ELTargetInfo>(Triple); + return new NaClTargetInfo<NaClMips32ELTargetInfo>(Triple); default: return new Mips32ELTargetInfo(Triple); } diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 0bccad0570da..afcb9e5c5055 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -292,6 +292,7 @@ void EmitAssemblyHelper::CreatePasses() { PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime; PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops; PMBuilder.MergeFunctions = CodeGenOpts.MergeFunctions; + PMBuilder.PrepareForLTO = CodeGenOpts.PrepareForLTO; PMBuilder.RerollLoops = CodeGenOpts.RerollLoops; PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible, @@ -454,8 +455,6 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } - if (llvm::TimePassesIsEnabled) - BackendArgs.push_back("-time-passes"); for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); BackendArgs.push_back(nullptr); diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp index da82249fe114..9839617c0e41 100644 --- a/lib/CodeGen/CGAtomic.cpp +++ b/lib/CodeGen/CGAtomic.cpp @@ -93,6 +93,7 @@ namespace { BFI = OrigBFI; BFI.Offset = Offset; BFI.StorageSize = AtomicSizeInBits; + BFI.StorageOffset += OffsetInChars; LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(), lvalue.getAlignment()); LVal.setTBAAInfo(lvalue.getTBAAInfo()); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2ec909b9aac5..9e538703177d 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -535,7 +535,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_readcyclecounter: { Value *F = CGM.getIntrinsic(Intrinsic::readcyclecounter); - return RValue::get(Builder.CreateCall(F, {})); + return RValue::get(Builder.CreateCall(F)); } case Builtin::BI__builtin___clear_cache: { Value *Begin = EmitScalarExpr(E->getArg(0)); @@ -923,7 +923,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_unwind_init: { Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init); - return RValue::get(Builder.CreateCall(F, {})); + return RValue::get(Builder.CreateCall(F)); } case Builtin::BI__builtin_extend_pointer: { // Extends a pointer to the size of an _Unwind_Word, which is @@ -962,7 +962,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Store the stack pointer to the setjmp buffer. Value *StackAddr = - Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave), {}); + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave)); Value *StackSaveSlot = Builder.CreateGEP(Buf, ConstantInt::get(Int32Ty, 2)); Builder.CreateStore(StackAddr, StackSaveSlot); @@ -3399,7 +3399,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, : InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "", /*SideEffects=*/true); - return Builder.CreateCall(Emit, {}); + return Builder.CreateCall(Emit); } if (BuiltinID == ARM::BI__builtin_arm_dbg) { @@ -3543,7 +3543,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, if (BuiltinID == ARM::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex); - return Builder.CreateCall(F, {}); + return Builder.CreateCall(F); } // CRC32 @@ -4339,7 +4339,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, if (BuiltinID == AArch64::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex); - return Builder.CreateCall(F, {}); + return Builder.CreateCall(F); } // CRC32 @@ -6375,7 +6375,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, break; } - Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID), {}); + Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID)); Builder.CreateStore(Builder.CreateExtractValue(Call, 0), Ops[0]); return Builder.CreateExtractValue(Call, 1); } @@ -6633,14 +6633,104 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(ID); return Builder.CreateCall(F, Ops, ""); } + // Square root + case PPC::BI__builtin_vsx_xvsqrtsp: + case PPC::BI__builtin_vsx_xvsqrtdp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + ID = Intrinsic::sqrt; + llvm::Function *F = CGM.getIntrinsic(ID, ResultType); + return Builder.CreateCall(F, X); + } + // Count leading zeros + case PPC::BI__builtin_altivec_vclzb: + case PPC::BI__builtin_altivec_vclzh: + case PPC::BI__builtin_altivec_vclzw: + case PPC::BI__builtin_altivec_vclzd: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); + Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType); + return Builder.CreateCall(F, {X, Undef}); + } + // Copy sign + case PPC::BI__builtin_vsx_xvcpsgnsp: + case PPC::BI__builtin_vsx_xvcpsgndp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + ID = Intrinsic::copysign; + llvm::Function *F = CGM.getIntrinsic(ID, ResultType); + return Builder.CreateCall(F, {X, Y}); + } + // Rounding/truncation case PPC::BI__builtin_vsx_xvrspip: case PPC::BI__builtin_vsx_xvrdpip: + case PPC::BI__builtin_vsx_xvrdpim: + case PPC::BI__builtin_vsx_xvrspim: + case PPC::BI__builtin_vsx_xvrdpi: + case PPC::BI__builtin_vsx_xvrspi: + case PPC::BI__builtin_vsx_xvrdpic: + case PPC::BI__builtin_vsx_xvrspic: + case PPC::BI__builtin_vsx_xvrdpiz: + case PPC::BI__builtin_vsx_xvrspiz: { llvm::Type *ResultType = ConvertType(E->getType()); Value *X = EmitScalarExpr(E->getArg(0)); - ID = Intrinsic::ceil; + if (BuiltinID == PPC::BI__builtin_vsx_xvrdpim || + BuiltinID == PPC::BI__builtin_vsx_xvrspim) + ID = Intrinsic::floor; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpi || + BuiltinID == PPC::BI__builtin_vsx_xvrspi) + ID = Intrinsic::round; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpic || + BuiltinID == PPC::BI__builtin_vsx_xvrspic) + ID = Intrinsic::nearbyint; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpip || + BuiltinID == PPC::BI__builtin_vsx_xvrspip) + ID = Intrinsic::ceil; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpiz || + BuiltinID == PPC::BI__builtin_vsx_xvrspiz) + ID = Intrinsic::trunc; llvm::Function *F = CGM.getIntrinsic(ID, ResultType); return Builder.CreateCall(F, X); } + // FMA variations + case PPC::BI__builtin_vsx_xvmaddadp: + case PPC::BI__builtin_vsx_xvmaddasp: + case PPC::BI__builtin_vsx_xvnmaddadp: + case PPC::BI__builtin_vsx_xvnmaddasp: + case PPC::BI__builtin_vsx_xvmsubadp: + case PPC::BI__builtin_vsx_xvmsubasp: + case PPC::BI__builtin_vsx_xvnmsubadp: + case PPC::BI__builtin_vsx_xvnmsubasp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + Value *Z = EmitScalarExpr(E->getArg(2)); + Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); + switch (BuiltinID) { + case PPC::BI__builtin_vsx_xvmaddadp: + case PPC::BI__builtin_vsx_xvmaddasp: + return Builder.CreateCall(F, {X, Y, Z}); + case PPC::BI__builtin_vsx_xvnmaddadp: + case PPC::BI__builtin_vsx_xvnmaddasp: + return Builder.CreateFSub(Zero, + Builder.CreateCall(F, {X, Y, Z}), "sub"); + case PPC::BI__builtin_vsx_xvmsubadp: + case PPC::BI__builtin_vsx_xvmsubasp: + return Builder.CreateCall(F, + {X, Y, Builder.CreateFSub(Zero, Z, "sub")}); + case PPC::BI__builtin_vsx_xvnmsubadp: + case PPC::BI__builtin_vsx_xvnmsubasp: + Value *FsubRes = + Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")}); + return Builder.CreateFSub(Zero, FsubRes, "sub"); + } + llvm_unreachable("Unknown FMA operation"); + return nullptr; // Suppress no-return warning + } + } } // Emit an intrinsic that has 1 float or double. diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 0535c05da5d5..3e4d7f323d46 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -912,20 +912,21 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, /// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as -/// a pointer to an object of type \arg Ty. +/// a pointer to an object of type \arg Ty, known to be aligned to +/// \arg SrcAlign bytes. /// /// This safely handles the case when the src type is smaller than the /// destination type; in this situation the values of bits which not /// present in the src are undefined. static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, - llvm::Type *Ty, + llvm::Type *Ty, CharUnits SrcAlign, CodeGenFunction &CGF) { llvm::Type *SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); // If SrcTy and Ty are the same, just do a load. if (SrcTy == Ty) - return CGF.Builder.CreateLoad(SrcPtr); + return CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity()); uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty); @@ -940,7 +941,8 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // extension or truncation to the desired type. if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) && (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) { - llvm::LoadInst *Load = CGF.Builder.CreateLoad(SrcPtr); + llvm::LoadInst *Load = + CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity()); return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF); } @@ -954,23 +956,20 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // to that information. llvm::Value *Casted = CGF.Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(Ty)); - llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted); - // FIXME: Use better alignment / avoid requiring aligned load. - Load->setAlignment(1); - return Load; + return CGF.Builder.CreateAlignedLoad(Casted, SrcAlign.getQuantity()); } // Otherwise do coercion through memory. This is stupid, but // simple. - llvm::Value *Tmp = CGF.CreateTempAlloca(Ty); + llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(Ty); + Tmp->setAlignment(SrcAlign.getQuantity()); llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy); - // FIXME: Use better alignment. CGF.Builder.CreateMemCpy(Casted, SrcCasted, llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize), - 1, false); - return CGF.Builder.CreateLoad(Tmp); + SrcAlign.getQuantity(), false); + return CGF.Builder.CreateAlignedLoad(Tmp, SrcAlign.getQuantity()); } // Function to store a first-class aggregate into memory. We prefer to @@ -979,39 +978,45 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // FIXME: Do we need to recurse here? static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, llvm::Value *DestPtr, bool DestIsVolatile, - bool LowAlignment) { + CharUnits DestAlign) { // Prefer scalar stores to first-class aggregate stores. if (llvm::StructType *STy = dyn_cast<llvm::StructType>(Val->getType())) { + const llvm::StructLayout *Layout = + CGF.CGM.getDataLayout().getStructLayout(STy); + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(STy, DestPtr, 0, i); llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i); - llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr, - DestIsVolatile); - if (LowAlignment) - SI->setAlignment(1); + uint64_t EltOffset = Layout->getElementOffset(i); + CharUnits EltAlign = + DestAlign.alignmentAtOffset(CharUnits::fromQuantity(EltOffset)); + CGF.Builder.CreateAlignedStore(Elt, EltPtr, EltAlign.getQuantity(), + DestIsVolatile); } } else { - llvm::StoreInst *SI = CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile); - if (LowAlignment) - SI->setAlignment(1); + CGF.Builder.CreateAlignedStore(Val, DestPtr, DestAlign.getQuantity(), + DestIsVolatile); } } /// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src, -/// where the source and destination may have different types. +/// where the source and destination may have different types. The +/// destination is known to be aligned to \arg DstAlign bytes. /// /// This safely handles the case when the src type is larger than the /// destination type; the upper bits of the src will be lost. static void CreateCoercedStore(llvm::Value *Src, llvm::Value *DstPtr, bool DstIsVolatile, + CharUnits DstAlign, CodeGenFunction &CGF) { llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType(); if (SrcTy == DstTy) { - CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); + CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(), + DstIsVolatile); return; } @@ -1027,7 +1032,8 @@ static void CreateCoercedStore(llvm::Value *Src, if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) && (isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) { Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF); - CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); + CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(), + DstIsVolatile); return; } @@ -1037,8 +1043,7 @@ static void CreateCoercedStore(llvm::Value *Src, if (SrcSize <= DstSize) { llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); - // FIXME: Use better alignment / avoid requiring aligned store. - BuildAggStore(CGF, Src, Casted, DstIsVolatile, true); + BuildAggStore(CGF, Src, Casted, DstIsVolatile, DstAlign); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -1049,15 +1054,15 @@ static void CreateCoercedStore(llvm::Value *Src, // // FIXME: Assert that we aren't truncating non-padding bits when have access // to that information. - llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy); - CGF.Builder.CreateStore(Src, Tmp); + llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(SrcTy); + Tmp->setAlignment(DstAlign.getQuantity()); + CGF.Builder.CreateAlignedStore(Src, Tmp, DstAlign.getQuantity()); llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy); - // FIXME: Use better alignment. CGF.Builder.CreateMemCpy(DstCasted, Casted, llvm::ConstantInt::get(CGF.IntPtrTy, DstSize), - 1, false); + DstAlign.getQuantity(), false); } } @@ -1506,7 +1511,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); if (FD) { - if (const TargetAttr *TD = FD->getAttr<TargetAttr>()) { + if (const auto *TD = FD->getAttr<TargetAttr>()) { StringRef FeaturesStr = TD->getFeatures(); SmallVector<StringRef, 1> AttrFeatures; FeaturesStr.split(AttrFeatures, ","); @@ -1514,9 +1519,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // Grab the various features and prepend a "+" to turn on the feature to // the backend and add them to our existing set of features. for (auto &Feature : AttrFeatures) { + // Go ahead and trim whitespace rather than either erroring or + // accepting it weirdly. + Feature = Feature.trim(); + // While we're here iterating check for a different target cpu. if (Feature.startswith("arch=")) - TargetCPU = Feature.split("=").second; + TargetCPU = Feature.split("=").second.trim(); else if (Feature.startswith("tune=")) // We don't support cpu tuning this way currently. ; @@ -1992,6 +2001,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Alloca->setAlignment(AlignmentToUse); llvm::Value *V = Alloca; llvm::Value *Ptr = V; // Pointer to store into. + CharUnits PtrAlign = CharUnits::fromQuantity(AlignmentToUse); // If the value is offset in memory, apply the offset now. if (unsigned Offs = ArgI.getDirectOffset()) { @@ -1999,6 +2009,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Ptr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), Ptr, Offs); Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(ArgI.getCoerceToType())); + PtrAlign = PtrAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } // Fast-isel and the optimizer generally like scalar values better than @@ -2043,7 +2054,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, assert(NumIRArgs == 1); auto AI = FnArgs[FirstIRArg]; AI->setName(Arg->getName() + ".coerce"); - CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, *this); + CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, PtrAlign, *this); } @@ -2411,15 +2422,17 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, } } else { llvm::Value *V = ReturnValue; + CharUnits Align = getContext().getTypeAlignInChars(RetTy); // If the value is offset in memory, apply the offset now. if (unsigned Offs = RetAI.getDirectOffset()) { V = Builder.CreateBitCast(V, Builder.getInt8PtrTy()); V = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), V, Offs); V = Builder.CreateBitCast(V, llvm::PointerType::getUnqual(RetAI.getCoerceToType())); + Align = Align.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } - RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this); + RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), Align, *this); } // In ARC, end functions that return a retainable type with a call @@ -3282,12 +3295,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. llvm::Value *SrcPtr; + CharUnits SrcAlign; if (RV.isScalar() || RV.isComplex()) { SrcPtr = CreateMemTemp(I->Ty, "coerce"); + SrcAlign = TypeAlign; LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign); EmitInitStoreOfNonAggregate(*this, RV, SrcLV); - } else + } else { SrcPtr = RV.getAggregateAddr(); + // This alignment is guaranteed by EmitCallArg. + SrcAlign = TypeAlign; + } // If the value is offset in memory, apply the offset now. if (unsigned Offs = ArgInfo.getDirectOffset()) { @@ -3295,7 +3313,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, SrcPtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), SrcPtr, Offs); SrcPtr = Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(ArgInfo.getCoerceToType())); - + SrcAlign = SrcAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } // Fast-isel and the optimizer generally like scalar values better than @@ -3334,7 +3352,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // In the simple case, just pass the coerced loaded value. assert(NumIRArgs == 1); IRCallArgs[FirstIRArg] = - CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), *this); + CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), + SrcAlign, *this); } break; @@ -3531,12 +3550,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case TEK_Aggregate: { llvm::Value *DestPtr = ReturnValue.getValue(); bool DestIsVolatile = ReturnValue.isVolatile(); + CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy); if (!DestPtr) { DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } - BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false); + BuildAggStore(*this, CI, DestPtr, DestIsVolatile, DestAlign); return RValue::getAggregate(DestPtr); } case TEK_Scalar: { @@ -3553,6 +3573,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *DestPtr = ReturnValue.getValue(); bool DestIsVolatile = ReturnValue.isVolatile(); + CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy); if (!DestPtr) { DestPtr = CreateMemTemp(RetTy, "coerce"); @@ -3561,14 +3582,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the value is offset in memory, apply the offset now. llvm::Value *StorePtr = DestPtr; + CharUnits StoreAlign = DestAlign; if (unsigned Offs = RetAI.getDirectOffset()) { StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy()); StorePtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), StorePtr, Offs); StorePtr = Builder.CreateBitCast(StorePtr, llvm::PointerType::getUnqual(RetAI.getCoerceToType())); + StoreAlign = + StoreAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } - CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this); + CreateCoercedStore(CI, StorePtr, DestIsVolatile, StoreAlign, *this); return convertTempToRValue(DestPtr, RetTy, SourceLocation()); } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 62df9820a6c3..c49f182c21d8 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -554,6 +554,20 @@ static bool isMemcpyEquivalentSpecialMember(const CXXMethodDecl *D) { return false; } +static void EmitLValueForAnyFieldInitialization(CodeGenFunction &CGF, + CXXCtorInitializer *MemberInit, + LValue &LHS) { + FieldDecl *Field = MemberInit->getAnyMember(); + if (MemberInit->isIndirectMemberInitializer()) { + // If we are initializing an anonymous union field, drill down to the field. + IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember(); + for (const auto *I : IndirectField->chain()) + LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I)); + } else { + LHS = CGF.EmitLValueForFieldInitialization(LHS, Field); + } +} + static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXCtorInitializer *MemberInit, @@ -572,16 +586,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); - if (MemberInit->isIndirectMemberInitializer()) { - // If we are initializing an anonymous union field, drill down to - // the field. - IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember(); - for (const auto *I : IndirectField->chain()) - LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I)); - FieldType = MemberInit->getIndirectMember()->getAnonField()->getType(); - } else { - LHS = CGF.EmitLValueForFieldInitialization(LHS, Field); - } + EmitLValueForAnyFieldInitialization(CGF, MemberInit, LHS); // Special case: if we are in a copy or move constructor, and we are copying // an array of PODs or classes with trivial copy constructors, ignore the @@ -606,6 +611,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // Copy the aggregate. CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType, LHS.isVolatileQualified()); + // Ensure that we destroy the objects if an exception is thrown later in + // the constructor. + QualType::DestructionKind dtorKind = FieldType.isDestructedType(); + if (CGF.needsEHCleanup(dtorKind)) + CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); return; } } @@ -906,32 +916,18 @@ namespace { return; } - CharUnits Alignment; - uint64_t FirstByteOffset; if (FirstField->isBitField()) { const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(FirstField->getParent()); const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField); - Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment); // FirstFieldOffset is not appropriate for bitfields, - // it won't tell us what the storage offset should be and thus might not - // be properly aligned. - // - // Instead calculate the storage offset using the offset of the field in - // the struct type. - const llvm::DataLayout &DL = CGF.CGM.getDataLayout(); - FirstByteOffset = - DL.getStructLayout(RL.getLLVMType()) - ->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField)); + // we need to use the storage offset instead. + FirstByteOffset = CGF.getContext().toBits(BFInfo.StorageOffset); } else { - Alignment = CGF.getContext().getDeclAlign(FirstField); FirstByteOffset = FirstFieldOffset; } - assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) % - Alignment) == 0 && "Bad field alignment."); - CharUnits MemcpySize = getMemcpySize(FirstByteOffset); QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); llvm::Value *ThisPtr = CGF.LoadCXXThis(); @@ -941,6 +937,9 @@ namespace { LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField); + CharUnits Offset = CGF.getContext().toCharUnitsFromBits(FirstByteOffset); + CharUnits Alignment = DestLV.getAlignment().alignmentAtOffset(Offset); + emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(), Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(), MemcpySize, Alignment); @@ -1078,6 +1077,7 @@ namespace { CopyingValueRepresentation CVR(CGF); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), AggregatedInits[0], ConstructorDecl, Args); + AggregatedInits.clear(); } reset(); return; @@ -1094,10 +1094,14 @@ namespace { LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); for (unsigned i = 0; i < AggregatedInits.size(); ++i) { - QualType FieldType = AggregatedInits[i]->getMember()->getType(); + CXXCtorInitializer *MemberInit = AggregatedInits[i]; + QualType FieldType = MemberInit->getAnyMember()->getType(); QualType::DestructionKind dtorKind = FieldType.isDestructedType(); - if (CGF.needsEHCleanup(dtorKind)) - CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); + if (!CGF.needsEHCleanup(dtorKind)) + continue; + LValue FieldLHS = LHS; + EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS); + CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType); } } @@ -1363,6 +1367,25 @@ static bool CanSkipVTablePointerInitialization(ASTContext &Context, return true; } +// Generates function call for handling object poisoning, passing in +// references to 'this' and its size as arguments. +static void EmitDtorSanitizerCallback(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor) { + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(Dtor->getParent()); + + llvm::Value *Args[] = { + CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy), + llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())}; + llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy}; + + llvm::FunctionType *FnType = + llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false); + llvm::Value *Fn = + CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback"); + CGF.EmitNounwindRuntimeCall(Fn, Args); +} + /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl()); @@ -1450,6 +1473,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true); + + // Insert memory-poisoning instrumentation. + if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor) + EmitDtorSanitizerCallback(*this, Dtor); } void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { @@ -2202,8 +2229,7 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc) { - // FIXME: Add blacklisting scheme. - if (RD->isInStdNamespace()) + if (CGM.IsCFIBlacklistedRecord(RD)) return; SanitizerScope SanScope(this); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 8c4b4b3d0617..93a2287b1e01 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -106,8 +106,6 @@ ApplyDebugLocation::~ApplyDebugLocation() { CGF.Builder.SetCurrentDebugLocation(std::move(OriginalLocation)); } -/// ArtificialLocation - An RAII object that temporarily switches to -/// an artificial debug location that has a valid scope, but no line void CGDebugInfo::setLocation(SourceLocation Loc) { // If the new location isn't valid return. if (Loc.isInvalid()) @@ -140,7 +138,6 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { } } -/// getContextDescriptor - Get context info for the decl. llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) { if (!Context) return TheCU; @@ -162,9 +159,6 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) { return TheCU; } -/// getFunctionName - Get function name for the given FunctionDecl. If the -/// name is constructed on demand (e.g. C++ destructor) then the name -/// is stored on the side. StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert(FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); @@ -220,13 +214,10 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { return internString(OS.str()); } -/// getSelectorName - Return selector name. This is used for debugging -/// info. StringRef CGDebugInfo::getSelectorName(Selector S) { return internString(S.getAsString()); } -/// getClassName - Get class name including template argument list. StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { // quick optimization to avoid having to intern strings that are already // stored reliably elsewhere @@ -244,7 +235,6 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { return internString(Name); } -/// getOrCreateFile - Get the file debug info descriptor for the input location. llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (!Loc.isValid()) // If Location is not valid then use main input file. @@ -274,13 +264,10 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { return F; } -/// getOrCreateMainFile - Get the file info for main compile unit. llvm::DIFile *CGDebugInfo::getOrCreateMainFile() { return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory()); } -/// getLineNumber - Get line number for the location. If location is invalid -/// then use current location. unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { if (Loc.isInvalid() && CurLoc.isInvalid()) return 0; @@ -289,7 +276,6 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { return PLoc.isValid() ? PLoc.getLine() : 0; } -/// getColumnNumber - Get column number for the location. unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { // We may not want column information at all. if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo) @@ -314,7 +300,6 @@ StringRef CGDebugInfo::getCurrentDirname() { return CWDName = internString(CWD); } -/// CreateCompileUnit - Create new compile unit. void CGDebugInfo::CreateCompileUnit() { // Should we be asking the SourceManager for the main file name, instead of @@ -385,8 +370,6 @@ void CGDebugInfo::CreateCompileUnit() { DebugKind != CodeGenOptions::LocTrackingOnly); } -/// CreateType - Get the Basic type from the cache or create a new -/// one if necessary. llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::dwarf::TypeKind Encoding; StringRef BTName; @@ -537,8 +520,6 @@ llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { return DBuilder.createBasicType("complex", Size, Align, Encoding); } -/// CreateCVRType - Get the qualified type from the cache or create -/// a new one if necessary. llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit) { QualifierCollector Qc; @@ -627,6 +608,7 @@ static SmallString<256> getUniqueTagTypeName(const TagType *Ty, return FullName; } +/// \return the approproate DWARF tag for a composite type. static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { llvm::dwarf::Tag Tag; if (RD->isStruct() || RD->isInterface()) @@ -642,7 +624,6 @@ static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { return Tag; } -// Creates a forward declaration for a RecordDecl in the given context. llvm::DICompositeType * CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DIScope *Ctx) { @@ -705,9 +686,6 @@ llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIFile *Unit) { - if (BlockLiteralGeneric) - return BlockLiteralGeneric; - SmallVector<llvm::Metadata *, 8> EltTys; QualType FType; uint64_t FieldSize, FieldOffset; @@ -723,10 +701,10 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.clear(); unsigned Flags = llvm::DINode::FlagAppleBlock; - unsigned LineNo = getLineNumber(CurLoc); + unsigned LineNo = 0; auto *EltTy = - DBuilder.createStructType(Unit, "__block_descriptor", Unit, LineNo, + DBuilder.createStructType(Unit, "__block_descriptor", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); // Bit size, align and offset of the type. @@ -746,19 +724,22 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldSize = CGM.getContext().getTypeSize(Ty); FieldAlign = CGM.getContext().getTypeAlign(Ty); - EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", Unit, LineNo, + EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign, FieldOffset, 0, DescTy)); FieldOffset += FieldSize; Elements = DBuilder.getOrCreateArray(EltTys); + // The __block_literal_generic structs are marked with a special + // DW_AT_APPLE_BLOCK attribute and are an implementation detail only + // the debugger needs to know about. To allow type uniquing, emit + // them without a name or a location. EltTy = - DBuilder.createStructType(Unit, "__block_literal_generic", Unit, LineNo, + DBuilder.createStructType(Unit, "", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); - BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size); - return BlockLiteralGeneric; + return DBuilder.createPointerType(EltTy, Size); } llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, @@ -871,7 +852,6 @@ llvm::DIType *CGDebugInfo::createFieldType( AlignInBits, offsetInBits, flags, debugType); } -/// CollectRecordLambdaFields - Helper for CollectRecordFields. void CGDebugInfo::CollectRecordLambdaFields( const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy) { @@ -916,7 +896,6 @@ void CGDebugInfo::CollectRecordLambdaFields( } } -/// Helper for CollectRecordFields. llvm::DIDerivedType * CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, const RecordDecl *RD) { @@ -946,7 +925,6 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, return GV; } -/// CollectRecordNormalField - Helper for CollectRecordFields. void CGDebugInfo::CollectRecordNormalField( const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit, SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy, @@ -971,8 +949,6 @@ void CGDebugInfo::CollectRecordNormalField( elements.push_back(fieldType); } -/// CollectRecordFields - A helper function to collect debug info for -/// record fields. This is used while creating debug info entry for a Record. void CGDebugInfo::CollectRecordFields( const RecordDecl *record, llvm::DIFile *tunit, SmallVectorImpl<llvm::Metadata *> &elements, @@ -1011,9 +987,6 @@ void CGDebugInfo::CollectRecordFields( } } -/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This -/// function type is not updated to include implicit "this" pointer. Use this -/// routine to get a method type which includes "this" pointer. llvm::DISubroutineType * CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *Unit) { @@ -1088,8 +1061,6 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) { return false; } -/// CreateCXXMemberFunction - A helper function to create a subprogram for -/// a single member function GlobalDecl. llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { bool IsCtorOrDtor = @@ -1165,9 +1136,6 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( return SP; } -/// CollectCXXMemberFunctions - A helper function to collect debug info for -/// C++ member functions. This is used while creating debug info entry for -/// a Record. void CGDebugInfo::CollectCXXMemberFunctions( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) { @@ -1206,9 +1174,6 @@ void CGDebugInfo::CollectCXXMemberFunctions( } } -/// CollectCXXBases - A helper function to collect debug info for -/// C++ base classes. This is used while creating debug info entry for -/// a Record. void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) { @@ -1246,7 +1211,6 @@ void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, } } -/// CollectTemplateParams - A helper function to collect template parameters. llvm::DINodeArray CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef<TemplateArgument> TAList, @@ -1351,8 +1315,6 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, return DBuilder.getOrCreateArray(TemplateParams); } -/// CollectFunctionTemplateParams - A helper function to collect debug -/// info for function template parameters. llvm::DINodeArray CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile *Unit) { @@ -1367,8 +1329,6 @@ CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, return llvm::DINodeArray(); } -/// CollectCXXTemplateParams - A helper function to collect debug info for -/// template parameters. llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { // Always get the full list of parameters, not just the ones from @@ -1379,7 +1339,6 @@ llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( return CollectTemplateParams(TPList, TAList.asArray(), Unit); } -/// getOrCreateVTablePtrType - Return debug info descriptor for vtable. llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; @@ -1397,14 +1356,11 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { return VTablePtrType; } -/// getVTableName - Get vtable name for the given Class. StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Copy the gdb compatible name on the side and use its reference. return internString("_vptr$", RD->getNameAsString()); } -/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate -/// debug info entry in EltTys vector. void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -1424,7 +1380,6 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, EltTys.push_back(VPTR); } -/// getOrCreateRecordType - Emit record type's standalone debug info. llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -1432,8 +1387,6 @@ llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, return T; } -/// getOrCreateInterfaceType - Emit an objective c interface type standalone -/// debug info. llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -1531,7 +1484,6 @@ static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind, return false; } -/// CreateType - get structure or union type. llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0))); @@ -1605,7 +1557,6 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { return FwdDecl; } -/// CreateType - get objective-c object type. llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty, llvm::DIFile *Unit) { // Ignore protocols. @@ -1636,7 +1587,6 @@ static bool hasDefaultSetterName(const ObjCPropertyDecl *PD, Setter->getDeclName().getObjCSelector().getNameForSlot(0); } -/// CreateType - get objective-c interface type. llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); @@ -1956,7 +1906,6 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getValueType(), U); } -/// CreateEnumType - get enumeration type. llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; @@ -2076,8 +2025,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { } while (true); } -/// getType - Get the type from the cache or return null type if it doesn't -/// exist. llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) { // Unwrap the type as needed for debug information. @@ -2104,8 +2051,6 @@ void CGDebugInfo::completeTemplateDefinition( RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr()); } -/// getOrCreateType - Get the type from the cache or create a new -/// one if necessary. llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (Ty.isNull()) return nullptr; @@ -2126,8 +2071,6 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { return Res; } -/// Currently the checksum of an interface includes the number of -/// ivars and property accessors. unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) { // The assumption is that the number of ivars can only increase // monotonically, so it is safe to just use their current number as @@ -2152,7 +2095,6 @@ ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) { } } -/// CreateTypeNode - Create a new debug type node. llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) @@ -2233,8 +2175,6 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { llvm_unreachable("type should have been unwrapped!"); } -/// getOrCreateLimitedType - Get the type from the cache or create a new -/// limited type if necessary. llvm::DIType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *Unit) { QualType QTy(Ty, 0); @@ -2328,7 +2268,6 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, DBuilder.replaceVTableHolder(RealDecl, ContainingType); } -/// CreateMemberType - Create new member and increase Offset by FType's size. llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType, StringRef Name, uint64_t *Offset) { llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); @@ -2493,8 +2432,6 @@ llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { return nullptr; } -/// getFunctionDeclaration - Return debug info descriptor to describe method -/// declaration for the given method definition. llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly) return nullptr; @@ -2591,7 +2528,6 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F)); } -/// EmitFunctionStart - Constructs the debug code for entering a function. void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { @@ -2667,9 +2603,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, RegionMap[D].reset(SP); } -/// EmitLocation - Emit metadata to indicate a change in line/column -/// information in the source file. If the location is invalid, the -/// previous location will be reused. void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { // Update our current location setLocation(Loc); @@ -2682,8 +2615,6 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope)); } -/// CreateLexicalBlock - Creates a new lexical block node and pushes it on -/// the stack. void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { llvm::MDNode *Back = nullptr; if (!LexicalBlockStack.empty()) @@ -2693,8 +2624,6 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { getColumnNumber(CurLoc))); } -/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative -/// region - beginning of a DW_TAG_lexical_block. void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { // Set our current location. @@ -2711,8 +2640,6 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, CreateLexicalBlock(Loc); } -/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative -/// region - end of a DW_TAG_lexical_block. void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); @@ -2726,7 +2653,6 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, LexicalBlockStack.pop_back(); } -/// EmitFunctionEnd - Constructs the debug code for exiting a function. void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); unsigned RCount = FnBeginRegionCount.back(); @@ -2741,8 +2667,6 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { FnBeginRegionCount.pop_back(); } -// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. -// See BuildByRefType. llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *XOffset) { @@ -2816,7 +2740,6 @@ llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, nullptr, Elements); } -/// EmitDeclare - Emit local variable declaration debug info. void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::Tag Tag, llvm::Value *Storage, unsigned ArgNo, CGBuilderTy &Builder) { @@ -2944,12 +2867,6 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); } -/// Look up the completed type for a self pointer in the TypeCache and -/// create a copy of it with the ObjectPointer and Artificial flags -/// set. If the type is not cached, a new one is created. This should -/// never happen though, since creating a type for the implicit self -/// argument implies that we already parsed the interface definition -/// and the ivar declarations in the implementation. llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType *Ty) { llvm::DIType *CachedTy = getTypeOrNull(QualTy); @@ -3027,8 +2944,6 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( Builder.GetInsertBlock()); } -/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument -/// variable declaration. void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { @@ -3192,8 +3107,6 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, Builder.GetInsertBlock()); } -/// If D is an out-of-class definition of a static data member of a class, find -/// its corresponding in-class declaration. llvm::DIDerivedType * CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { if (!D->isStaticDataMember()) @@ -3213,9 +3126,6 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC)); } -/// Recursively collect all of the member fields of a global anonymous decl and -/// create static variables for them. The first time this is called it needs -/// to be on a union and then from there we can have additional unnamed fields. llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls( const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) { @@ -3241,7 +3151,6 @@ llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls( return GV; } -/// EmitGlobalVariable - Emit information about a global variable. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -3274,7 +3183,6 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, DeclCache[D->getCanonicalDecl()].reset(static_cast<llvm::Metadata *>(GV)); } -/// EmitGlobalVariable - Emit global variable's debug info. void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -3380,8 +3288,6 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { return R; } -/// getOrCreateNamesSpace - Return namespace descriptor for the given -/// namespace decl. llvm::DINamespace * CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { NSDecl = NSDecl->getCanonicalDecl(); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 10d3b0d9ab02..4c77a8d28974 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -26,26 +26,26 @@ #include "llvm/Support/Allocator.h" namespace llvm { - class MDNode; +class MDNode; } namespace clang { - class CXXMethodDecl; - class VarDecl; - class ObjCInterfaceDecl; - class ObjCIvarDecl; - class ClassTemplateSpecializationDecl; - class GlobalDecl; - class UsingDecl; +class CXXMethodDecl; +class VarDecl; +class ObjCInterfaceDecl; +class ObjCIvarDecl; +class ClassTemplateSpecializationDecl; +class GlobalDecl; +class UsingDecl; namespace CodeGen { - class CodeGenModule; - class CodeGenFunction; - class CGBlockInfo; +class CodeGenModule; +class CodeGenFunction; +class CGBlockInfo; -/// \brief This class gathers all debug information during compilation -/// and is responsible for emitting to llvm globals or pass directly to -/// the backend. +/// This class gathers all debug information during compilation and is +/// responsible for emitting to llvm globals or pass directly to the +/// backend. class CGDebugInfo { friend class ApplyDebugLocation; friend class SaveAndRestoreLocation; @@ -65,9 +65,8 @@ class CGDebugInfo { llvm::DIType *OCLImage2dArrayDITy = nullptr; llvm::DIType *OCLImage3dDITy = nullptr; llvm::DIType *OCLEventDITy = nullptr; - llvm::DIType *BlockLiteralGeneric = nullptr; - /// \brief Cache of previously constructed Types. + /// Cache of previously constructed Types. llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache; struct ObjCInterfaceCacheEntry { @@ -79,41 +78,40 @@ class CGDebugInfo { : Type(Type), Decl(Decl), Unit(Unit) {} }; - /// \brief Cache of previously constructed interfaces - /// which may change. + /// Cache of previously constructed interfaces which may change. llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache; - /// \brief Cache of references to AST files such as PCHs or modules. + /// Cache of references to AST files such as PCHs or modules. llvm::DenseMap<uint64_t, llvm::DIModule *> ModuleRefCache; - /// \brief list of interfaces we want to keep even if orphaned. + /// List of interfaces we want to keep even if orphaned. std::vector<void *> RetainedTypes; - /// \brief Cache of forward declared types to RAUW at the end of + /// Cache of forward declared types to RAUW at the end of /// compilation. std::vector<std::pair<const TagType *, llvm::TrackingMDRef>> ReplaceMap; - /// \brief Cache of replaceable forward declarartions (functions and + /// Cache of replaceable forward declarartions (functions and /// variables) to RAUW at the end of compilation. std::vector<std::pair<const DeclaratorDecl *, llvm::TrackingMDRef>> FwdDeclReplaceMap; - // LexicalBlockStack - Keep track of our current nested lexical block. + /// Keep track of our current nested lexical block. std::vector<llvm::TypedTrackingMDRef<llvm::DIScope>> LexicalBlockStack; llvm::DenseMap<const Decl *, llvm::TrackingMDRef> RegionMap; - // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the - // beginning of a function. This is used to pop unbalanced regions at - // the end of a function. + /// Keep track of LexicalBlockStack counter at the beginning of a + /// function. This is used to pop unbalanced regions at the end of a + /// function. std::vector<unsigned> FnBeginRegionCount; - /// \brief This is a storage for names that are - /// constructed on demand. For example, C++ destructors, C++ operators etc.. + /// This is a storage for names that are constructed on demand. For + /// example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; StringRef CWDName; llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache; - /// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++ + /// Cache declarations relevant to DW_TAG_imported_declarations (C++ /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache; llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache; @@ -122,6 +120,9 @@ class CGDebugInfo { llvm::DenseMap<const Decl *, llvm::TrackingMDRef> StaticDataMemberCache; /// Helper functions for getOrCreateType. + /// @{ + /// Currently the checksum of an interface includes the number of + /// ivars and property accessors. unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl); llvm::DIType *CreateType(const BuiltinType *Ty); llvm::DIType *CreateType(const ComplexType *Ty); @@ -133,14 +134,17 @@ class CGDebugInfo { llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F); + /// Get structure or union type. llvm::DIType *CreateType(const RecordType *Tyg); llvm::DIType *CreateTypeDefinition(const RecordType *Ty); llvm::DICompositeType *CreateLimitedType(const RecordType *Ty); void CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType *CT); + /// Get Objective-C interface type. llvm::DIType *CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *F); llvm::DIType *CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile *F); + /// Get Objective-C object type. llvm::DIType *CreateType(const ObjCObjectType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const VectorType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const ArrayType *Ty, llvm::DIFile *F); @@ -148,10 +152,25 @@ class CGDebugInfo { llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit); llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F); + /// Get enumeration type. llvm::DIType *CreateEnumType(const EnumType *Ty); llvm::DIType *CreateTypeDefinition(const EnumType *Ty); + /// Look up the completed type for a self pointer in the TypeCache and + /// create a copy of it with the ObjectPointer and Artificial flags + /// set. If the type is not cached, a new one is created. This should + /// never happen though, since creating a type for the implicit self + /// argument implies that we already parsed the interface definition + /// and the ivar declarations in the implementation. llvm::DIType *CreateSelfType(const QualType &QualTy, llvm::DIType *Ty); + /// @} + + /// Get the type from the cache or return null type if it doesn't + /// exist. llvm::DIType *getTypeOrNull(const QualType); + /// Return the debug type for a C++ method. + /// \arg CXXMethodDecl is of FunctionType. This function type is + /// not updated to include implicit \c this pointer. Use this routine + /// to get a method type which includes \c this pointer. llvm::DISubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *F); llvm::DISubroutineType * @@ -159,7 +178,9 @@ class CGDebugInfo { llvm::DIFile *Unit); llvm::DISubroutineType * getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F); + /// \return debug info descriptor for vtable. llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F); + /// \return namespace descriptor for the given namespace decl. llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N); llvm::DIType *getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile *F); llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, @@ -168,23 +189,37 @@ class CGDebugInfo { llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty); llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache); + /// A helper function to create a subprogram for a single member + /// function GlobalDecl. llvm::DISubprogram *CreateCXXMemberFunction(const CXXMethodDecl *Method, llvm::DIFile *F, llvm::DIType *RecordTy); + /// A helper function to collect debug info for C++ member + /// functions. This is used while creating debug info entry for a + /// Record. void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &E, llvm::DIType *T); + /// A helper function to collect debug info for C++ base + /// classes. This is used while creating debug info entry for a + /// Record. void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy); + /// A helper function to collect template parameters. llvm::DINodeArray CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef<TemplateArgument> TAList, llvm::DIFile *Unit); + /// A helper function to collect debug info for function template + /// parameters. llvm::DINodeArray CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile *Unit); + + /// A helper function to collect debug info for template + /// parameters. llvm::DINodeArray CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, llvm::DIFile *F); @@ -195,7 +230,8 @@ class CGDebugInfo { llvm::DIFile *tunit, llvm::DIScope *scope, const RecordDecl *RD = nullptr); - // Helpers for collecting fields of a record. + /// Helpers for collecting fields of a record. + /// @{ void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &E, llvm::DIType *RecordTy); @@ -210,11 +246,13 @@ class CGDebugInfo { SmallVectorImpl<llvm::Metadata *> &E, llvm::DICompositeType *RecordTy); + /// If the C++ class has vtable info then insert appropriate debug + /// info entry in EltTys vector. void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &EltTys); + /// @} - // CreateLexicalBlock - Create a new lexical block node and push it on - // the stack. + /// Create a new lexical block node and push it on the stack. void CreateLexicalBlock(SourceLocation Loc); public: @@ -223,86 +261,84 @@ public: void finalize(); - /// \brief Update the current source location. If \arg loc is - /// invalid it is ignored. + /// Update the current source location. If \arg loc is invalid it is + /// ignored. void setLocation(SourceLocation Loc); - /// \brief Emit metadata to indicate a change in line/column - /// information in the source file. + /// Emit metadata to indicate a change in line/column information in + /// the source file. If the location is invalid, the previous + /// location will be reused. void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit a call to llvm.dbg.function.start to indicate + /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. /// \param Loc The location of the function header. /// \param ScopeLoc The location of the function body. - void EmitFunctionStart(GlobalDecl GD, - SourceLocation Loc, SourceLocation ScopeLoc, - QualType FnType, llvm::Function *Fn, - CGBuilderTy &Builder); + void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, + SourceLocation ScopeLoc, QualType FnType, + llvm::Function *Fn, CGBuilderTy &Builder); - /// \brief Constructs the debug code for exiting a function. + /// Constructs the debug code for exiting a function. void EmitFunctionEnd(CGBuilderTy &Builder); - /// \brief Emit metadata to indicate the beginning of a - /// new lexical block and push the block onto the stack. + /// Emit metadata to indicate the beginning of a new lexical block + /// and push the block onto the stack. void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit metadata to indicate the end of a new lexical - /// block and pop the current block. + /// Emit metadata to indicate the end of a new lexical block and pop + /// the current block. void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit call to llvm.dbg.declare for an automatic - /// variable declaration. + /// Emit call to \c llvm.dbg.declare for an automatic variable + /// declaration. void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, CGBuilderTy &Builder); - /// \brief Emit call to llvm.dbg.declare for an - /// imported variable declaration in a block. + /// Emit call to \c llvm.dbg.declare for an imported variable + /// declaration in a block. void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable, llvm::Value *storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint = 0); - /// \brief Emit call to llvm.dbg.declare for an argument - /// variable declaration. + /// Emit call to \c llvm.dbg.declare for an argument variable + /// declaration. void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder); - /// \brief Emit call to - /// llvm.dbg.declare for the block-literal argument to a block - /// invocation function. + /// Emit call to \c llvm.dbg.declare for the block-literal argument + /// to a block invocation function. void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::Value *Arg, unsigned ArgNo, llvm::Value *LocalAddr, CGBuilderTy &Builder); - /// \brief Emit information about a global variable. + /// Emit information about a global variable. void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); - /// \brief Emit global variable's debug info. + /// Emit global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); - /// \brief Emit C++ using directive. + /// Emit C++ using directive. void EmitUsingDirective(const UsingDirectiveDecl &UD); - /// \brief Emit the type explicitly casted to. + /// Emit the type explicitly casted to. void EmitExplicitCastType(QualType Ty); - /// \brief Emit C++ using declaration. + /// Emit C++ using declaration. void EmitUsingDecl(const UsingDecl &UD); - /// \brief Emit an @import declaration. + /// Emit an @import declaration. void EmitImportDecl(const ImportDecl &ID); - /// \brief Emit C++ namespace alias. + /// Emit C++ namespace alias. llvm::DIImportedEntity *EmitNamespaceAlias(const NamespaceAliasDecl &NA); - /// \brief Emit record type's standalone debug info. + /// Emit record type's standalone debug info. llvm::DIType *getOrCreateRecordType(QualType Ty, SourceLocation L); - /// \brief Emit an objective c interface type standalone - /// debug info. + /// Emit an Objective-C interface type standalone debug info. llvm::DIType *getOrCreateInterfaceType(QualType Ty, SourceLocation Loc); void completeType(const EnumDecl *ED); @@ -313,120 +349,124 @@ public: void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); private: - /// \brief Emit call to llvm.dbg.declare for a variable declaration. + /// Emit call to llvm.dbg.declare for a variable declaration. /// Tag accepts custom types DW_TAG_arg_variable and DW_TAG_auto_variable, /// otherwise would be of type llvm::dwarf::Tag. void EmitDeclare(const VarDecl *decl, llvm::dwarf::Tag Tag, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder); - // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. - // See BuildByRefType. + /// Build up structure info for the byref. See \a BuildByRefType. llvm::DIType *EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *OffSet); - /// \brief Get context info for the decl. + /// Get context info for the decl. llvm::DIScope *getContextDescriptor(const Decl *Decl); llvm::DIScope *getCurrentContextDescriptor(const Decl *Decl); - /// \brief Create a forward decl for a RecordType in a given context. + /// Create a forward decl for a RecordType in a given context. llvm::DICompositeType *getOrCreateRecordFwdDecl(const RecordType *, llvm::DIScope *); - /// \brief Return current directory name. + /// Return current directory name. StringRef getCurrentDirname(); - /// \brief Create new compile unit. + /// Create new compile unit. void CreateCompileUnit(); - /// \brief Get the file debug info descriptor for the input - /// location. + /// Get the file debug info descriptor for the input location. llvm::DIFile *getOrCreateFile(SourceLocation Loc); - /// \brief Get the file info for main compile unit. + /// Get the file info for main compile unit. llvm::DIFile *getOrCreateMainFile(); - /// \brief Get the type from the cache or create a new type if - /// necessary. + /// Get the type from the cache or create a new type if necessary. llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg); - /// \brief Get a reference to a clang module. + /// Get a reference to a clang module. llvm::DIModule * getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod); - /// \brief Get the type from the cache or create a new - /// partial type if necessary. + /// Get the type from the cache or create a new partial type if + /// necessary. llvm::DIType *getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *F); - /// \brief Create type metadata for a source language type. + /// Create type metadata for a source language type. llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg); - /// \brief return the underlying ObjCInterfaceDecl - /// if Ty is an ObjCInterface or a pointer to one. - ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty); + /// Return the underlying ObjCInterfaceDecl if \arg Ty is an + /// ObjCInterface or a pointer to one. + ObjCInterfaceDecl *getObjCInterfaceDecl(QualType Ty); - /// \brief Create new member and increase Offset by FType's size. + /// Create new member and increase Offset by FType's size. llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType, StringRef Name, uint64_t *Offset); - /// \brief Retrieve the DIDescriptor, if any, for the canonical form of this + /// Retrieve the DIDescriptor, if any, for the canonical form of this /// declaration. llvm::DINode *getDeclarationOrDefinition(const Decl *D); - /// \brief Return debug info descriptor to describe method + /// \return debug info descriptor to describe method /// declaration for the given method definition. llvm::DISubprogram *getFunctionDeclaration(const Decl *D); - /// Return debug info descriptor to describe in-class static data member - /// declaration for the given out-of-class definition. + /// \return debug info descriptor to describe in-class static data + /// member declaration for the given out-of-class definition. If D + /// is an out-of-class definition of a static data member of a + /// class, find its corresponding in-class declaration. llvm::DIDerivedType * getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D); - /// \brief Create a subprogram describing the forward - /// decalration represented in the given FunctionDecl. + /// Create a subprogram describing the forward declaration + /// represented in the given FunctionDecl. llvm::DISubprogram *getFunctionForwardDeclaration(const FunctionDecl *FD); - /// \brief Create a global variable describing the forward decalration + /// Create a global variable describing the forward decalration /// represented in the given VarDecl. llvm::DIGlobalVariable * getGlobalVariableForwardDeclaration(const VarDecl *VD); - /// Return a global variable that represents one of the collection of - /// global variables created for an anonmyous union. + /// \brief Return a global variable that represents one of the + /// collection of global variables created for an anonmyous union. + /// + /// Recursively collect all of the member fields of a global + /// anonymous decl and create static variables for them. The first + /// time this is called it needs to be on a union and then from + /// there we can have additional unnamed fields. llvm::DIGlobalVariable * CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext); - /// \brief Get function name for the given FunctionDecl. If the - /// name is constructed on demand (e.g. C++ destructor) then the name - /// is stored on the side. + /// Get function name for the given FunctionDecl. If the name is + /// constructed on demand (e.g., C++ destructor) then the name is + /// stored on the side. StringRef getFunctionName(const FunctionDecl *FD); - /// \brief Returns the unmangled name of an Objective-C method. + /// Returns the unmangled name of an Objective-C method. /// This is the display name for the debugging info. StringRef getObjCMethodName(const ObjCMethodDecl *FD); - /// \brief Return selector name. This is used for debugging + /// Return selector name. This is used for debugging /// info. StringRef getSelectorName(Selector S); - /// \brief Get class name including template argument list. + /// Get class name including template argument list. StringRef getClassName(const RecordDecl *RD); - /// \brief Get vtable name for the given Class. + /// Get the vtable name for the given class. StringRef getVTableName(const CXXRecordDecl *Decl); - /// \brief Get line number for the location. If location is invalid + /// Get line number for the location. If location is invalid /// then use current location. unsigned getLineNumber(SourceLocation Loc); - /// \brief Get column number for the location. If location is + /// Get column number for the location. If location is /// invalid then use current location. /// \param Force Assume DebugColumnInfo option is true. - unsigned getColumnNumber(SourceLocation Loc, bool Force=false); + unsigned getColumnNumber(SourceLocation Loc, bool Force = false); - /// \brief Collect various properties of a FunctionDecl. + /// Collect various properties of a FunctionDecl. /// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl. void collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, StringRef &Name, StringRef &LinkageName, @@ -434,12 +474,12 @@ private: llvm::DINodeArray &TParamsArray, unsigned &Flags); - /// \brief Collect various properties of a VarDecl. + /// Collect various properties of a VarDecl. void collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, unsigned &LineNo, QualType &T, StringRef &Name, StringRef &LinkageName, llvm::DIScope *&VDContext); - /// \brief Allocate a copy of \p A using the DebugInfoNames allocator + /// Allocate a copy of \p A using the DebugInfoNames allocator /// and return a reference to it. If multiple arguments are given the strings /// are concatenated. StringRef internString(StringRef A, StringRef B = StringRef()) { @@ -450,7 +490,7 @@ private: } }; -/// \brief A scoped helper to set the current debug location to the specified +/// A scoped helper to set the current debug location to the specified /// location or preferred location of the specified Expr. class ApplyDebugLocation { private: @@ -460,55 +500,56 @@ private: llvm::DebugLoc OriginalLocation; CodeGenFunction &CGF; -public: - /// \brief Set the location to the (valid) TemporaryLocation. +public: + /// Set the location to the (valid) TemporaryLocation. ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation); ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E); ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc); ~ApplyDebugLocation(); - /// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an - /// artificial debug location that has a valid scope, but no line information. + /// \brief Apply TemporaryLocation if it is valid. Otherwise switch + /// to an artificial debug location that has a valid scope, but no + /// line information. /// - /// Artificial locations are useful when emitting compiler-generated helper - /// functions that have no source location associated with them. The DWARF - /// specification allows the compiler to use the special line number 0 to - /// indicate code that can not be attributed to any source location. Note that - /// passing an empty SourceLocation to CGDebugInfo::setLocation() will result - /// in the last valid location being reused. + /// Artificial locations are useful when emitting compiler-generated + /// helper functions that have no source location associated with + /// them. The DWARF specification allows the compiler to use the + /// special line number 0 to indicate code that can not be + /// attributed to any source location. Note that passing an empty + /// SourceLocation to CGDebugInfo::setLocation() will result in the + /// last valid location being reused. static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF) { return ApplyDebugLocation(CGF, false, SourceLocation()); } - /// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an - /// artificial debug location that has a valid scope, but no line information. - static ApplyDebugLocation CreateDefaultArtificial(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) { + /// \brief Apply TemporaryLocation if it is valid. Otherwise switch + /// to an artificial debug location that has a valid scope, but no + /// line information. + static ApplyDebugLocation + CreateDefaultArtificial(CodeGenFunction &CGF, + SourceLocation TemporaryLocation) { return ApplyDebugLocation(CGF, false, TemporaryLocation); } - /// \brief Set the IRBuilder to not attach debug locations. Note that passing - /// an empty SourceLocation to CGDebugInfo::setLocation() will result in the - /// last valid location being reused. Note that all instructions that do not - /// have a location at the beginning of a function are counted towards to - /// funciton prologue. + /// Set the IRBuilder to not attach debug locations. Note that + /// passing an empty SourceLocation to \a CGDebugInfo::setLocation() + /// will result in the last valid location being reused. Note that + /// all instructions that do not have a location at the beginning of + /// a function are counted towards to funciton prologue. static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF) { return ApplyDebugLocation(CGF, true, SourceLocation()); } /// \brief Apply TemporaryLocation if it is valid. Otherwise set the IRBuilder /// to not attach debug locations. - static ApplyDebugLocation CreateDefaultEmpty(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) { + static ApplyDebugLocation + CreateDefaultEmpty(CodeGenFunction &CGF, SourceLocation TemporaryLocation) { return ApplyDebugLocation(CGF, true, TemporaryLocation); } - }; - } // namespace CodeGen } // namespace clang - #endif diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 839c2e474ca3..96aa8c68e004 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: case Decl::UsingShadow: + case Decl::ObjCTypeParam: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; @@ -987,7 +988,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Value *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack"); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave); - llvm::Value *V = Builder.CreateCall(F, {}); + llvm::Value *V = Builder.CreateCall(F); Builder.CreateStore(V, Stack); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 4c8501724bd8..7b8368ee2b32 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -20,6 +20,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" @@ -1279,14 +1280,6 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { } void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { - // FIXME: Implement SEH on other architectures. - const llvm::Triple &T = CGM.getTarget().getTriple(); - if (T.getArch() != llvm::Triple::x86_64 || - !T.isKnownWindowsMSVCEnvironment()) { - ErrorUnsupported(&S, "__try statement"); - return; - } - EnterSEHTryStmt(S); { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); @@ -1311,24 +1304,27 @@ struct PerformSEHFinally : EHScopeStack::Cleanup { void Emit(CodeGenFunction &CGF, Flags F) override { ASTContext &Context = CGF.getContext(); - QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; - FunctionProtoType::ExtProtoInfo EPI; - const auto *FTP = cast<FunctionType>( - Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); + CodeGenModule &CGM = CGF.CGM; CallArgList Args; + + // Compute the two argument values. + QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; + llvm::Value *LocalAddrFn = CGM.getIntrinsic(llvm::Intrinsic::localaddress); + llvm::Value *FP = CGF.Builder.CreateCall(LocalAddrFn); llvm::Value *IsForEH = llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); Args.add(RValue::get(IsForEH), ArgTys[0]); - - CodeGenModule &CGM = CGF.CGM; - llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0); - llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); - llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero); Args.add(RValue::get(FP), ArgTys[1]); + // Arrange a two-arg function info and type. + FunctionProtoType::ExtProtoInfo EPI; + const auto *FPT = cast<FunctionProtoType>( + Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false); + CGM.getTypes().arrangeFreeFunctionCall(Args, FPT, + /*chainCall=*/false); + CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args); } }; @@ -1340,9 +1336,15 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { CodeGenFunction &ParentCGF; const VarDecl *ParentThis; SmallVector<const VarDecl *, 4> Captures; + llvm::Value *SEHCodeSlot = nullptr; CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) : ParentCGF(ParentCGF), ParentThis(ParentThis) {} + // Return true if we need to do any capturing work. + bool foundCaptures() { + return !Captures.empty() || SEHCodeSlot; + } + void Visit(const Stmt *S) { // See if this is a capture, then recurse. ConstStmtVisitor<CaptureFinder>::Visit(S); @@ -1366,27 +1368,106 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { void VisitCXXThisExpr(const CXXThisExpr *E) { Captures.push_back(ParentThis); } + + void VisitCallExpr(const CallExpr *E) { + // We only need to add parent frame allocations for these builtins in x86. + if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86) + return; + + unsigned ID = E->getBuiltinCallee(); + switch (ID) { + case Builtin::BI__exception_code: + case Builtin::BI_exception_code: + // This is the simple case where we are the outermost finally. All we + // have to do here is make sure we escape this and recover it in the + // outlined handler. + if (!SEHCodeSlot) + SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back(); + break; + } + } }; } +llvm::Value *CodeGenFunction::recoverAddrOfEscapedLocal( + CodeGenFunction &ParentCGF, llvm::Value *ParentVar, llvm::Value *ParentFP) { + llvm::CallInst *RecoverCall = nullptr; + CGBuilderTy Builder(AllocaInsertPt); + if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) { + // Mark the variable escaped if nobody else referenced it and compute the + // localescape index. + auto InsertPair = ParentCGF.EscapedLocals.insert( + std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); + int FrameEscapeIdx = InsertPair.first->second; + // call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N) + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::localrecover); + llvm::Constant *ParentI8Fn = + llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + RecoverCall = Builder.CreateCall( + FrameRecoverFn, {ParentI8Fn, ParentFP, + llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); + + } else { + // If the parent didn't have an alloca, we're doing some nested outlining. + // Just clone the existing localrecover call, but tweak the FP argument to + // use our FP value. All other arguments are constants. + auto *ParentRecover = + cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts()); + assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover && + "expected alloca or localrecover in parent LocalDeclMap"); + RecoverCall = cast<llvm::CallInst>(ParentRecover->clone()); + RecoverCall->setArgOperand(1, ParentFP); + RecoverCall->insertBefore(AllocaInsertPt); + } + + // Bitcast the variable, rename it, and insert it in the local decl map. + llvm::Value *ChildVar = + Builder.CreateBitCast(RecoverCall, ParentVar->getType()); + ChildVar->setName(ParentVar->getName()); + return ChildVar; +} + void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, - llvm::Value *ParentFP) { + bool IsFilter) { // Find all captures in the Stmt. CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl); Finder.Visit(OutlinedStmt); - // Typically there are no captures and we can exit early. - if (Finder.Captures.empty()) + // We can exit early on x86_64 when there are no captures. We just have to + // save the exception code in filters so that __exception_code() works. + if (!Finder.foundCaptures() && + CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + if (IsFilter) + EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr); return; + } - // Prepare the first two arguments to llvm.framerecover. - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::framerecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + llvm::Value *EntryEBP = nullptr; + llvm::Value *ParentFP; + if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) { + // 32-bit SEH filters need to be careful about FP recovery. The end of the + // EH registration is passed in as the EBP physical register. We can + // recover that with llvm.frameaddress(1), and adjust that to recover the + // parent's true frame pointer. + CGBuilderTy Builder(AllocaInsertPt); + EntryEBP = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)}); + llvm::Function *RecoverFPIntrin = + CGM.getIntrinsic(llvm::Intrinsic::x86_seh_recoverfp); + llvm::Constant *ParentI8Fn = + llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryEBP}); + } else { + // Otherwise, for x64 and 32-bit finally functions, the parent FP is the + // second parameter. + auto AI = CurFn->arg_begin(); + ++AI; + ParentFP = AI; + } - // Create llvm.framerecover calls for all captures. + // Create llvm.localrecover calls for all captures. for (const VarDecl *VD : Finder.Captures) { if (isa<ImplicitParamDecl>(VD)) { CGM.ErrorUnsupported(VD, "'this' captured by SEH"); @@ -1407,49 +1488,63 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, continue; llvm::Value *ParentVar = I->second; - llvm::CallInst *RecoverCall = nullptr; - CGBuilderTy Builder(AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) { - // Mark the variable escaped if nobody else referenced it and compute the - // frameescape index. - auto InsertPair = - ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1)); - if (InsertPair.second) - InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1; - int FrameEscapeIdx = InsertPair.first->second; - // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N) - RecoverCall = Builder.CreateCall( - FrameRecoverFn, {ParentI8Fn, ParentFP, - llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); - - } else { - // If the parent didn't have an alloca, we're doing some nested outlining. - // Just clone the existing framerecover call, but tweak the FP argument to - // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts()); - assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover && - "expected alloca or framerecover in parent LocalDeclMap"); - RecoverCall = cast<llvm::CallInst>(ParentRecover->clone()); - RecoverCall->setArgOperand(1, ParentFP); - RecoverCall->insertBefore(AllocaInsertPt); - } + LocalDeclMap[VD] = + recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); + } - // Bitcast the variable, rename it, and insert it in the local decl map. - llvm::Value *ChildVar = - Builder.CreateBitCast(RecoverCall, ParentVar->getType()); - ChildVar->setName(ParentVar->getName()); - LocalDeclMap[VD] = ChildVar; + if (Finder.SEHCodeSlot) { + SEHCodeSlotStack.push_back( + recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP)); } + + if (IsFilter) + EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryEBP); } /// Arrange a function prototype that can be called by Windows exception /// handling personalities. On Win64, the prototype looks like: /// RetTy func(void *EHPtrs, void *ParentFP); void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, - StringRef Name, QualType RetTy, - FunctionArgList &Args, + bool IsFilter, const Stmt *OutlinedStmt) { + SourceLocation StartLoc = OutlinedStmt->getLocStart(); + + // Get the mangled function name. + SmallString<128> Name; + { + llvm::raw_svector_ostream OS(Name); + const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; + const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); + assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); + MangleContext &Mangler = CGM.getCXXABI().getMangleContext(); + if (IsFilter) + Mangler.mangleSEHFilterExpression(Parent, OS); + else + Mangler.mangleSEHFinallyBlock(Parent, OS); + } + + FunctionArgList Args; + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) { + // All SEH finally functions take two parameters. Win64 filters take two + // parameters. Win32 filters take no parameters. + if (IsFilter) { + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("exception_pointers"), + getContext().VoidPtrTy)); + } else { + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("abnormal_termination"), + getContext().UnsignedCharTy)); + } + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); + } + + QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; + llvm::Function *ParentFn = ParentCGF.CurFn; const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration( RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false); @@ -1474,10 +1569,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); - - auto AI = Fn->arg_begin(); - ++AI; - EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI); + EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter); } /// Create a stub filter function that will ultimately hold the code of the @@ -1487,37 +1579,7 @@ llvm::Function * CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const SEHExceptStmt &Except) { const Expr *FilterExpr = Except.getFilterExpr(); - SourceLocation StartLoc = FilterExpr->getLocStart(); - - SEHPointersDecl = ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); - FunctionArgList Args; - Args.push_back(SEHPointersDecl); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - - // Get the mangled function name. - SmallString<128> Name; - { - llvm::raw_svector_ostream OS(Name); - const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; - const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); - assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); - CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS); - } - - startOutlinedSEHHelper(ParentCGF, Name, getContext().LongTy, Args, - FilterExpr); - - // Mark finally block calls as nounwind and noinline to make LLVM's job a - // little easier. - // FIXME: Remove these restrictions in the future. - CurFn->addFnAttr(llvm::Attribute::NoUnwind); - CurFn->addFnAttr(llvm::Attribute::NoInline); - - EmitSEHExceptionCodeSave(); + startOutlinedSEHHelper(ParentCGF, true, FilterExpr); // Emit the original filter expression, convert to i32, and return. llvm::Value *R = EmitScalarExpr(FilterExpr); @@ -1534,29 +1596,13 @@ llvm::Function * CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, const SEHFinallyStmt &Finally) { const Stmt *FinallyBlock = Finally.getBlock(); - SourceLocation StartLoc = FinallyBlock->getLocStart(); + startOutlinedSEHHelper(ParentCGF, false, FinallyBlock); - FunctionArgList Args; - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("abnormal_termination"), - getContext().UnsignedCharTy)); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - - // Get the mangled function name. - SmallString<128> Name; - { - llvm::raw_svector_ostream OS(Name); - const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; - const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); - assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); - CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS); - } - - startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args, - FinallyBlock); + // Mark finally block calls as nounwind and noinline to make LLVM's job a + // little easier. + // FIXME: Remove these restrictions in the future. + CurFn->addFnAttr(llvm::Attribute::NoUnwind); + CurFn->addFnAttr(llvm::Attribute::NoInline); // Emit the original filter expression, convert to i32, and return. EmitStmt(FinallyBlock); @@ -1566,44 +1612,58 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, return CurFn; } -void CodeGenFunction::EmitSEHExceptionCodeSave() { +void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, + llvm::Value *ParentFP, + llvm::Value *EntryEBP) { + // Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the + // __exception_info intrinsic. + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + // On Win64, the info is passed as the first parameter to the filter. + auto AI = CurFn->arg_begin(); + SEHInfo = AI; + SEHCodeSlotStack.push_back( + CreateMemTemp(getContext().IntTy, "__exception_code")); + } else { + // On Win32, the EBP on entry to the filter points to the end of an + // exception registration object. It contains 6 32-bit fields, and the info + // pointer is stored in the second field. So, GEP 20 bytes backwards and + // load the pointer. + SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryEBP, -20); + SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo()); + SEHInfo = Builder.CreateLoad(Int8PtrTy, SEHInfo); + SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal( + ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP)); + } + // Save the exception code in the exception slot to unify exception access in // the filter function and the landing pad. // struct EXCEPTION_POINTERS { // EXCEPTION_RECORD *ExceptionRecord; // CONTEXT *ContextRecord; // }; - // void *exn.slot = - // (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode; - llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl)); + // int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode; llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo(); llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr); - Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo()); + llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo()); llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0); Rec = Builder.CreateLoad(Rec); llvm::Value *Code = Builder.CreateLoad(Rec); - Code = Builder.CreateZExt(Code, CGM.IntPtrTy); - // FIXME: Change landing pads to produce {i32, i32} and make the exception - // slot an i32. - Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy); - Builder.CreateStore(Code, getExceptionSlot()); + assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); + Builder.CreateStore(Code, SEHCodeSlotStack.back()); } llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() { // Sema should diagnose calling this builtin outside of a filter context, but // don't crash if we screw up. - if (!SEHPointersDecl) + if (!SEHInfo) return llvm::UndefValue::get(Int8PtrTy); - return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl)); + assert(SEHInfo->getType() == Int8PtrTy); + return SEHInfo; } llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { - // If we're in a landing pad or filter function, the exception slot contains - // the code. - assert(ExceptionSlot); - llvm::Value *Code = - Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy); - return Builder.CreateTrunc(Code, CGM.Int32Ty); + assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); + return Builder.CreateLoad(Int32Ty, SEHCodeSlotStack.back()); } llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { @@ -1616,9 +1676,11 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { - // Push a cleanup for __finally blocks. + // Outline the finally block. llvm::Function *FinallyFunc = HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); + + // Push a cleanup for __finally blocks. EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc); return; } @@ -1627,12 +1689,16 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { const SEHExceptStmt *Except = S.getExceptHandler(); assert(Except); EHCatchScope *CatchScope = EHStack.pushCatch(1); + SEHCodeSlotStack.push_back( + CreateMemTemp(getContext().IntTy, "__exception_code")); - // If the filter is known to evaluate to 1, then we can use the clause "catch - // i8* null". + // If the filter is known to evaluate to 1, then we can use the clause + // "catch i8* null". We can't do this on x86 because the filter has to save + // the exception code. llvm::Constant *C = CGM.EmitConstantExpr(Except->getFilterExpr(), getContext().IntTy, this); - if (C && C->isOneValue()) { + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && + C->isOneValue()) { CatchScope->setCatchAllHandler(0, createBasicBlock("__except")); return; } @@ -1664,6 +1730,7 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { if (!CatchScope.hasEHBranches()) { CatchScope.clearHandlerBlocks(); EHStack.popCatch(); + SEHCodeSlotStack.pop_back(); return; } @@ -1683,9 +1750,20 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { EmitBlockAfterUses(ExceptBB); + // On Win64, the exception pointer is the exception code. Copy it to the slot. + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + llvm::Value *Code = + Builder.CreatePtrToInt(getExceptionFromSlot(), IntPtrTy); + Code = Builder.CreateTrunc(Code, Int32Ty); + Builder.CreateStore(Code, SEHCodeSlotStack.back()); + } + // Emit the __except body. EmitStmt(Except->getBlock()); + // End the lifetime of the exception code. + SEHCodeSlotStack.pop_back(); + if (HaveInsertPoint()) Builder.CreateBr(ContBB); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 175763c4e815..9c3dfe52716b 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1356,14 +1356,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); + CharUnits Align = LV.getAlignment().alignmentAtOffset(Info.StorageOffset); // Get the output type. llvm::Type *ResLTy = ConvertType(LV.getType()); llvm::Value *Ptr = LV.getBitFieldAddr(); - llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), - "bf.load"); - cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment); + llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(), + LV.isVolatileQualified(), + "bf.load"); if (Info.IsSigned) { assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize); @@ -1559,6 +1560,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, llvm::Value **Result) { const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); + CharUnits Align = Dst.getAlignment().alignmentAtOffset(Info.StorageOffset); llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType()); llvm::Value *Ptr = Dst.getBitFieldAddr(); @@ -1575,9 +1577,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // and mask together with source before storing. if (Info.StorageSize != Info.Size) { assert(Info.StorageSize > Info.Size && "Invalid bitfield size."); - llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), - "bf.load"); - cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment); + llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(), + Dst.isVolatileQualified(), + "bf.load"); // Mask the source value as needed. if (!hasBooleanRepresentation(Dst.getType())) @@ -1603,9 +1605,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, } // Write the new value back out. - llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr, - Dst.isVolatileQualified()); - Store->setAlignment(Info.StorageAlignment); + Builder.CreateAlignedStore(SrcVal, Ptr, Align.getQuantity(), + Dst.isVolatileQualified()); // Return the new value of the bit-field, if requested. if (Result) { @@ -2415,8 +2416,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) { } llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { - llvm::CallInst *TrapCall = - Builder.CreateCall(CGM.getIntrinsic(IntrID), {}); + llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(IntrID)); if (!CGM.getCodeGenOpts().TrapFuncName.empty()) TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex, diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 747326e4c5bc..eb76ad1ce1f7 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -31,10 +31,9 @@ using namespace CodeGen; typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult; static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ET, - const ObjCMethodDecl *Method, - RValue Result); +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, + QualType ET, + RValue Result); /// Given the address of a variable of pointer type, find the correct /// null to store into it. @@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol()); } -/// \brief Adjust the type of the result of an Objective-C message send -/// expression when the method has a related result type. -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ExpT, - const ObjCMethodDecl *Method, - RValue Result) { - if (!Method) +/// \brief Adjust the type of an Objective-C object that doesn't match up due +/// to type erasure at various points, e.g., related result types or the use +/// of parameterized classes. +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT, + RValue Result) { + if (!ExpT->isObjCRetainableType()) return Result; - if (!Method->hasRelatedResultType() || - CGF.getContext().hasSameType(ExpT, Method->getReturnType()) || - !Result.isScalar()) + // If the converted types are the same, we're done. + llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT); + if (ExpLLVMTy == Result.getScalarVal()->getType()) return Result; - - // We have applied a related result type. Cast the rvalue appropriately. + + // We have applied a substitution. Cast the rvalue appropriately. return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), - CGF.ConvertType(ExpT))); + ExpLLVMTy)); } /// Decide whether to extend the lifetime of the receiver of a @@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E->getType(), method, result); + return AdjustObjCObjectType(*this, E->getType(), result); } namespace { @@ -2011,7 +2009,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { // Call the marker asm if we made one, which we do only at -O0. if (marker) - Builder.CreateCall(marker, {}); + Builder.CreateCall(marker); return emitARCValueOperation(*this, value, CGM.getARCEntrypoints().objc_retainAutoreleasedReturnValue, diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index 5290a87cebf2..2ac6bb2e8a93 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -134,7 +134,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, CGF.CGM.getContext().toBits(StorageSize), - Alignment.getQuantity())); + CharUnits::fromQuantity(0))); V = CGF.Builder.CreateBitCast(V, llvm::Type::getIntNPtrTy(CGF.getLLVMContext(), @@ -160,7 +160,7 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) override { if (!MightThrow) { - CGF.Builder.CreateCall(Fn, {})->setDoesNotThrow(); + CGF.Builder.CreateCall(Fn)->setDoesNotThrow(); return; } diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 534d148209ba..81488398bb86 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -537,7 +537,7 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) { break; } case OMPRTL__kmpc_barrier: { - // Build void __kmpc_cancel_barrier(ident_t *loc, kmp_int32 global_tid); + // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); @@ -829,6 +829,15 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancellationpoint"); break; } + case OMPRTL__kmpc_cancel: { + // Build kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind) + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancel"); + break; + } } return RTLFn; } @@ -923,6 +932,8 @@ llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize, llvm::Constant * CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) { + assert(!CGM.getLangOpts().OpenMPUseTLS || + !CGM.getContext().getTargetInfo().isTLSSupported()); // Lookup the entry, lazily creating it if necessary. return getOrCreateInternalVariable(CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)) + ".cache."); @@ -932,6 +943,10 @@ llvm::Value *CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF, const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc) { + if (CGM.getLangOpts().OpenMPUseTLS && + CGM.getContext().getTargetInfo().isTLSSupported()) + return VDAddr; + auto VarTy = VDAddr->getType()->getPointerElementType(); llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), CGF.Builder.CreatePointerCast(VDAddr, CGM.Int8PtrTy), @@ -961,6 +976,10 @@ void CGOpenMPRuntime::emitThreadPrivateVarInit( llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition( const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc, bool PerformInit, CodeGenFunction *CGF) { + if (CGM.getLangOpts().OpenMPUseTLS && + CGM.getContext().getTargetInfo().isTLSSupported()) + return nullptr; + VD = VD->getDefinition(CGM.getContext()); if (VD && ThreadPrivateWithDefinition.count(VD) == 0) { ThreadPrivateWithDefinition.insert(VD); @@ -2723,18 +2742,18 @@ void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF, CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr); } -void CGOpenMPRuntime::emitCancellationPointCall( - CodeGenFunction &CGF, SourceLocation Loc, - OpenMPDirectiveKind CancelRegion) { - // Build call kmp_int32 OMPRTL__kmpc_cancellationpoint(ident_t *loc, kmp_int32 - // global_tid, kmp_int32 cncl_kind); - enum { - CancelNoreq = 0, - CancelParallel = 1, - CancelLoop = 2, - CancelSections = 3, - CancelTaskgroup = 4 - } CancelKind = CancelNoreq; +namespace { +enum RTCancelKind { + CancelNoreq = 0, + CancelParallel = 1, + CancelLoop = 2, + CancelSections = 3, + CancelTaskgroup = 4 +}; +} + +static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) { + RTCancelKind CancelKind = CancelNoreq; if (CancelRegion == OMPD_parallel) CancelKind = CancelParallel; else if (CancelRegion == OMPD_for) @@ -2745,14 +2764,22 @@ void CGOpenMPRuntime::emitCancellationPointCall( assert(CancelRegion == OMPD_taskgroup); CancelKind = CancelTaskgroup; } + return CancelKind; +} + +void CGOpenMPRuntime::emitCancellationPointCall( + CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion) { + // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 cncl_kind); if (auto *OMPRegionInfo = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { auto CancelDest = CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); if (CancelDest.isValid()) { - llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), - getThreadID(CGF, Loc), - CGF.Builder.getInt32(CancelKind)}; + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; // Ignore return result until untied tasks are supported. auto *Result = CGF.EmitRuntimeCall( createRuntimeFunction(OMPRTL__kmpc_cancellationpoint), Args); @@ -2774,3 +2801,36 @@ void CGOpenMPRuntime::emitCancellationPointCall( } } +void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion) { + // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind); + if (auto *OMPRegionInfo = + dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { + auto CancelDest = + CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); + if (CancelDest.isValid()) { + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; + // Ignore return result until untied tasks are supported. + auto *Result = + CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args); + // if (__kmpc_cancel()) { + // __kmpc_cancel_barrier(); + // exit from construct; + // } + auto *ExitBB = CGF.createBasicBlock(".cancel.exit"); + auto *ContBB = CGF.createBasicBlock(".cancel.continue"); + auto *Cmp = CGF.Builder.CreateIsNotNull(Result); + CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB); + CGF.EmitBlock(ExitBB); + // __kmpc_cancel_barrier(); + emitBarrierCall(CGF, Loc, OMPD_unknown, /*CheckForCancel=*/false); + // exit from construct; + CGF.EmitBranchThroughCleanup(CancelDest); + CGF.EmitBlock(ContBB, /*IsFinished=*/true); + } + } +} + diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h index 76bb3ae35931..44bc8a139b15 100644 --- a/lib/CodeGen/CGOpenMPRuntime.h +++ b/lib/CodeGen/CGOpenMPRuntime.h @@ -151,6 +151,9 @@ private: // Call to kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 // global_tid, kmp_int32 cncl_kind); OMPRTL__kmpc_cancellationpoint, + // Call to kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind); + OMPRTL__kmpc_cancel, }; /// \brief Values for bit flags used in the ident_t to describe the fields. @@ -698,6 +701,12 @@ public: virtual void emitCancellationPointCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind CancelRegion); + + /// \brief Emit code for 'cancel' construct. + /// \param CancelRegion Region kind for which the cancel must be emitted. + /// + virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion); }; } // namespace CodeGen diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index c15f9fde06f5..d4ad33e3345e 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -78,16 +78,16 @@ struct CGBitFieldInfo { /// bitfield. unsigned StorageSize; - /// The alignment which should be used when accessing the bitfield. - unsigned StorageAlignment; + /// The offset of the bitfield storage from the start of the struct. + CharUnits StorageOffset; CGBitFieldInfo() - : Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {} + : Offset(), Size(), IsSigned(), StorageSize(), StorageOffset() {} CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned, - unsigned StorageSize, unsigned StorageAlignment) + unsigned StorageSize, CharUnits StorageOffset) : Offset(Offset), Size(Size), IsSigned(IsSigned), - StorageSize(StorageSize), StorageAlignment(StorageAlignment) {} + StorageSize(StorageSize), StorageOffset(StorageOffset) {} void print(raw_ostream &OS) const; void dump() const; @@ -99,7 +99,7 @@ struct CGBitFieldInfo { const FieldDecl *FD, uint64_t Offset, uint64_t Size, uint64_t StorageSize, - uint64_t StorageAlignment); + CharUnits StorageOffset); }; /// CGRecordLayout - This class handles struct and union layout info while diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index c89d5cc3892a..f91ecebd0926 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -228,11 +228,7 @@ void CGRecordLowering::setBitFieldInfo( Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset)); Info.Size = FD->getBitWidthValue(Context); Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType); - // Here we calculate the actual storage alignment of the bits. E.g if we've - // got an alignment >= 2 and the bitfield starts at offset 6 we've got an - // alignment of 2. - Info.StorageAlignment = - Layout.getAlignment().alignmentAtOffset(StartOffset).getQuantity(); + Info.StorageOffset = StartOffset; if (Info.Size > Info.StorageSize) Info.Size = Info.StorageSize; // Reverse the bit offsets for big endian machines. Because we represent @@ -651,7 +647,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, const FieldDecl *FD, uint64_t Offset, uint64_t Size, uint64_t StorageSize, - uint64_t StorageAlignment) { + CharUnits StorageOffset) { // This function is vestigial from CGRecordLayoutBuilder days but is still // used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that // when addressed will allow for the removal of this function. @@ -683,7 +679,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, Offset = StorageSize - (Offset + Size); } - return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment); + return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset); } CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, @@ -856,7 +852,7 @@ void CGBitFieldInfo::print(raw_ostream &OS) const { << " Size:" << Size << " IsSigned:" << IsSigned << " StorageSize:" << StorageSize - << " StorageAlignment:" << StorageAlignment << ">"; + << " StorageOffset:" << StorageOffset.getQuantity() << ">"; } void CGBitFieldInfo::dump() const { diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index a12f29534bfe..7a0b8a35be01 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1852,6 +1852,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector<llvm::Value*> InOutArgs; std::vector<llvm::Type*> InOutArgTypes; + // An inline asm can be marked readonly if it meets the following conditions: + // - it doesn't have any sideeffects + // - it doesn't clobber memory + // - it doesn't return a value by-reference + // It can be marked readnone if it doesn't have any input memory constraints + // in addition to meeting the conditions listed above. + bool ReadOnly = true, ReadNone = true; + for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; @@ -1915,6 +1923,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Args.push_back(Dest.getAddress()); Constraints += "=*"; Constraints += OutputConstraint; + ReadOnly = ReadNone = false; } if (Info.isReadWrite()) { @@ -1959,6 +1968,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + if (Info.allowsMemory()) + ReadNone = false; + if (!Constraints.empty()) Constraints += ','; @@ -2023,7 +2035,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { StringRef Clobber = S.getClobber(i); - if (Clobber != "memory" && Clobber != "cc") + if (Clobber == "memory") + ReadOnly = ReadNone = false; + else if (Clobber != "cc") Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); if (!Constraints.empty()) @@ -2063,6 +2077,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Result->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind); + // Attach readnone and readonly attributes. + if (!HasSideEffect) { + if (ReadNone) + Result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadNone); + else if (ReadOnly) + Result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadOnly); + } + // Slap the source location of the inline asm into a !srcloc metadata on the // call. if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) { diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index b021c1275318..a1f093a8d866 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -2108,7 +2108,8 @@ void CodeGenFunction::EmitOMPCancellationPointDirective( } void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { - llvm_unreachable("CodeGen for 'omp cancel' is not supported yet."); + CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), + S.getCancelRegion()); } CodeGenFunction::JumpDest diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 969629fb5845..e36051c2053b 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -364,7 +364,7 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD, FinishFunction(); } -void CodeGenFunction::GenerateThunk(llvm::Function *Fn, +void CodeGenFunction::generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk) { StartThunk(Fn, GD, FnInfo); @@ -376,13 +376,6 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, // Make the call and return the result. EmitCallAndReturnForThunk(Callee, &Thunk); - - // Set the right linkage. - CGM.setFunctionLinkage(GD, Fn); - - // Set the right visibility. - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - setThunkVisibility(CGM, MD, Thunk, Fn); } void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, @@ -455,11 +448,17 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk); } else { // Normal thunk body generation. - CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); + CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, Thunk); } + CGM.setFunctionLinkage(GD, ThunkFn); CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD, !Thunk.Return.isEmpty()); + + // Set the right visibility. + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + setThunkVisibility(CGM, MD, Thunk, ThunkFn); + if (CGM.supportsCOMDAT() && ThunkFn->isWeakForLinker()) ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName())); } @@ -841,6 +840,11 @@ void CodeGenModule::EmitDeferredVTables() { DeferredVTables.clear(); } +bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) { + // FIXME: Make this user configurable. + return RD->isInStdNamespace(); +} + void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && @@ -855,8 +859,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, std::vector<llvm::MDTuple *> BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) { - // FIXME: Add blacklisting scheme. - if (AP.first.getBase()->isInStdNamespace()) + if (IsCFIBlacklistedRecord(AP.first.getBase())) continue; BitsetEntries.push_back(CreateVTableBitSetEntry( diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 5a060b30808b..10bda76b6b69 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS Linker MC ObjCARCOpts + Object ProfileData ScalarOpts Support @@ -71,6 +72,7 @@ add_clang_library(clangCodeGen ItaniumCXXABI.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp + ObjectFilePCHContainerOperations.cpp SanitizerMetadata.cpp TargetInfo.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 1fca466e9244..ec3c75ccd257 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -45,12 +45,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr), - AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr), - DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false), - DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm), - SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr), - UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0), - CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr), + DebugInfo(CGM.getModuleDebugInfo()), + DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr), + PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr), + CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0), + NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr), + CXXABIThisValue(nullptr), CXXThisValue(nullptr), CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr), CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr), CurLexicalScope(nullptr), TerminateLandingPad(nullptr), @@ -284,7 +284,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { Builder.ClearInsertionPoint(); } - // If some of our locals escaped, insert a call to llvm.frameescape in the + // If some of our locals escaped, insert a call to llvm.localescape in the // entry block. if (!EscapedLocals.empty()) { // Invert the map from local to index into a simple vector. There should be @@ -294,7 +294,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { for (auto &Pair : EscapedLocals) EscapeArgs[Pair.second] = Pair.first; llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::frameescape); + &CGM.getModule(), llvm::Intrinsic::localescape); CGBuilderTy(AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index a74c474232c8..f2bc402f8b25 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -324,11 +324,13 @@ public: /// write the current selector value into this alloca. llvm::AllocaInst *EHSelectorSlot; - llvm::AllocaInst *AbnormalTerminationSlot; + /// A stack of exception code slots. Entering an __except block pushes a slot + /// on the stack and leaving pops one. The __exception_code() intrinsic loads + /// a value from the top of the stack. + SmallVector<llvm::Value *, 1> SEHCodeSlotStack; - /// The implicit parameter to SEH filter functions of type - /// 'EXCEPTION_POINTERS*'. - ImplicitParamDecl *SEHPointersDecl; + /// Value returned by __exception_info intrinsic. + llvm::Value *SEHInfo = nullptr; /// Emits a landing pad for the current EH stack. llvm::BasicBlock *EmitLandingPad(); @@ -886,7 +888,7 @@ private: DeclMapTy LocalDeclMap; /// Track escaped local variables with auto storage. Used during SEH - /// outlining to produce a call to llvm.frameescape. + /// outlining to produce a call to llvm.localescape. llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals; /// LabelMap - This keeps track of the LLVM basic block for each C label. @@ -1292,8 +1294,8 @@ public: void EmitMustTailThunk(const CXXMethodDecl *MD, llvm::Value *AdjustedThisPtr, llvm::Value *Callee); - /// GenerateThunk - Generate a thunk for the given method. - void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, + /// Generate a thunk for the given method. + void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn, @@ -2048,8 +2050,7 @@ public: void EnterSEHTryStmt(const SEHTryStmt &S); void ExitSEHTryStmt(const SEHTryStmt &S); - void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name, - QualType RetTy, FunctionArgList &Args, + void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter, const Stmt *OutlinedStmt); llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, @@ -2058,16 +2059,27 @@ public: llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, const SEHFinallyStmt &Finally); - void EmitSEHExceptionCodeSave(); + void EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, + llvm::Value *ParentFP, + llvm::Value *EntryEBP); llvm::Value *EmitSEHExceptionCode(); llvm::Value *EmitSEHExceptionInfo(); llvm::Value *EmitSEHAbnormalTermination(); /// Scan the outlined statement for captures from the parent function. For /// each capture, mark the capture as escaped and emit a call to - /// llvm.framerecover. Insert the framerecover result into the LocalDeclMap. + /// llvm.localrecover. Insert the localrecover result into the LocalDeclMap. void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, - llvm::Value *ParentFP); + bool IsFilter); + + /// Recovers the address of a local in a parent function. ParentVar is the + /// address of the variable used in the immediate parent function. It can + /// either be an alloca or a call to llvm.localrecover if there are nested + /// outlined functions. ParentFP is the frame pointer of the outermost parent + /// frame. + llvm::Value *recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, + llvm::Value *ParentVar, + llvm::Value *ParentFP); void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef<const Attr *> Attrs = None); @@ -2931,6 +2943,26 @@ private: SourceLocation Loc); public: +#ifndef NDEBUG + // Determine whether the given argument is an Objective-C method + // that may have type parameters in its signature. + static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { + const DeclContext *dc = method->getDeclContext(); + if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) { + return classDecl->getTypeParamListAsWritten(); + } + + if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) { + return catDecl->getTypeParamList(); + } + + return false; + } + + template<typename T> + static bool isObjCMethodWithTypeParams(const T *) { return false; } +#endif + /// EmitCallArgs - Emit call arguments for a function. template <typename T> void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, @@ -2944,18 +2976,25 @@ public: assert((ParamsToSkip == 0 || CallArgTypeInfo) && "Can't skip parameters if type info is not provided"); if (CallArgTypeInfo) { +#ifndef NDEBUG + bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo); +#endif + // First, use the argument types that the type info knows about for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip, E = CallArgTypeInfo->param_type_end(); I != E; ++I, ++Arg) { assert(Arg != ArgEnd && "Running over edge of argument list!"); - assert( - ((*I)->isVariablyModifiedType() || - getContext() - .getCanonicalType((*I).getNonReferenceType()) - .getTypePtr() == - getContext().getCanonicalType(Arg->getType()).getTypePtr()) && - "type mismatch in call argument!"); + assert((isGenericMethod || + ((*I)->isVariablyModifiedType() || + (*I).getNonReferenceType()->isObjCRetainableType() || + getContext() + .getCanonicalType((*I).getNonReferenceType()) + .getTypePtr() == + getContext() + .getCanonicalType(Arg->getType()) + .getTypePtr())) && + "type mismatch in call argument!"); ArgTypes.push_back(*I); } } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index b905bd2b36bf..a179ad42eac1 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1262,6 +1262,11 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { // Implicit template instantiations may change linkage if they are later // explicitly instantiated, so they should not be emitted eagerly. return false; + // If OpenMP is enabled and threadprivates must be generated like TLS, delay + // codegen for global variables, because they may be marked as threadprivate. + if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS && + getContext().getTargetInfo().isTLSSupported() && isa<VarDecl>(Global)) + return false; return true; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 9a295feaffa4..dd167a29f5ac 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1126,6 +1126,10 @@ public: /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + /// Returns whether the given record is blacklisted from control flow + /// integrity checks. + bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD); + /// Emit bit set entries for the given vtable using the given layout if /// vptr CFI is enabled. void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index fa86e52ec804..70af69b76457 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2095,7 +2095,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( CGBuilderTy Builder(Entry); if (InitIsInitFunc) { if (Init) - Builder.CreateCall(Init, {}); + Builder.CreateCall(Init); } else { // Don't know whether we have an init function. Call it if it exists. llvm::Value *Have = Builder.CreateIsNotNull(Init); @@ -2104,7 +2104,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( Builder.CreateCondBr(Have, InitBB, ExitBB); Builder.SetInsertPoint(InitBB); - Builder.CreateCall(Init, {}); + Builder.CreateCall(Init); Builder.CreateBr(ExitBB); Builder.SetInsertPoint(ExitBB); @@ -2133,7 +2133,7 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty); llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val); - Val = CGF.Builder.CreateCall(Wrapper, {}); + Val = CGF.Builder.CreateCall(Wrapper); LValue LV; if (VD->getType()->isReferenceType()) @@ -3620,7 +3620,7 @@ static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) { catchCall->setCallingConv(CGM.getRuntimeCC()); // Call std::terminate(). - llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn(), {}); + llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn()); termCall->setDoesNotThrow(); termCall->setDoesNotReturn(); termCall->setCallingConv(CGM.getRuntimeCC()); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index d149df63c9e4..3433990e1288 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1466,20 +1466,27 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, llvm::NamedMDNode *BitsetsMD = CGM.getModule().getOrInsertNamedMetadata("llvm.bitsets"); - CharUnits PointerWidth = getContext().toCharUnitsFromBits( - getContext().getTargetInfo().getPointerWidth(0)); - // FIXME: Add blacklisting scheme. + // The location of the first virtual function pointer in the virtual table, + // aka the "address point" on Itanium. This is at offset 0 if RTTI is + // disabled, or sizeof(void*) if RTTI is enabled. + CharUnits AddressPoint = + getContext().getLangOpts().RTTIData + ? getContext().toCharUnitsFromBits( + getContext().getTargetInfo().getPointerWidth(0)) + : CharUnits::Zero(); if (Info->PathToBaseWithVPtr.empty()) { - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + if (!CGM.IsCFIBlacklistedRecord(RD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); return; } // Add a bitset entry for the least derived base belonging to this vftable. - BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( - VTable, PointerWidth, Info->PathToBaseWithVPtr.back())); + if (!CGM.IsCFIBlacklistedRecord(Info->PathToBaseWithVPtr.back())) + BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( + VTable, AddressPoint, Info->PathToBaseWithVPtr.back())); // Add a bitset entry for each derived class that is laid out at the same // offset as the least derived base. @@ -1497,14 +1504,15 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, Offset = VBI->second.VBaseOffset; if (!Offset.isZero()) return; - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, DerivedRD)); + if (!CGM.IsCFIBlacklistedRecord(DerivedRD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, DerivedRD)); } // Finally do the same for the most derived class. - if (Info->FullOffsetInMDC.isZero()) + if (Info->FullOffsetInMDC.isZero() && !CGM.IsCFIBlacklistedRecord(RD)) BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); } void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, @@ -1707,7 +1715,7 @@ static const CXXRecordDecl *getClassAtVTableLocation(ASTContext &Ctx, for (auto &&B : RD->bases()) { const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); CharUnits BaseOffset = Layout.getBaseClassOffset(Base); - if (BaseOffset <= Offset && BaseOffset > MaxBaseOffset) { + if (BaseOffset <= Offset && BaseOffset >= MaxBaseOffset) { MaxBase = Base; MaxBaseOffset = BaseOffset; } @@ -1715,7 +1723,7 @@ static const CXXRecordDecl *getClassAtVTableLocation(ASTContext &Ctx, for (auto &&B : RD->vbases()) { const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); CharUnits BaseOffset = Layout.getVBaseClassOffset(Base); - if (BaseOffset <= Offset && BaseOffset > MaxBaseOffset) { + if (BaseOffset <= Offset && BaseOffset >= MaxBaseOffset) { MaxBase = Base; MaxBaseOffset = BaseOffset; } diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp new file mode 100644 index 000000000000..8f04e06988d8 --- /dev/null +++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -0,0 +1,193 @@ +//===--- ObjectFilePCHContainerOperations.cpp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" +#include "CGDebugInfo.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/BackendUtil.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Serialization/ASTWriter.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/TargetRegistry.h" +#include <memory> +using namespace clang; + +#define DEBUG_TYPE "pchcontainer" + +namespace { +class PCHContainerGenerator : public ASTConsumer { + DiagnosticsEngine &Diags; + const std::string MainFileName; + ASTContext *Ctx; + const HeaderSearchOptions &HeaderSearchOpts; + const PreprocessorOptions &PreprocessorOpts; + CodeGenOptions CodeGenOpts; + const TargetOptions TargetOpts; + const LangOptions LangOpts; + std::unique_ptr<llvm::LLVMContext> VMContext; + std::unique_ptr<llvm::Module> M; + std::unique_ptr<CodeGen::CodeGenModule> Builder; + raw_pwrite_stream *OS; + std::shared_ptr<PCHBuffer> Buffer; + +public: + PCHContainerGenerator(DiagnosticsEngine &diags, + const HeaderSearchOptions &HSO, + const PreprocessorOptions &PPO, const TargetOptions &TO, + const LangOptions &LO, const std::string &MainFileName, + const std::string &OutputFileName, + raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) + : Diags(diags), HeaderSearchOpts(HSO), PreprocessorOpts(PPO), + TargetOpts(TO), LangOpts(LO), OS(OS), Buffer(Buffer) { + // The debug info output isn't affected by CodeModel and + // ThreadModel, but the backend expects them to be nonempty. + CodeGenOpts.CodeModel = "default"; + CodeGenOpts.ThreadModel = "single"; + CodeGenOpts.setDebugInfo(CodeGenOptions::FullDebugInfo); + CodeGenOpts.SplitDwarfFile = OutputFileName; + } + + virtual ~PCHContainerGenerator() {} + + void Initialize(ASTContext &Context) override { + Ctx = &Context; + VMContext.reset(new llvm::LLVMContext()); + M.reset(new llvm::Module(MainFileName, *VMContext)); + M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); + Builder.reset(new CodeGen::CodeGenModule(*Ctx, HeaderSearchOpts, + PreprocessorOpts, CodeGenOpts, *M, + M->getDataLayout(), Diags)); + } + + /// Emit a container holding the serialized AST. + void HandleTranslationUnit(ASTContext &Ctx) override { + assert(M && VMContext && Builder); + // Delete these on function exit. + std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext); + std::unique_ptr<llvm::Module> M = std::move(this->M); + std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder); + + if (Diags.hasErrorOccurred()) + return; + + M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple()); + M->setDataLayout(Ctx.getTargetInfo().getTargetDescription()); + + // Finalize the Builder. + if (Builder) + Builder->Release(); + + // Ensure the target exists. + std::string Error; + auto Triple = Ctx.getTargetInfo().getTriple(); + if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error)) + llvm::report_fatal_error(Error); + + // Emit the serialized Clang AST into its own section. + assert(Buffer->IsComplete && "serialization did not complete"); + auto &SerializedAST = Buffer->Data; + auto Size = SerializedAST.size(); + auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); + auto *Ty = llvm::ArrayType::get(Int8Ty, Size); + auto *Data = llvm::ConstantDataArray::getString( + *VMContext, StringRef(SerializedAST.data(), Size), + /*AddNull=*/false); + auto *ASTSym = new llvm::GlobalVariable( + *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data, + "__clang_ast"); + // The on-disk hashtable needs to be aligned. + ASTSym->setAlignment(8); + + // Mach-O also needs a segment name. + if (Triple.isOSBinFormatMachO()) + ASTSym->setSection("__CLANG,__clangast"); + // COFF has an eight character length limit. + else if (Triple.isOSBinFormatCOFF()) + ASTSym->setSection("clangast"); + else + ASTSym->setSection("__clangast"); + + DEBUG({ + // Print the IR for the PCH container to the debug output. + llvm::SmallString<0> Buffer; + llvm::raw_svector_ostream OS(Buffer); + clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, + Ctx.getTargetInfo().getTargetDescription(), + M.get(), BackendAction::Backend_EmitLL, &OS); + OS.flush(); + llvm::dbgs() << Buffer; + }); + + // Use the LLVM backend to emit the pch container. + clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, + Ctx.getTargetInfo().getTargetDescription(), + M.get(), BackendAction::Backend_EmitObj, OS); + + // Make sure the pch container hits disk. + OS->flush(); + + // Free the memory for the temporary buffer. + llvm::SmallVector<char, 0> Empty; + SerializedAST = std::move(Empty); + } +}; + +} // namespace + +std::unique_ptr<ASTConsumer> +ObjectFilePCHContainerOperations::CreatePCHContainerGenerator( + DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO, + const PreprocessorOptions &PPO, const TargetOptions &TO, + const LangOptions &LO, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const { + return llvm::make_unique<PCHContainerGenerator>( + Diags, HSO, PPO, TO, LO, MainFileName, OutputFileName, OS, Buffer); +} + +void ObjectFilePCHContainerOperations::ExtractPCH( + llvm::MemoryBufferRef Buffer, llvm::BitstreamReader &StreamFile) const { + if (auto OF = llvm::object::ObjectFile::createObjectFile(Buffer)) { + auto *Obj = OF.get().get(); + bool IsCOFF = isa<llvm::object::COFFObjectFile>(Obj); + // Find the clang AST section in the container. + for (auto &Section : OF->get()->sections()) { + StringRef Name; + Section.getName(Name); + if ((!IsCOFF && Name == "__clangast") || + ( IsCOFF && Name == "clangast")) { + StringRef Buf; + Section.getContents(Buf); + StreamFile.init((const unsigned char *)Buf.begin(), + (const unsigned char *)Buf.end()); + return; + } + } + } + + // As a fallback, treat the buffer as a raw AST. + StreamFile.init((const unsigned char *)Buffer.getBufferStart(), + (const unsigned char *)Buffer.getBufferEnd()); + return; +} diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index e5ba200e1c57..6226d213b620 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2073,8 +2073,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; + if (Lo == Memory || Hi == Memory) { + postMerge(Size, Lo, Hi); + return; + } } } @@ -2094,11 +2096,13 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // if (Size > 128 && getContext().getTypeSize(i->getType()) != 256) { Lo = Memory; + postMerge(Size, Lo, Hi); return; } // Note, skip this test for bit-fields, see below. if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { Lo = Memory; + postMerge(Size, Lo, Hi); return; } @@ -7095,6 +7099,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: + if (Triple.getOS() == llvm::Triple::NaCl) + return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true)); case llvm::Triple::mips64: diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 360dbeecabf9..3219dc1cc0e9 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -24,6 +24,8 @@ const char *Action::getClassName(ActionClass AC) { switch (AC) { case InputClass: return "input"; case BindArchClass: return "bind-arch"; + case CudaDeviceClass: return "cuda-device"; + case CudaHostClass: return "cuda-host"; case PreprocessJobClass: return "preprocessor"; case PrecompileJobClass: return "precompiler"; case AnalyzeJobClass: return "analyzer"; @@ -53,6 +55,25 @@ BindArchAction::BindArchAction(std::unique_ptr<Action> Input, const char *_ArchName) : Action(BindArchClass, std::move(Input)), ArchName(_ArchName) {} +void CudaDeviceAction::anchor() {} + +CudaDeviceAction::CudaDeviceAction(std::unique_ptr<Action> Input, + const char *ArchName, bool AtTopLevel) + : Action(CudaDeviceClass, std::move(Input)), GpuArchName(ArchName), + AtTopLevel(AtTopLevel) {} + +void CudaHostAction::anchor() {} + +CudaHostAction::CudaHostAction(std::unique_ptr<Action> Input, + const ActionList &_DeviceActions) + : Action(CudaHostClass, std::move(Input)), DeviceActions(_DeviceActions) {} + +CudaHostAction::~CudaHostAction() { + for (iterator it = DeviceActions.begin(), ie = DeviceActions.end(); it != ie; + ++it) + delete *it; +} + void JobAction::anchor() {} JobAction::JobAction(ActionClass Kind, std::unique_ptr<Action> Input, diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index b9dc35d6219a..180c412bd791 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -174,8 +174,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; - // -c only runs up to the assembler. - } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { + // -c and partial CUDA compilations only run up to the assembler. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_c)) || + (PhaseArg = DAL.getLastArg(options::OPT_cuda_device_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_cuda_host_only))) { FinalPhase = phases::Assemble; // Otherwise do everything. @@ -281,6 +283,83 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { return DAL; } +/// \brief Compute target triple from args. +/// +/// This routine provides the logic to compute a target triple from various +/// args passed to the driver and the default triple string. +static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, + const ArgList &Args, + StringRef DarwinArchName = "") { + // FIXME: Already done in Compilation *Driver::BuildCompilation + if (const Arg *A = Args.getLastArg(options::OPT_target)) + DefaultTargetTriple = A->getValue(); + + llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); + + // Handle Apple-specific options available here. + if (Target.isOSBinFormatMachO()) { + // If an explict Darwin arch name is given, that trumps all. + if (!DarwinArchName.empty()) { + tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); + return Target; + } + + // Handle the Darwin '-arch' flag. + if (Arg *A = Args.getLastArg(options::OPT_arch)) { + StringRef ArchName = A->getValue(); + tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); + } + } + + // Handle pseudo-target flags '-mlittle-endian'/'-EL' and + // '-mbig-endian'/'-EB'. + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + if (A->getOption().matches(options::OPT_mlittle_endian)) { + llvm::Triple LE = Target.getLittleEndianArchVariant(); + if (LE.getArch() != llvm::Triple::UnknownArch) + Target = std::move(LE); + } else { + llvm::Triple BE = Target.getBigEndianArchVariant(); + if (BE.getArch() != llvm::Triple::UnknownArch) + Target = std::move(BE); + } + } + + // Skip further flag support on OSes which don't support '-m32' or '-m64'. + if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) + return Target; + + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. + if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, + options::OPT_m32, options::OPT_m16)) { + llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; + + if (A->getOption().matches(options::OPT_m64)) { + AT = Target.get64BitArchVariant().getArch(); + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_mx32) && + Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { + AT = llvm::Triple::x86_64; + Target.setEnvironment(llvm::Triple::GNUX32); + } else if (A->getOption().matches(options::OPT_m32)) { + AT = Target.get32BitArchVariant().getArch(); + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_m16) && + Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { + AT = llvm::Triple::x86; + Target.setEnvironment(llvm::Triple::CODE16); + } + + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) + Target.setArch(AT); + } + + return Target; +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -367,7 +446,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); // Owned by the host. - const ToolChain &TC = getToolChain(*UArgs); + const ToolChain &TC = + getToolChain(*UArgs, computeTargetTriple(DefaultTargetTriple, *UArgs)); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); @@ -398,6 +478,19 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { return C; } +static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { + llvm::opt::ArgStringList ASL; + for (const auto *A : Args) + A->render(Args, ASL); + + for (auto I = ASL.begin(), E = ASL.end(); I != E; ++I) { + if (I != ASL.begin()) + OS << ' '; + Command::printArg(OS, *I, true); + } + OS << '\n'; +} + // When clang crashes, produce diagnostic information including the fully // preprocessed source file(s). Request that the developer attach the // diagnostic information to a bug report. @@ -546,7 +639,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C, << "Error generating run script: " + Script + " " + EC.message(); } else { ScriptOS << "# Crash reproducer for " << getClangFullVersion() << "\n" - << "# Original command: "; + << "# Driver args: "; + printArgList(ScriptOS, C.getInputArgs()); + ScriptOS << "# Original command: "; Cmd.Print(ScriptOS, "\n", /*Quote=*/true); Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo); Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; @@ -787,14 +882,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } return false; } - - if (C.getArgs().hasArg(options::OPT_print_multi_os_directory)) { - // FIXME: This should print out "lib/../lib", "lib/../lib64", or - // "lib/../lib32" as appropriate for the toolchain. For now, print - // nothing because it's not supported yet. - return false; - } - return true; } @@ -815,9 +902,20 @@ static unsigned PrintActions1(const Compilation &C, Action *A, } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { os << '"' << BIA->getArchName() << '"' << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}"; + } else if (CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { + os << '"' << CDA->getGpuArchName() << '"' << ", {" + << PrintActions1(C, *CDA->begin(), Ids) << "}"; } else { + ActionList *AL; + if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { + os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}" + << ", gpu binaries "; + AL = &CHA->getDeviceActions(); + } else + AL = &A->getInputs(); + const char *Prefix = "{"; - for (Action *PreRequisite : *A) { + for (Action *PreRequisite : *AL) { os << Prefix << PrintActions1(C, PreRequisite, Ids); Prefix = ", "; } @@ -1130,6 +1228,93 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } +// For each unique --cuda-gpu-arch= argument creates a TY_CUDA_DEVICE input +// action and then wraps each in CudaDeviceAction paired with appropriate GPU +// arch name. If we're only building device-side code, each action remains +// independent. Otherwise we pass device-side actions as inputs to a new +// CudaHostAction which combines both host and device side actions. +static std::unique_ptr<Action> +buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, + const Arg *InputArg, const types::ID InputType, + std::unique_ptr<Action> Current, ActionList &Actions) { + + assert(InputType == types::TY_CUDA && + "CUDA Actions only apply to CUDA inputs."); + + // Collect all cuda_gpu_arch parameters, removing duplicates. + SmallVector<const char *, 4> GpuArchList; + llvm::StringSet<> GpuArchNames; + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) { + A->claim(); + if (GpuArchNames.insert(A->getValue()).second) + GpuArchList.push_back(A->getValue()); + } + } + + // Default to sm_20 which is the lowest common denominator for supported GPUs. + // sm_20 code should work correctly, if suboptimally, on all newer GPUs. + if (GpuArchList.empty()) + GpuArchList.push_back("sm_20"); + + // Replicate inputs for each GPU architecture. + Driver::InputList CudaDeviceInputs; + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); + + // Build actions for all device inputs. + ActionList CudaDeviceActions; + D.BuildActions(TC, Args, CudaDeviceInputs, CudaDeviceActions); + assert(GpuArchList.size() == CudaDeviceActions.size() && + "Failed to create actions for all devices"); + + // Check whether any of device actions stopped before they could generate PTX. + bool PartialCompilation = false; + bool DeviceOnlyCompilation = Args.hasArg(options::OPT_cuda_device_only); + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) { + if (CudaDeviceActions[i]->getKind() != Action::BackendJobClass) { + PartialCompilation = true; + break; + } + } + + // Figure out what to do with device actions -- pass them as inputs to the + // host action or run each of them independently. + if (PartialCompilation || DeviceOnlyCompilation) { + // In case of partial or device-only compilation results of device actions + // are not consumed by the host action device actions have to be added to + // top-level actions list with AtTopLevel=true and run independently. + + // -o is ambiguous if we have more than one top-level action. + if (Args.hasArg(options::OPT_o) && + (!DeviceOnlyCompilation || GpuArchList.size() > 1)) { + D.Diag(clang::diag::err_drv_output_argument_with_multiple_files); + return nullptr; + } + + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + Actions.push_back( + new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), + GpuArchList[i], /* AtTopLevel */ true)); + // Kill host action in case of device-only compilation. + if (DeviceOnlyCompilation) + Current.reset(nullptr); + return Current; + } else { + // Outputs of device actions during complete CUDA compilation get created + // with AtTopLevel=false and become inputs for the host action. + ActionList DeviceActions; + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + DeviceActions.push_back( + new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), + GpuArchList[i], /* AtTopLevel */ false)); + // Return a new host action that incorporates original host action and all + // device actions. + return std::unique_ptr<Action>( + new CudaHostAction(std::move(Current), DeviceActions)); + } +} + void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, const InputList &Inputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); @@ -1227,6 +1412,25 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, continue; } + phases::ID CudaInjectionPhase; + if (isSaveTempsEnabled()) { + // All phases are done independently, inject GPU blobs during compilation + // phase as that's where we generate glue code to init them. + CudaInjectionPhase = phases::Compile; + } else { + // Assumes that clang does everything up until linking phase, so we inject + // cuda device actions at the last step before linking. Otherwise CUDA + // host action forces preprocessor into a separate invocation. + if (FinalPhase == phases::Link) { + for (auto i = PL.begin(), e = PL.end(); i != e; ++i) { + auto next = i + 1; + if (next != e && *next == phases::Link) + CudaInjectionPhase = *i; + } + } else + CudaInjectionPhase = FinalPhase; + } + // Build the pipeline for this file. std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType)); for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); @@ -1252,6 +1456,15 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // Otherwise construct the appropriate action. Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current)); + + if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase && + !Args.hasArg(options::OPT_cuda_host_only)) { + Current = buildCudaActions(*this, TC, Args, InputArg, InputType, + std::move(Current), Actions); + if (!Current) + break; + } + if (Current->getType() == types::TY_Nothing) break; } @@ -1491,7 +1704,13 @@ static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps, if (isa<BackendJobAction>(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); - JobAction *CompileJA = cast<CompileJobAction>(*Inputs->begin()); + JobAction *CompileJA; + // Extract real host action, if it's a CudaHostAction. + if (CudaHostAction *CudaHA = dyn_cast<CudaHostAction>(*Inputs->begin())) + CompileJA = cast<CompileJobAction>(*CudaHA->begin()); + else + CompileJA = cast<CompileJobAction>(*Inputs->begin()); + const Tool *Compiler = TC->SelectTool(*CompileJA); if (!Compiler) return nullptr; @@ -1525,6 +1744,20 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); + InputInfoList CudaDeviceInputInfos; + if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { + InputInfo II; + // Append outputs of device jobs to the input list. + for (const Action *DA : CHA->getDeviceActions()) { + BuildJobsForAction(C, DA, TC, "", AtTopLevel, + /*MultipleArchs*/ false, LinkingOutput, II); + CudaDeviceInputInfos.push_back(II); + } + // Override current action with a real host compile action and continue + // processing it. + A = *CHA->begin(); + } + if (const InputAction *IA = dyn_cast<InputAction>(A)) { // FIXME: It would be nice to not claim this here; maybe the old scheme of // just using Args was better? @@ -1544,15 +1777,30 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, const char *ArchName = BAA->getArchName(); if (ArchName) - TC = &getToolChain(C.getArgs(), ArchName); + TC = &getToolChain( + C.getArgs(), + computeTargetTriple(DefaultTargetTriple, C.getArgs(), ArchName)); else TC = &C.getDefaultToolChain(); - BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), AtTopLevel, + BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel, MultipleArchs, LinkingOutput, Result); return; } + if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { + // Figure out which NVPTX triple to use for device-side compilation based on + // whether host is 64-bit. + llvm::Triple DeviceTriple(C.getDefaultToolChain().getTriple().isArch64Bit() + ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda"); + BuildJobsForAction(C, *CDA->begin(), + &getToolChain(C.getArgs(), DeviceTriple), + CDA->getGpuArchName(), CDA->isAtTopLevel(), + /*MultipleArchs*/ true, LinkingOutput, Result); + return; + } + const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); @@ -1584,6 +1832,10 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); + // Append outputs of cuda device jobs to the input list + if (CudaDeviceInputInfos.size()) + InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end()); + // Determine the place to write output to, if any. if (JA->getType() == types::TY_Nothing) Result = InputInfo(A->getType(), BaseInput); @@ -1899,93 +2151,8 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, return Path.str(); } -/// \brief Compute target triple from args. -/// -/// This routine provides the logic to compute a target triple from various -/// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, - const ArgList &Args, - StringRef DarwinArchName) { - // FIXME: Already done in Compilation *Driver::BuildCompilation - if (const Arg *A = Args.getLastArg(options::OPT_target)) - DefaultTargetTriple = A->getValue(); - - llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); - - // Handle Apple-specific options available here. - if (Target.isOSBinFormatMachO()) { - // If an explict Darwin arch name is given, that trumps all. - if (!DarwinArchName.empty()) { - tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); - return Target; - } - - // Handle the Darwin '-arch' flag. - if (Arg *A = Args.getLastArg(options::OPT_arch)) { - StringRef ArchName = A->getValue(); - tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); - } - } - - // Handle pseudo-target flags '-mlittle-endian'/'-EL' and - // '-mbig-endian'/'-EB'. - if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, - options::OPT_mbig_endian)) { - if (A->getOption().matches(options::OPT_mlittle_endian)) { - if (Target.getArch() == llvm::Triple::mips) - Target.setArch(llvm::Triple::mipsel); - else if (Target.getArch() == llvm::Triple::mips64) - Target.setArch(llvm::Triple::mips64el); - else if (Target.getArch() == llvm::Triple::aarch64_be) - Target.setArch(llvm::Triple::aarch64); - } else { - if (Target.getArch() == llvm::Triple::mipsel) - Target.setArch(llvm::Triple::mips); - else if (Target.getArch() == llvm::Triple::mips64el) - Target.setArch(llvm::Triple::mips64); - else if (Target.getArch() == llvm::Triple::aarch64) - Target.setArch(llvm::Triple::aarch64_be); - } - } - - // Skip further flag support on OSes which don't support '-m32' or '-m64'. - if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) - return Target; - - // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. - if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, - options::OPT_m32, options::OPT_m16)) { - llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; - - if (A->getOption().matches(options::OPT_m64)) { - AT = Target.get64BitArchVariant().getArch(); - if (Target.getEnvironment() == llvm::Triple::GNUX32) - Target.setEnvironment(llvm::Triple::GNU); - } else if (A->getOption().matches(options::OPT_mx32) && - Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { - AT = llvm::Triple::x86_64; - Target.setEnvironment(llvm::Triple::GNUX32); - } else if (A->getOption().matches(options::OPT_m32)) { - AT = Target.get32BitArchVariant().getArch(); - if (Target.getEnvironment() == llvm::Triple::GNUX32) - Target.setEnvironment(llvm::Triple::GNU); - } else if (A->getOption().matches(options::OPT_m16) && - Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { - AT = llvm::Triple::x86; - Target.setEnvironment(llvm::Triple::CODE16); - } - - if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) - Target.setArch(AT); - } - - return Target; -} - const ToolChain &Driver::getToolChain(const ArgList &Args, - StringRef DarwinArchName) const { - llvm::Triple Target = - computeTargetTriple(DefaultTargetTriple, Args, DarwinArchName); + const llvm::Triple &Target) const { ToolChain *&TC = ToolChains[Target.str()]; if (!TC) { @@ -2050,6 +2217,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; } break; + case llvm::Triple::CUDA: + TC = new toolchains::CudaToolChain(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index ac18e1eb56a1..42bba56f5d41 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -71,7 +71,7 @@ static int skipArgs(const char *Flag, bool HaveCrashVFS) { return 0; } -static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { +void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) { const bool Escape = std::strpbrk(Arg, "\"\\$"); if (!Quote && !Escape) { @@ -146,7 +146,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { // Always quote the exe. OS << ' '; - PrintArg(OS, Executable, /*Quote=*/true); + printArg(OS, Executable, /*Quote=*/true); llvm::ArrayRef<const char *> Args = Arguments; llvm::SmallVector<const char *, 128> ArgsRespFile; @@ -175,20 +175,20 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, // Replace the input file name with the crashinfo's file name. OS << ' '; StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); - PrintArg(OS, ShortName.str().c_str(), Quote); + printArg(OS, ShortName.str().c_str(), Quote); continue; } } OS << ' '; - PrintArg(OS, Arg, Quote); + printArg(OS, Arg, Quote); } if (CrashInfo && HaveCrashVFS) { OS << ' '; - PrintArg(OS, "-ivfsoverlay", Quote); + printArg(OS, "-ivfsoverlay", Quote); OS << ' '; - PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); + printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); } if (ResponseFile != nullptr) { diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp index f20f58a119f4..c816b29dca23 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/MSVCToolChain.cpp @@ -526,8 +526,5 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, SanitizerMask MSVCToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; - // CFI checks are not implemented for MSVC ABI for now. - Res &= ~SanitizerKind::CFI; - Res &= ~SanitizerKind::CFICastStrict; return Res; } diff --git a/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp index 606508da6964..197c19e91413 100644 --- a/lib/Driver/MinGWToolChain.cpp +++ b/lib/Driver/MinGWToolChain.cpp @@ -1,5 +1,4 @@ -//===--- MinGWToolChain.cpp - MinGWToolChain Implementation -//-----------------------===// +//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===// // // The LLVM Compiler Infrastructure // @@ -25,6 +24,9 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + llvm::SmallString<1024> LibDir; + +#ifdef LLVM_ON_WIN32 if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; else if (llvm::ErrorOr<std::string> GPPName = @@ -34,8 +36,17 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) else Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); Base += llvm::sys::path::get_separator(); - llvm::SmallString<1024> LibDir(Base); + LibDir = Base; llvm::sys::path::append(LibDir, "lib", "gcc"); +#else + if (getDriver().SysRoot.size()) + Base = getDriver().SysRoot; + else + Base = "/usr/"; + LibDir = Base; + llvm::sys::path::append(LibDir, "lib64", "gcc"); +#endif + LibDir += llvm::sys::path::get_separator(); // First look for mingw-w64. @@ -45,6 +56,7 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) llvm::sys::fs::directory_iterator MingW64Entry(LibDir + Arch, EC); if (!EC) { GccLibDir = MingW64Entry->path(); + Ver = llvm::sys::path::filename(GccLibDir); } else { // If mingw-w64 not found, try looking for mingw.org. Arch = "mingw32"; @@ -58,6 +70,10 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) getFilePaths().push_back(GccLibDir); getFilePaths().push_back(Base + "lib"); getFilePaths().push_back(Base + Arch + "lib"); +#ifdef LLVM_ON_UNIX + // For openSUSE. + getFilePaths().push_back(Base + Arch + "sys-root/mingw/lib"); +#endif } bool MinGW::IsIntegratedAssemblerDefault() const { return true; } @@ -117,6 +133,11 @@ void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, llvm::sys::path::append(IncludeDir, "include"); addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str()); IncludeDir += "-fixed"; +#ifdef LLVM_ON_UNIX + // For openSUSE. + addSystemInclude(DriverArgs, CC1Args, + "/usr/x86_64-w64-mingw32/sys-root/mingw/include"); +#endif addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str()); addSystemInclude(DriverArgs, CC1Args, Base + Arch + "include"); addSystemInclude(DriverArgs, CC1Args, Base + "include"); @@ -128,16 +149,27 @@ void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdincxx)) return; - llvm::SmallString<1024> IncludeDir; - for (bool MingW64 : {true, false}) { - if (MingW64) - IncludeDir = Base + Arch; - else - IncludeDir = GccLibDir; - llvm::sys::path::append(IncludeDir, "include", "c++"); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str()); - IncludeDir += llvm::sys::path::get_separator(); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str() + Arch); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str() + "backward"); + // C++ includes may be found in several locations depending on distribution. + // Windows + // ------- + // mingw-w64 mingw-builds: $sysroot/i686-w64-mingw32/include/c++. + // mingw-w64 msys2: $sysroot/include/c++/4.9.2 + // mingw.org: GccLibDir/include/c++ + // + // Linux + // ----- + // openSUSE: GccLibDir/include/c++ + llvm::SmallVector<llvm::SmallString<1024>, 3> CppIncludeBases; + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[1], "include", "c++", Ver); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[2], "include", "c++"); + for (auto &CppIncludeBase : CppIncludeBases) { + CppIncludeBase += llvm::sys::path::get_separator(); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } } diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 3043481c7132..c3ad8ef9c1ef 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -176,6 +176,7 @@ void SanitizerArgs::clear() { BlacklistFiles.clear(); CoverageFeatures = 0; MsanTrackOrigins = 0; + MsanUseAfterDtor = false; AsanFieldPadding = 0; AsanZeroBaseShadow = false; AsanSharedRuntime = false; @@ -289,8 +290,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // toolchain. We don't have a good way to check the latter, so we just // check if the toolchan supports vptr. if (~Supported & Vptr) { - if (SanitizerMask KindsToDiagnose = - Kinds & ~TrappingKinds & NeedsUbsanCxxRt) { + SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; + // The runtime library supports the Microsoft C++ ABI, but only well enough + // for CFI. FIXME: Remove this once we support vptr on Windows. + if (TC.getTriple().isOSWindows()) + KindsToDiagnose &= ~CFI; + if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; D.Diag(diag::err_drv_unsupported_opt_for_target) @@ -413,6 +418,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } } + MsanUseAfterDtor = + Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); } // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the @@ -558,6 +565,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanTrackOrigins) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + llvm::utostr(MsanTrackOrigins))); + + if (MsanUseAfterDtor) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor")); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index da020a2b8c9d..e6a1bc9685de 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -151,6 +151,8 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::InputClass: case Action::BindArchClass: + case Action::CudaDeviceClass: + case Action::CudaHostClass: case Action::LipoJobClass: case Action::DsymutilJobClass: case Action::VerifyDebugInfoJobClass: diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index df74b41b0225..15e36a1e6ce0 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -303,6 +303,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || @@ -2337,6 +2338,13 @@ NaCl_TC::NaCl_TC(const Driver &D, const llvm::Triple &Triple, file_paths.push_back(ToolPath + "arm-nacl"); break; } + case llvm::Triple::mipsel: { + file_paths.push_back(FilePath + "mipsel-nacl/lib"); + file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "bin"); + file_paths.push_back(ToolPath + "mipsel-nacl"); + break; + } default: break; } @@ -2372,6 +2380,9 @@ void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/usr/include"); break; + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/usr/include"); + break; default: return; } @@ -2416,6 +2427,10 @@ void NaCl_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + break; default: break; } @@ -2868,6 +2883,7 @@ enum Distro { UbuntuTrusty, UbuntuUtopic, UbuntuVivid, + UbuntuWily, UnknownDistro }; @@ -2882,7 +2898,7 @@ static bool IsDebian(enum Distro Distro) { } static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuVivid; + return Distro >= UbuntuHardy && Distro <= UbuntuWily; } static Distro DetectDistro(llvm::Triple::ArchType Arch) { @@ -2911,6 +2927,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { .Case("trusty", UbuntuTrusty) .Case("utopic", UbuntuUtopic) .Case("vivid", UbuntuVivid) + .Case("wily", UbuntuWily) .Default(UnknownDistro); return Version; } @@ -3635,6 +3652,65 @@ Tool *DragonFly::buildLinker() const { return new tools::dragonfly::Linker(*this); } +/// Stub for CUDA toolchain. At the moment we don't have assembler or +/// linker and need toolchain mainly to propagate device-side options +/// to CC1. + +CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) {} + +void +CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + Linux::addClangTargetOptions(DriverArgs, CC1Args); + CC1Args.push_back("-fcuda-is-device"); +} + +llvm::opt::DerivedArgList * +CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_Xarch__)) { + // Skip this argument unless the architecture matches BoundArch + if (A->getValue(0) != StringRef(BoundArch)) + continue; + + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned Prev = Index; + std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + + // If the argument parsing failed or more than one argument was + // consumed, the -Xarch_ argument's parameter tried to consume + // extra arguments. Emit an error and ignore. + // + // We also want to disallow any options which would alter the + // driver behavior; that isn't going to work in our model. We + // use isDriverOption() as an approximation, although things + // like -O4 are going to slip through. + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) + << A->getAsString(Args); + continue; + } + XarchArg->setBaseArg(A); + A = XarchArg.release(); + DAL->AddSynthesizedArg(A); + } + DAL->append(A); + } + + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + return DAL; +} + /// XCore tool chain XCore::XCore(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 629f90ac79f8..327ff9b13b19 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -552,6 +552,7 @@ protected: private: std::string Base; std::string GccLibDir; + std::string Ver; std::string Arch; mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; @@ -698,6 +699,18 @@ private: std::string computeSysRoot() const; }; +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux { +public: + CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { protected: GCCVersion GCCLibAndIncVersion; @@ -746,7 +759,9 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool IsIntegratedAssemblerDefault() const override { return false; } + bool IsIntegratedAssemblerDefault() const override { + return getTriple().getArch() == llvm::Triple::mipsel; + } // Get the path to the file containing NaCl's ARM macros. It lives in NaCl_TC // because the AssembleARM tool needs a const char * that it can pass around diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index a2955dbb9e77..8c11992f1f82 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -638,6 +638,8 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<const char *> &Features, bool ForAS) { + bool KernelOrKext = + Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); if (!ForAS) { // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these @@ -705,6 +707,17 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_1a) { Features.insert(Features.begin(), "+v8.1a"); } + + // Look for the last occurrence of -mlong-calls or -mno-long-calls. If + // neither options are specified, see if we are compiling for kernel/kext and + // decide whether to pass "+long-calls" based on the OS and its version. + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mlong_calls)) + Features.push_back("+long-calls"); + } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6))) { + Features.push_back("+long-calls"); + } } void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, @@ -778,11 +791,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, // Kernel code has more strict alignment requirements. if (KernelOrKext) { - if (!Triple.isiOS() || Triple.isOSVersionLT(6)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-long-calls"); - } - CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-strict-align"); @@ -1264,9 +1272,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. const char *ABIName = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { - ABIName = A->getValue(); - } else if (getToolChain().getTriple().isOSLinux()) + if (getToolChain().getTriple().isOSLinux()) switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { // When targeting a processor that supports QPX, or if QPX is @@ -1291,6 +1297,13 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, break; } + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore + // the option if given as we don't have backend support for any targets + // that don't use the altivec abi. + if (StringRef(A->getValue()) != "altivec") + ABIName = A->getValue(); + if (ABIName) { CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); @@ -1475,6 +1488,12 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { return CPUName; } + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + return ""; + case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: { @@ -2028,17 +2047,6 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, Triple.getArch() == llvm::Triple::arm)); } -// exceptionSettings() exists to share the logic between -cc1 and linker -// invocations. -static bool exceptionSettings(const ArgList &Args, const llvm::Triple &Triple) { - if (Arg *A = Args.getLastArg(options::OPT_fexceptions, - options::OPT_fno_exceptions)) - if (A->getOption().matches(options::OPT_fexceptions)) - return true; - - return false; -} - /// Adds exception related arguments to the driver command arguments. There's a /// master flag, -fexceptions and also language specific flags to enable/disable /// C++ and Objective-C exceptions. This makes it possible to for example @@ -2062,8 +2070,9 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, return; } - // Gather the exception settings from the command line arguments. - bool EH = exceptionSettings(Args, Triple); + // See if the user explicitly enabled exceptions. + bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false); // Obj-C exceptions are enabled by default, regardless of -fexceptions. This // is not necessarily sensible, but follows GCC. @@ -2076,8 +2085,11 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, } if (types::isCXX(InputType)) { - bool CXXExceptionsEnabled = - Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); + // Disable C++ EH by default on XCore, PS4, and MSVC. + // FIXME: Remove MSVC from this list once things work. + bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore && + !Triple.isPS4CPU() && + !Triple.isWindowsMSVCEnvironment(); Arg *ExceptionArg = Args.getLastArg( options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions); @@ -2290,6 +2302,7 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || @@ -2723,6 +2736,89 @@ VersionTuple visualstudio::getMSVCVersion(const Driver *D, return VersionTuple(); } +static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, + const InputInfo &Output, const ArgList &Args, + ArgStringList &CmdArgs) { + auto *ProfileGenerateArg = Args.getLastArg( + options::OPT_fprofile_instr_generate, + options::OPT_fprofile_instr_generate_EQ, options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ); + + auto *ProfileUseArg = Args.getLastArg( + options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ); + + if (ProfileGenerateArg && ProfileUseArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << ProfileGenerateArg->getSpelling() + << ProfileUseArg->getSpelling(); + + if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_instr_generate_EQ)) + ProfileGenerateArg->render(Args, CmdArgs); + else if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_generate_EQ)) { + SmallString<128> Path(ProfileGenerateArg->getValue()); + llvm::sys::path::append(Path, "default.profraw"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); + } else + Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); + + if (ProfileUseArg && + ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) + ProfileUseArg->render(Args, CmdArgs); + else if (ProfileUseArg && + (ProfileUseArg->getOption().matches(options::OPT_fprofile_use_EQ) || + ProfileUseArg->getOption().matches( + options::OPT_fprofile_instr_use))) { + SmallString<128> Path( + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + } + + if (Args.hasArg(options::OPT_ftest_coverage) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-notes"); + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-data"); + + if (Args.hasArg(options::OPT_fcoverage_mapping) && !ProfileGenerateArg) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mapping" + << "-fprofile-instr-generate"; + + if (Args.hasArg(options::OPT_fcoverage_mapping)) + CmdArgs.push_back("-fcoverage-mapping"); + + if (C.getArgs().hasArg(options::OPT_c) || + C.getArgs().hasArg(options::OPT_S)) { + if (Output.isFilename()) { + CmdArgs.push_back("-coverage-file"); + SmallString<128> CoverageFilename; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { + CoverageFilename = FinalOutput->getValue(); + } else { + CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); + } + if (llvm::sys::path::is_relative(CoverageFilename)) { + SmallString<128> Pwd; + if (!llvm::sys::fs::current_path(Pwd)) { + llvm::sys::path::append(Pwd, CoverageFilename); + CoverageFilename.swap(Pwd); + } + } + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + } + } +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2736,8 +2832,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().isWindowsCygwinEnvironment(); bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); - assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Check number of inputs for sanity. We need at least one input. + assert(Inputs.size() >= 1 && "Must have at least one input."); const InputInfo &Input = Inputs[0]; + // CUDA compilation may have multiple inputs (source file + results of + // device-side compilations). All other jobs are expected to have exactly one + // input. + bool IsCuda = types::isCuda(Input.getType()); + assert((IsCuda || Inputs.size() == 1) && "Unable to handle multiple inputs."); // Invoke ourselves in -cc1 mode. // @@ -2805,6 +2907,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); + if (JA.getType() == types::TY_LTO_IR || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-flto"); + } if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); } else if (JA.getType() == types::TY_LLVM_IR || @@ -3520,62 +3626,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); - if ((Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ)) && - (Args.hasArg(options::OPT_fprofile_instr_use) || - Args.hasArg(options::OPT_fprofile_instr_use_EQ))) - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fprofile-instr-generate" - << "-fprofile-instr-use"; - - if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_generate_EQ)) - A->render(Args, CmdArgs); - else - Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); - - if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ)) - A->render(Args, CmdArgs); - else if (Args.hasArg(options::OPT_fprofile_instr_use)) - CmdArgs.push_back("-fprofile-instr-use=pgo-data"); - - if (Args.hasArg(options::OPT_ftest_coverage) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-notes"); - if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-data"); - - if (Args.hasArg(options::OPT_fcoverage_mapping) && - !(Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ))) - D.Diag(diag::err_drv_argument_only_allowed_with) - << "-fcoverage-mapping" - << "-fprofile-instr-generate"; - - if (Args.hasArg(options::OPT_fcoverage_mapping)) - CmdArgs.push_back("-fcoverage-mapping"); - - if (C.getArgs().hasArg(options::OPT_c) || - C.getArgs().hasArg(options::OPT_S)) { - if (Output.isFilename()) { - CmdArgs.push_back("-coverage-file"); - SmallString<128> CoverageFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { - CoverageFilename = FinalOutput->getValue(); - } else { - CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); - } - if (llvm::sys::path::is_relative(CoverageFilename)) { - SmallString<128> Pwd; - if (!llvm::sys::fs::current_path(Pwd)) { - llvm::sys::path::append(Pwd, CoverageFilename); - CoverageFilename.swap(Pwd); - } - } - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); - } - } + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { @@ -3915,6 +3966,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case OMPRT_IOMP5: // Clang can generate useful OpenMP code for these two runtime libraries. CmdArgs.push_back("-fopenmp"); + + // If no option regarding the use of TLS in OpenMP codegeneration is + // given, decide a default based on the target. Otherwise rely on the + // options and pass the right information to the frontend. + if (!Args.hasFlag(options::OPT_fopenmp_use_tls, + options::OPT_fnoopenmp_use_tls, + getToolChain().getArch() == llvm::Triple::ppc || + getToolChain().getArch() == llvm::Triple::ppc64 || + getToolChain().getArch() == llvm::Triple::ppc64le)) + CmdArgs.push_back("-fnoopenmp-use-tls"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -4070,17 +4131,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arm-restrict-it"); } - if (TT.getArch() == llvm::Triple::arm || - TT.getArch() == llvm::Triple::thumb) { - if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, - options::OPT_mno_long_calls)) { - if (A->getOption().matches(options::OPT_mlong_calls)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-long-calls"); - } - } - } - // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { @@ -4172,27 +4222,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmodule-cache-path specifies where our implicitly-built module files // should be written. - SmallString<128> ModuleCachePath; + SmallString<128> Path; if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) - ModuleCachePath = A->getValue(); + Path = A->getValue(); if (HaveModules) { if (C.isForDiagnostics()) { // When generating crash reports, we want to emit the modules along with // the reproduction sources, so we ignore any provided module path. - ModuleCachePath = Output.getFilename(); - llvm::sys::path::replace_extension(ModuleCachePath, ".cache"); - llvm::sys::path::append(ModuleCachePath, "modules"); - } else if (ModuleCachePath.empty()) { + Path = Output.getFilename(); + llvm::sys::path::replace_extension(Path, ".cache"); + llvm::sys::path::append(Path, "modules"); + } else if (Path.empty()) { // No module path was provided: use the default. llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, - ModuleCachePath); - llvm::sys::path::append(ModuleCachePath, "org.llvm.clang."); - appendUserToPath(ModuleCachePath); - llvm::sys::path::append(ModuleCachePath, "ModuleCache"); + Path); + llvm::sys::path::append(Path, "org.llvm.clang."); + appendUserToPath(Path); + llvm::sys::path::append(Path, "ModuleCache"); } const char Arg[] = "-fmodules-cache-path="; - ModuleCachePath.insert(ModuleCachePath.begin(), Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(ModuleCachePath)); + Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(Path)); } // When building modules and generating crashdumps, we need to dump a module @@ -4774,14 +4824,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - for (const auto &II : Inputs) { - addDashXForInput(Args, II, CmdArgs); + addDashXForInput(Args, Input, CmdArgs); - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else - II.getInputArg().renderAsInput(Args, CmdArgs); - } + if (Input.isFilename()) + CmdArgs.push_back(Input.getFilename()); + else + Input.getInputArg().renderAsInput(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_undef); @@ -4819,6 +4867,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(SplitDwarfOut); } + // Host-side cuda compilation receives device-side outputs as Inputs[1...]. + // Include them with -fcuda-include-gpubinary. + if (IsCuda && Inputs.size() > 1) + for (InputInfoList::const_iterator it = std::next(Inputs.begin()), + ie = Inputs.end(); + it != ie; ++it) { + CmdArgs.push_back("-fcuda-include-gpubinary"); + CmdArgs.push_back(it->getFilename()); + } + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && @@ -5005,6 +5063,7 @@ struct EHFlags { /// The default is /EHs-c-, meaning cleanups are disabled. static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { EHFlags EH; + std::vector<std::string> EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH); for (auto EHVal : EHArgs) { @@ -5026,6 +5085,11 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { break; } } + + // FIXME: Disable C++ EH completely, until it becomes more reliable. Users + // can use -Xclang to manually enable C++ EH until then. + EH = EHFlags(); + return EH; } @@ -8199,6 +8263,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("armelf_nacl"); else if (Arch == llvm::Triple::x86_64) CmdArgs.push_back("elf_x86_64_nacl"); + else if (Arch == llvm::Triple::mipsel) + CmdArgs.push_back("mipselelf_nacl"); else D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() << "Native Client"; @@ -8260,6 +8326,13 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // in the group for C++. if (Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { + // Gold, used by Mips, handles nested groups differently than ld, and + // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, + // which is not a desired behaviour here. + // See https://sourceware.org/ml/binutils/2015-03/msg00034.html + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lnacl"); + CmdArgs.push_back("-lpthread"); } @@ -8270,6 +8343,13 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); + + // Mips needs to create and use pnacl_legacy library that contains + // definitions from bitcode/pnaclmm.c and definitions for + // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lpnacl_legacy"); + CmdArgs.push_back("--end-group"); } @@ -8863,6 +8943,12 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld"); + if (LinkerName.equals_lower("lld")) { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("gnu"); + } + if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -8874,6 +8960,8 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("i386pe"); if (TC.getArch() == llvm::Triple::x86_64) CmdArgs.push_back("i386pep"); + if (TC.getArch() == llvm::Triple::arm) + CmdArgs.push_back("thumb2pe"); if (Args.hasArg(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); @@ -8968,10 +9056,8 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgmon"); - // FIXME: what to do about pthreads library? - // Currently required for OpenMP and posix-threading libgcc, - // does not exists in mingw.org. - //CmdArgs.push_back("-lpthread"); + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); // add system libraries if (Args.hasArg(options::OPT_mwindows)) { @@ -8985,7 +9071,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); - else + else if (!LinkerName.equals_lower("lld")) AddLibGCC(Args, CmdArgs); } @@ -8996,7 +9082,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } - const char *Exec = Args.MakeArgString(TC.GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); } @@ -9053,7 +9139,9 @@ void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); - if (exceptionSettings(Args, getToolChain().getTriple())) + // Pass -fexceptions through to the linker if it was present. + if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false)) CmdArgs.push_back("-fexceptions"); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 7b281457557b..2085b0124298 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -86,6 +86,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_C: case TY_PP_C: case TY_CL: case TY_CUDA: case TY_PP_CUDA: + case TY_CUDA_DEVICE: case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: case TY_CXX: case TY_PP_CXX: case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: @@ -122,7 +123,19 @@ bool types::isCXX(ID Id) { case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: - case TY_CUDA: case TY_PP_CUDA: + case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: + return true; + } +} + +bool types::isCuda(ID Id) { + switch (Id) { + default: + return false; + + case TY_CUDA: + case TY_PP_CUDA: + case TY_CUDA_DEVICE: return true; } } @@ -206,10 +219,12 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { P.push_back(phases::Compile); P.push_back(phases::Backend); } - P.push_back(phases::Assemble); + if (Id != TY_CUDA_DEVICE) + P.push_back(phases::Assemble); } } - if (!onlyPrecompileType(Id)) { + + if (!onlyPrecompileType(Id) && Id != TY_CUDA_DEVICE) { P.push_back(phases::Link); } assert(0 < P.size() && "Not enough phases in list"); diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index ed01d689c590..dd56831a3bc5 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -628,7 +628,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_StartOfName, TT_PointerOrReference) || - Previous.isOneOf(tok::coloncolon, tok::equal)) + Previous.isOneOf(tok::coloncolon, tok::equal, TT_JsTypeColon)) return ContinuationIndent; if (PreviousNonComment && PreviousNonComment->is(tok::colon) && PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) @@ -862,6 +862,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, unsigned LastSpace = State.Stack.back().LastSpace; bool AvoidBinPacking; bool BreakBeforeParameter = false; + unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, + State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) { if (Current.opensBlockTypeList(Style)) { NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth; @@ -875,6 +877,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) || Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod)); + if (Current.ParameterCount > 1) + NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { NewIndent = Style.ContinuationIndentWidth + std::max(State.Stack.back().LastSpace, @@ -922,8 +926,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, bool NoLineBreak = State.Stack.back().NoLineBreak || (Current.is(TT_TemplateOpener) && State.Stack.back().ContainsUnwrappedBuilder); - unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, - State.Stack.back().NestedBlockIndent); State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace, AvoidBinPacking, NoLineBreak)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 2bbe4c63d156..382ae819ebfd 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/YAMLTraits.h" #include <queue> #include <string> @@ -93,6 +94,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) { IO.enumCase(Value, "Attach", FormatStyle::BS_Attach); IO.enumCase(Value, "Linux", FormatStyle::BS_Linux); + IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla); IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup); IO.enumCase(Value, "Allman", FormatStyle::BS_Allman); IO.enumCase(Value, "GNU", FormatStyle::BS_GNU); @@ -244,6 +246,8 @@ template <> struct MappingTraits<FormatStyle> { Style.IndentWrappedFunctionNames); IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", Style.KeepEmptyLinesAtTheStartOfBlocks); + IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); + IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth); @@ -468,6 +472,8 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) { ChromiumStyle.BinPackParameters = false; ChromiumStyle.DerivePointerAlignment = false; } + ChromiumStyle.MacroBlockBegin = "^IPC_BEGIN_MESSAGE_MAP$"; + ChromiumStyle.MacroBlockBegin = "^IPC_END_MESSAGE_MAP$"; return ChromiumStyle; } @@ -478,6 +484,7 @@ FormatStyle getMozillaStyle() { MozillaStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel; MozillaStyle.AlwaysBreakTemplateDeclarations = true; + MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; MozillaStyle.BreakConstructorInitializersBeforeComma = true; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; @@ -620,7 +627,9 @@ public: LessStashed(false), Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false) { + Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), + MacroBlockBeginRegex(Style.MacroBlockBegin), + MacroBlockEndRegex(Style.MacroBlockEnd) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); @@ -1168,12 +1177,21 @@ private: Column = FormatTok->LastLineColumnWidth; } - if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() && - Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == - tok::pp_define) && - std::find(ForEachMacros.begin(), ForEachMacros.end(), - FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) - FormatTok->Type = TT_ForEachMacro; + if (Style.Language == FormatStyle::LK_Cpp) { + if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() && + Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == + tok::pp_define) && + std::find(ForEachMacros.begin(), ForEachMacros.end(), + FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) { + FormatTok->Type = TT_ForEachMacro; + } else if (FormatTok->is(tok::identifier)) { + if (MacroBlockBeginRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockBegin; + } else if (MacroBlockEndRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockEnd; + } + } + } return FormatTok; } @@ -1198,6 +1216,9 @@ private: bool FormattingDisabled; + llvm::Regex MacroBlockBeginRegex; + llvm::Regex MacroBlockEndRegex; + void readRawToken(FormatToken &Tok) { Lex->LexFromRawLexer(Tok.Tok); Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()), diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp index 316171dc1891..6c244c316604 100644 --- a/lib/Format/FormatToken.cpp +++ b/lib/Format/FormatToken.cpp @@ -23,6 +23,20 @@ namespace clang { namespace format { +const char *getTokenTypeName(TokenType Type) { + static const char *const TokNames[] = { +#define TYPE(X) #X, +LIST_TOKEN_TYPES +#undef TYPE + nullptr + }; + + if (Type < NUM_TOKEN_TYPES) + return TokNames[Type]; + llvm_unreachable("unknown TokenType"); + return nullptr; +} + // FIXME: This is copy&pasted from Sema. Put it in a common place and remove // duplication. bool FormatToken::isSimpleTypeSpecifier() const { diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 5b7dadb8545b..f335eda086c0 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -25,66 +25,77 @@ namespace clang { namespace format { +#define LIST_TOKEN_TYPES \ + TYPE(ArrayInitializerLSquare) \ + TYPE(ArraySubscriptLSquare) \ + TYPE(AttributeParen) \ + TYPE(BinaryOperator) \ + TYPE(BitFieldColon) \ + TYPE(BlockComment) \ + TYPE(CastRParen) \ + TYPE(ConditionalExpr) \ + TYPE(ConflictAlternative) \ + TYPE(ConflictEnd) \ + TYPE(ConflictStart) \ + TYPE(CtorInitializerColon) \ + TYPE(CtorInitializerComma) \ + TYPE(DesignatedInitializerPeriod) \ + TYPE(DictLiteral) \ + TYPE(ForEachMacro) \ + TYPE(FunctionAnnotationRParen) \ + TYPE(FunctionDeclarationName) \ + TYPE(FunctionLBrace) \ + TYPE(FunctionTypeLParen) \ + TYPE(ImplicitStringLiteral) \ + TYPE(InheritanceColon) \ + TYPE(InlineASMBrace) \ + TYPE(InlineASMColon) \ + TYPE(JavaAnnotation) \ + TYPE(JsComputedPropertyName) \ + TYPE(JsFatArrow) \ + TYPE(JsTypeColon) \ + TYPE(JsTypeOptionalQuestion) \ + TYPE(LambdaArrow) \ + TYPE(LambdaLSquare) \ + TYPE(LeadingJavaAnnotation) \ + TYPE(LineComment) \ + TYPE(MacroBlockBegin) \ + TYPE(MacroBlockEnd) \ + TYPE(ObjCBlockLBrace) \ + TYPE(ObjCBlockLParen) \ + TYPE(ObjCDecl) \ + TYPE(ObjCForIn) \ + TYPE(ObjCMethodExpr) \ + TYPE(ObjCMethodSpecifier) \ + TYPE(ObjCProperty) \ + TYPE(ObjCStringLiteral) \ + TYPE(OverloadedOperator) \ + TYPE(OverloadedOperatorLParen) \ + TYPE(PointerOrReference) \ + TYPE(PureVirtualSpecifier) \ + TYPE(RangeBasedForLoopColon) \ + TYPE(RegexLiteral) \ + TYPE(SelectorName) \ + TYPE(StartOfName) \ + TYPE(TemplateCloser) \ + TYPE(TemplateOpener) \ + TYPE(TemplateString) \ + TYPE(TrailingAnnotation) \ + TYPE(TrailingReturnArrow) \ + TYPE(TrailingUnaryOperator) \ + TYPE(UnaryOperator) \ + TYPE(Unknown) + enum TokenType { - TT_ArrayInitializerLSquare, - TT_ArraySubscriptLSquare, - TT_AttributeParen, - TT_BinaryOperator, - TT_BitFieldColon, - TT_BlockComment, - TT_CastRParen, - TT_ConditionalExpr, - TT_ConflictAlternative, - TT_ConflictEnd, - TT_ConflictStart, - TT_CtorInitializerColon, - TT_CtorInitializerComma, - TT_DesignatedInitializerPeriod, - TT_DictLiteral, - TT_ForEachMacro, - TT_FunctionAnnotationRParen, - TT_FunctionDeclarationName, - TT_FunctionLBrace, - TT_FunctionTypeLParen, - TT_ImplicitStringLiteral, - TT_InheritanceColon, - TT_InlineASMBrace, - TT_InlineASMColon, - TT_JavaAnnotation, - TT_JsComputedPropertyName, - TT_JsFatArrow, - TT_JsTypeColon, - TT_JsTypeOptionalQuestion, - TT_LambdaArrow, - TT_LambdaLSquare, - TT_LeadingJavaAnnotation, - TT_LineComment, - TT_ObjCBlockLBrace, - TT_ObjCBlockLParen, - TT_ObjCDecl, - TT_ObjCForIn, - TT_ObjCMethodExpr, - TT_ObjCMethodSpecifier, - TT_ObjCProperty, - TT_ObjCStringLiteral, - TT_OverloadedOperator, - TT_OverloadedOperatorLParen, - TT_PointerOrReference, - TT_PureVirtualSpecifier, - TT_RangeBasedForLoopColon, - TT_RegexLiteral, - TT_SelectorName, - TT_StartOfName, - TT_TemplateCloser, - TT_TemplateOpener, - TT_TemplateString, - TT_TrailingAnnotation, - TT_TrailingReturnArrow, - TT_TrailingUnaryOperator, - TT_UnaryOperator, - TT_Unknown +#define TYPE(X) TT_##X, +LIST_TOKEN_TYPES +#undef TYPE + NUM_TOKEN_TYPES }; +/// \brief Determines the name of a token type. +const char *getTokenTypeName(TokenType Type); + // Represents what type of block a set of braces open. enum BraceBlockKind { BK_Unknown, BK_Block, BK_BracedInit }; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 0e1f14ad05f2..ea8b30de8dfb 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -505,7 +505,8 @@ private: if (Line.MustBeDeclaration && Contexts.size() == 1 && !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && (!Tok->Previous || - !Tok->Previous->isOneOf(tok::kw_decltype, TT_LeadingJavaAnnotation))) + !Tok->Previous->isOneOf(tok::kw_decltype, tok::kw___attribute, + TT_LeadingJavaAnnotation))) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -1627,6 +1628,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma)) return 100; + if (Left.is(TT_JsTypeColon)) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -1705,7 +1708,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket) return 100; - if (Left.is(tok::l_paren) && Left.Previous && Left.Previous->is(tok::kw_if)) + if (Left.is(tok::l_paren) && Left.Previous && + Left.Previous->isOneOf(tok::kw_if, tok::kw_for)) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -2104,7 +2108,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) return Style.BreakBeforeBraces == FormatStyle::BS_Allman || - Style.BreakBeforeBraces == FormatStyle::BS_GNU; + Style.BreakBeforeBraces == FormatStyle::BS_GNU || + (Style.BreakBeforeBraces == FormatStyle::BS_Mozilla && + Line.startsWith(tok::kw_enum)); if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) && Right.is(TT_SelectorName)) return true; @@ -2205,6 +2211,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) return false; + if (Right.is(tok::r_square) && Right.MatchingParen && + Right.MatchingParen->is(TT_LambdaLSquare)) + return false; // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. @@ -2265,7 +2274,8 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore - << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type + << " C=" << Tok->CanBreakBefore + << " T=" << getTokenTypeName(Tok->Type) << " S=" << Tok->SpacesRequiredBefore << " B=" << Tok->BlockParameterCount << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index c58e6bccd9bc..97fd98ecb947 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -269,7 +269,14 @@ void UnwrappedLineParser::parseFile() { void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { bool SwitchLabelEncountered = false; do { - switch (FormatTok->Tok.getKind()) { + tok::TokenKind kind = FormatTok->Tok.getKind(); + if (FormatTok->Type == TT_MacroBlockBegin) { + kind = tok::l_brace; + } else if (FormatTok->Type == TT_MacroBlockEnd) { + kind = tok::r_brace; + } + + switch (kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -393,10 +400,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, bool MunchSemi) { - assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected"); + assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && + "'{' or macro block token expected"); + const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); + unsigned InitialLevel = Line->Level; nextToken(); + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + addUnwrappedLine(); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, @@ -405,12 +418,17 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, ++Line->Level; parseLevel(/*HasOpeningBrace=*/true); - if (!FormatTok->Tok.is(tok::r_brace)) { + if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) + : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; return; } nextToken(); // Munch the closing brace. + + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + if (MunchSemi && FormatTok->Tok.is(tok::semi)) nextToken(); Line->Level = InitialLevel; @@ -439,6 +457,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style, switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: return InitialToken.isOneOf(tok::kw_namespace, tok::kw_class); + case FormatStyle::BS_Mozilla: + return InitialToken.isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union); case FormatStyle::BS_Allman: case FormatStyle::BS_GNU: return true; @@ -757,6 +777,11 @@ void UnwrappedLineParser::parseStructuralElement() { parseForOrWhileLoop(); return; } + if (FormatTok->is(TT_MacroBlockBegin)) { + parseBlock(/*MustBeDeclaration=*/false, /*AddLevel=*/true, + /*MunchSemi=*/false); + return; + } if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(Keywords.kw_import)) { parseJavaScriptEs6ImportExport(); @@ -860,6 +885,11 @@ void UnwrappedLineParser::parseStructuralElement() { parseTryCatch(); return; case tok::identifier: { + if (FormatTok->is(TT_MacroBlockEnd)) { + addUnwrappedLine(); + return; + } + // Parse function literal unless 'function' is the first token in a line // in which case this should be treated as a free-standing function. if (Style.Language == FormatStyle::LK_JavaScript && @@ -872,7 +902,7 @@ void UnwrappedLineParser::parseStructuralElement() { FormatTok->is(Keywords.kw_interface)) { parseRecord(); addUnwrappedLine(); - break; + return; } StringRef Text = FormatTok->TokenText; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 01c56bdc4df9..57c97d0c312f 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -353,6 +353,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Translate global code completions into cached completions. llvm::DenseMap<CanQualType, unsigned> CompletionTypes; + CodeCompletionContext CCContext(CodeCompletionContext::CCC_TopLevel); for (Result &R : Results) { switch (R.Kind) { @@ -360,7 +361,7 @@ void ASTUnit::CacheCodeCompletionResults() { bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = getDeclShowContexts( R.Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier); @@ -423,7 +424,7 @@ void ASTUnit::CacheCodeCompletionResults() { // nested-name-specifier completion. R.StartsNestedNameSpecifier = true; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; @@ -444,7 +445,7 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Macro: { CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = (1LL << CodeCompletionContext::CCC_TopLevel) diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 6b0fed676182..ff041a8ec431 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -405,7 +405,7 @@ void CompilerInstance::createPCHExternalASTSource( } IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( - StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + StringRef Path, StringRef Sysroot, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerOperations &PCHContainerOps, void *DeserializationListener, bool OwnDeserializationListener, @@ -413,7 +413,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader( - PP, Context, PCHContainerOps, Sysroot.empty() ? "" : Sysroot.c_str(), + PP, Context, PCHContainerOps, Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); @@ -497,12 +497,14 @@ void CompilerInstance::createCodeCompletionConsumer() { } void CompilerInstance::createFrontendTimer() { - FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); + FrontendTimerGroup.reset(new llvm::TimerGroup("Clang front-end time report")); + FrontendTimer.reset( + new llvm::Timer("Clang front-end timer", *FrontendTimerGroup)); } CodeCompleteConsumer * CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, - const std::string &Filename, + StringRef Filename, unsigned Line, unsigned Column, const CodeCompleteOptions &Opts, @@ -1237,13 +1239,18 @@ void CompilerInstance::createModuleManager() { HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); std::string Sysroot = HSOpts.Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + std::unique_ptr<llvm::Timer> ReadTimer; + if (FrontendTimerGroup) + ReadTimer = llvm::make_unique<llvm::Timer>("Reading modules", + *FrontendTimerGroup); ModuleManager = new ASTReader( getPreprocessor(), *Context, *getPCHContainerOperations(), Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, /*AllowASTWithCompilerErrors=*/false, /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, - getFrontendOpts().UseGlobalModuleIndex); + getFrontendOpts().UseGlobalModuleIndex, + std::move(ReadTimer)); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); @@ -1259,6 +1266,11 @@ void CompilerInstance::createModuleManager() { } bool CompilerInstance::loadModuleFile(StringRef FileName) { + llvm::Timer Timer; + if (FrontendTimerGroup) + Timer.init("Preloading " + FileName.str(), *FrontendTimerGroup); + llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); + // Helper to recursively read the module names for all modules we're adding. // We mark these as known and redirect any attempt to load that module to // the files we were handed. @@ -1418,6 +1430,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*ModuleManager); + llvm::Timer Timer; + if (FrontendTimerGroup) + Timer.init("Loading " + ModuleFileName, *FrontendTimerGroup); + llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); + // Try to load the module file. unsigned ARRFlags = Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index dd664ca652f0..6f13faf573be 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -508,6 +508,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); + Opts.PrepareForLTO = Args.hasArg(OPT_flto); + Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive); @@ -555,6 +557,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_fsanitize_coverage_8bit_counters); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); + Opts.SanitizeMemoryUseAfterDtor = + Args.hasArg(OPT_fsanitize_memory_use_after_dtor); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); @@ -1647,6 +1651,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Check if -fopenmp is specified. Opts.OpenMP = Args.hasArg(options::OPT_fopenmp); + Opts.OpenMPUseTLS = + Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 4a8a8a029e79..2afd23fcb9e8 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" @@ -61,9 +62,25 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, } // We expect to get back exactly one command job, if we didn't something - // failed. + // failed. CUDA compilation is an exception as it creates multiple jobs. If + // that's the case, we proceed with the first job. If caller needs particular + // CUDA job, it should be controlled via --cuda-{host|device}-only option + // passed to the driver. const driver::JobList &Jobs = C->getJobs(); - if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { + bool CudaCompilation = false; + if (Jobs.size() > 1) { + for (auto &A : C->getActions()){ + // On MacOSX real actions may end up being wrapped in BindArchAction + if (isa<driver::BindArchAction>(A)) + A = *A->begin(); + if (isa<driver::CudaDeviceAction>(A)) { + CudaCompilation = true; + break; + } + } + } + if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) || + (Jobs.size() > 1 && !CudaCompilation)) { SmallString<256> Msg; llvm::raw_svector_ostream OS(Msg); Jobs.Print(OS, "; ", true); diff --git a/lib/Frontend/PCHContainerOperations.cpp b/lib/Frontend/PCHContainerOperations.cpp index fd3278b3b145..c749bb5c8db4 100644 --- a/lib/Frontend/PCHContainerOperations.cpp +++ b/lib/Frontend/PCHContainerOperations.cpp @@ -18,8 +18,6 @@ #include "clang/Lex/ModuleLoader.h" using namespace clang; -PCHContainerOperations::~PCHContainerOperations() {} - namespace { /// \brief A PCHContainerGenerator that writes out the PCH to a flat file. diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h index 7ba311ea4b94..24b3eae8bf86 100644 --- a/lib/Headers/Intrin.h +++ b/lib/Headers/Intrin.h @@ -513,47 +513,40 @@ _BitScanReverse(unsigned long *_Index, unsigned long _Mask) { return 1; } static __inline__ unsigned short __DEFAULT_FN_ATTRS -__popcnt16(unsigned short value) { - return __builtin_popcount((int)value); +__popcnt16(unsigned short _Value) { + return __builtin_popcount((int)_Value); } static __inline__ unsigned int __DEFAULT_FN_ATTRS -__popcnt(unsigned int value) { - return __builtin_popcount(value); +__popcnt(unsigned int _Value) { + return __builtin_popcount(_Value); } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittest(long const *a, long b) { - return (*a >> b) & 1; +_bittest(long const *_BitBase, long _BitPos) { + return (*_BitBase >> _BitPos) & 1; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandcomplement(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a ^ (1 << b); - return x; +_bittestandcomplement(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase ^ (1 << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandreset(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a & ~(1 << b); - return x; +_bittestandreset(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase & ~(1 << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandset(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a | (1 << b); - return x; +_bittestandset(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase | (1 << _BitPos); + return _Res; } -#if defined(__i386__) || defined(__x86_64__) static __inline__ unsigned char __DEFAULT_FN_ATTRS -_interlockedbittestandset(long volatile *__BitBase, long __BitPos) { - unsigned char __Res; - __asm__ ("xor %0, %0\n" - "lock bts %2, %1\n" - "setc %0\n" - : "=r" (__Res), "+m"(*__BitBase) - : "Ir"(__BitPos)); - return __Res; +_interlockedbittestandset(long volatile *_BitBase, long _BitPos) { + long _PrevVal = __atomic_fetch_or(_BitBase, 1l << _BitPos, __ATOMIC_SEQ_CST); + return (_PrevVal >> _BitPos) & 1; } -#endif #ifdef __x86_64__ static __inline__ unsigned char __DEFAULT_FN_ATTRS _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask) { @@ -571,40 +564,36 @@ _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask) { } static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS - __popcnt64(unsigned __int64 value) { - return __builtin_popcountll(value); +__popcnt64(unsigned __int64 _Value) { + return __builtin_popcountll(_Value); } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittest64(__int64 const *a, __int64 b) { - return (*a >> b) & 1; +_bittest64(__int64 const *_BitBase, __int64 _BitPos) { + return (*_BitBase >> _BitPos) & 1; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandcomplement64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a ^ (1ll << b); - return x; +_bittestandcomplement64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase ^ (1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandreset64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a & ~(1ll << b); - return x; +_bittestandreset64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase & ~(1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandset64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a | (1ll << b); - return x; +_bittestandset64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase | (1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_interlockedbittestandset64(__int64 volatile *__BitBase, __int64 __BitPos) { - unsigned char __Res; - __asm__ ("xor %0, %0\n" - "lock bts %2, %1\n" - "setc %0\n" - : "=r" (__Res), "+m"(*__BitBase) - : "Ir"(__BitPos)); - return __Res; +_interlockedbittestandset64(__int64 volatile *_BitBase, __int64 _BitPos) { + long long _PrevVal = + __atomic_fetch_or(_BitBase, 1ll << _BitPos, __ATOMIC_SEQ_CST); + return (_PrevVal >> _BitPos) & 1; } #endif /*----------------------------------------------------------------------------*\ @@ -612,16 +601,16 @@ _interlockedbittestandset64(__int64 volatile *__BitBase, __int64 __BitPos) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchangeAdd8(char volatile *_Addend, char _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchangeAdd16(short volatile *_Addend, short _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -629,20 +618,20 @@ _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchangeSub8(char volatile *_Subend, char _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchangeSub16(short volatile *_Subend, short _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchangeSub(long volatile *_Subend, long _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -650,12 +639,12 @@ _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) { \*----------------------------------------------------------------------------*/ static __inline__ short __DEFAULT_FN_ATTRS _InterlockedIncrement16(short volatile *_Value) { - return __atomic_add_fetch(_Value, 1, 0); + return __atomic_add_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedIncrement64(__int64 volatile *_Value) { - return __atomic_add_fetch(_Value, 1, 0); + return __atomic_add_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -663,12 +652,12 @@ _InterlockedIncrement64(__int64 volatile *_Value) { \*----------------------------------------------------------------------------*/ static __inline__ short __DEFAULT_FN_ATTRS _InterlockedDecrement16(short volatile *_Value) { - return __atomic_sub_fetch(_Value, 1, 0); + return __atomic_sub_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedDecrement64(__int64 volatile *_Value) { - return __atomic_sub_fetch(_Value, 1, 0); + return __atomic_sub_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -676,20 +665,20 @@ _InterlockedDecrement64(__int64 volatile *_Value) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedAnd8(char volatile *_Value, char _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedAnd16(short volatile *_Value, short _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedAnd(long volatile *_Value, long _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -697,20 +686,20 @@ _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedOr8(char volatile *_Value, char _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedOr16(short volatile *_Value, short _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedOr(long volatile *_Value, long _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -718,20 +707,20 @@ _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedXor8(char volatile *_Value, char _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedXor16(short volatile *_Value, short _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedXor(long volatile *_Value, long _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -739,18 +728,18 @@ _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchange8(char volatile *_Target, char _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchange16(short volatile *_Target, short _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } #endif @@ -760,19 +749,22 @@ _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) { static __inline__ char __DEFAULT_FN_ATTRS _InterlockedCompareExchange8(char volatile *_Destination, char _Exchange, char _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedCompareExchange16(short volatile *_Destination, short _Exchange, short _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } /*----------------------------------------------------------------------------*\ diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h index 2c80e24db335..f52bcbc5b4a8 100644 --- a/lib/Headers/altivec.h +++ b/lib/Headers/altivec.h @@ -48,7 +48,8 @@ static vector bool char __ATTRS_o_ai vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c); -static vector short __ATTRS_o_ai vec_perm(vector short __a, vector short __b, +static vector short __ATTRS_o_ai vec_perm(vector signed short __a, + vector signed short __b, vector unsigned char __c); static vector unsigned short __ATTRS_o_ai vec_perm(vector unsigned short __a, @@ -62,7 +63,8 @@ static vector bool short __ATTRS_o_ai vec_perm(vector bool short __a, static vector pixel __ATTRS_o_ai vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c); -static vector int __ATTRS_o_ai vec_perm(vector int __a, vector int __b, +static vector int __ATTRS_o_ai vec_perm(vector signed int __a, + vector signed int __b, vector unsigned char __c); static vector unsigned int __ATTRS_o_ai vec_perm(vector unsigned int __a, @@ -77,14 +79,18 @@ static vector float __ATTRS_o_ai vec_perm(vector float __a, vector float __b, vector unsigned char __c); #ifdef __VSX__ -static vector long long __ATTRS_o_ai vec_perm(vector long long __a, - vector long long __b, +static vector long long __ATTRS_o_ai vec_perm(vector signed long long __a, + vector signed long long __b, vector unsigned char __c); static vector unsigned long long __ATTRS_o_ai vec_perm(vector unsigned long long __a, vector unsigned long long __b, vector unsigned char __c); +static vector bool long long __ATTRS_o_ai +vec_perm(vector bool long long __a, vector bool long long __b, + vector unsigned char __c); + static vector double __ATTRS_o_ai vec_perm(vector double __a, vector double __b, vector unsigned char __c); #endif @@ -1735,6 +1741,48 @@ static vector bool long long __ATTRS_o_ai vec_cmplt(vector unsigned long long __a, vector unsigned long long __b) { return vec_cmpgt(__b, __a); } + +/* vec_cntlz */ + +static vector signed char __ATTRS_o_ai vec_cntlz(vector signed char __a) { + return __builtin_altivec_vclzb(__a); +} +static vector unsigned char __ATTRS_o_ai vec_cntlz(vector unsigned char __a) { + return __builtin_altivec_vclzb(__a); +} +static vector signed short __ATTRS_o_ai vec_cntlz(vector signed short __a) { + return __builtin_altivec_vclzh(__a); +} +static vector unsigned short __ATTRS_o_ai vec_cntlz(vector unsigned short __a) { + return __builtin_altivec_vclzh(__a); +} +static vector signed int __ATTRS_o_ai vec_cntlz(vector signed int __a) { + return __builtin_altivec_vclzw(__a); +} +static vector unsigned int __ATTRS_o_ai vec_cntlz(vector unsigned int __a) { + return __builtin_altivec_vclzw(__a); +} +static vector signed long long __ATTRS_o_ai +vec_cntlz(vector signed long long __a) { + return __builtin_altivec_vclzd(__a); +} +static vector unsigned long long __ATTRS_o_ai +vec_cntlz(vector unsigned long long __a) { + return __builtin_altivec_vclzd(__a); +} +#endif + +/* vec_cpsgn */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai vec_cpsgn(vector float __a, vector float __b) { + return __builtin_vsx_xvcpsgnsp(__a, __b); +} + +static vector double __ATTRS_o_ai vec_cpsgn(vector double __a, + vector double __b) { + return __builtin_vsx_xvcpsgndp(__a, __b); +} #endif /* vec_ctf */ @@ -1790,14 +1838,58 @@ vec_vctuxs(vector float __a, int __b) { } /* vec_div */ + +/* Integer vector divides (vectors are scalarized, elements divided + and the vectors reassembled). +*/ +static vector signed char __ATTRS_o_ai vec_div(vector signed char __a, + vector signed char __b) { + return __a / __b; +} + +static vector unsigned char __ATTRS_o_ai vec_div(vector unsigned char __a, + vector unsigned char __b) { + return __a / __b; +} + +static vector signed short __ATTRS_o_ai vec_div(vector signed short __a, + vector signed short __b) { + return __a / __b; +} + +static vector unsigned short __ATTRS_o_ai vec_div(vector unsigned short __a, + vector unsigned short __b) { + return __a / __b; +} + +static vector signed int __ATTRS_o_ai vec_div(vector signed int __a, + vector signed int __b) { + return __a / __b; +} + +static vector unsigned int __ATTRS_o_ai vec_div(vector unsigned int __a, + vector unsigned int __b) { + return __a / __b; +} + #ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_div(vector signed long long __a, vector signed long long __b) { + return __a / __b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_div(vector unsigned long long __a, vector unsigned long long __b) { + return __a / __b; +} + static vector float __ATTRS_o_ai vec_div(vector float __a, vector float __b) { - return __builtin_vsx_xvdivsp(__a, __b); + return __a / __b; } static vector double __ATTRS_o_ai vec_div(vector double __a, vector double __b) { - return __builtin_vsx_xvdivdp(__a, __b); + return __a / __b; } #endif @@ -1841,6 +1933,189 @@ vec_dstt(const void *__a, int __b, int __c) { __builtin_altivec_dstt(__a, __b, __c); } +/* vec_eqv */ + +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_eqv(vector signed char __a, + vector signed char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed char __ATTRS_o_ai vec_eqv(vector bool char __a, + vector signed char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed char __ATTRS_o_ai vec_eqv(vector signed char __a, + vector bool char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector unsigned char __a, + vector unsigned char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector bool char __a, + vector unsigned char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector unsigned char __a, + vector bool char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector signed short __a, + vector signed short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector bool short __a, + vector signed short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector signed short __a, + vector bool short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector unsigned short __a, + vector unsigned short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector bool short __a, + vector unsigned short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector unsigned short __a, + vector bool short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector signed int __a, + vector signed int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector bool int __a, + vector signed int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector signed int __a, + vector bool int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector unsigned int __a, + vector unsigned int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector bool int __a, + vector unsigned int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector unsigned int __a, + vector bool int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector signed long long __a, vector signed long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector bool long long __a, vector signed long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector signed long long __a, vector bool long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector unsigned long long __a, vector unsigned long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector bool long long __a, vector unsigned long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector unsigned long long __a, vector bool long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector float __a, vector float __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector bool int __a, + vector float __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector float __a, + vector bool int __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector double __a, + vector double __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector bool long long __a, + vector double __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector double __a, + vector bool long long __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} +#endif + /* vec_expte */ static vector float __attribute__((__always_inline__)) @@ -1857,10 +2132,19 @@ vec_vexptefp(vector float __a) { /* vec_floor */ -static vector float __attribute__((__always_inline__)) -vec_floor(vector float __a) { +static vector float __ATTRS_o_ai vec_floor(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspim(__a); +#else return __builtin_altivec_vrfim(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_floor(vector double __a) { + return __builtin_vsx_xvrdpim(__a); } +#endif /* vec_vrfim */ @@ -2532,10 +2816,21 @@ static vector unsigned char __ATTRS_o_ai vec_lvsr(int __a, const float *__b) { /* vec_madd */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_madd(vector float __a, vector float __b, vector float __c) { +#ifdef __VSX__ + return __builtin_vsx_xvmaddasp(__a, __b, __c); +#else return __builtin_altivec_vmaddfp(__a, __b, __c); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_madd(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvmaddadp(__a, __b, __c); } +#endif /* vec_vmaddfp */ @@ -2559,6 +2854,20 @@ vec_vmhaddshs(vector signed short __a, vector signed short __b, return __builtin_altivec_vmhaddshs(__a, __b, __c); } +/* vec_msub */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai +vec_msub(vector float __a, vector float __b, vector float __c) { + return __builtin_vsx_xvmsubasp(__a, __b, __c); +} + +static vector double __ATTRS_o_ai +vec_msub(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvmsubadp(__a, __b, __c); +} +#endif + /* vec_max */ static vector signed char __ATTRS_o_ai vec_max(vector signed char __a, @@ -2893,6 +3202,86 @@ static vector float __ATTRS_o_ai vec_mergeh(vector float __a, 0x14, 0x15, 0x16, 0x17)); } +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector signed long long __a, vector signed long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector signed long long __a, vector bool long long __b) { + return vec_perm(__a, (vector signed long long)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector bool long long __a, vector signed long long __b) { + return vec_perm((vector signed long long)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector unsigned long long __a, vector unsigned long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector unsigned long long __a, vector bool long long __b) { + return vec_perm(__a, (vector unsigned long long)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector bool long long __a, vector unsigned long long __b) { + return vec_perm((vector unsigned long long)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector double __a, + vector double __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector double __a, + vector bool long long __b) { + return vec_perm(__a, (vector double)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector bool long long __a, + vector double __b) { + return vec_perm((vector double)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +#endif + /* vec_vmrghb */ #define __builtin_altivec_vmrghb vec_vmrghb @@ -3081,6 +3470,81 @@ static vector float __ATTRS_o_ai vec_mergel(vector float __a, 0x1C, 0x1D, 0x1E, 0x1F)); } +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mergel(vector signed long long __a, vector signed long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector signed long long __ATTRS_o_ai +vec_mergel(vector signed long long __a, vector bool long long __b) { + return vec_perm(__a, (vector signed long long)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector signed long long __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector signed long long __b) { + return vec_perm((vector signed long long)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector unsigned long long __a, vector unsigned long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector unsigned long long __a, vector bool long long __b) { + return vec_perm(__a, (vector unsigned long long)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector unsigned long long __b) { + return vec_perm((vector unsigned long long)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector double __a, vector double __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector double __a, vector bool long long __b) { + return vec_perm(__a, (vector double)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector double __b) { + return vec_perm((vector double)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +#endif + /* vec_vmrglb */ #define __builtin_altivec_vmrglb vec_vmrglb @@ -3677,6 +4141,65 @@ static void __ATTRS_o_ai vec_mtvscr(vector float __a) { __builtin_altivec_mtvscr((vector int)__a); } +/* vec_mul */ + +/* Integer vector multiplication will involve multiplication of the odd/even + elements separately, then truncating the results and moving to the + result vector. +*/ +static vector signed char __ATTRS_o_ai vec_mul(vector signed char __a, + vector signed char __b) { + return __a * __b; +} + +static vector unsigned char __ATTRS_o_ai vec_mul(vector unsigned char __a, + vector unsigned char __b) { + return __a * __b; +} + +static vector signed short __ATTRS_o_ai vec_mul(vector signed short __a, + vector signed short __b) { + return __a * __b; +} + +static vector unsigned short __ATTRS_o_ai vec_mul(vector unsigned short __a, + vector unsigned short __b) { + return __a * __b; +} + +static vector signed int __ATTRS_o_ai vec_mul(vector signed int __a, + vector signed int __b) { + return __a * __b; +} + +static vector unsigned int __ATTRS_o_ai vec_mul(vector unsigned int __a, + vector unsigned int __b) { + return __a * __b; +} + +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mul(vector signed long long __a, vector signed long long __b) { + return __a * __b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_mul(vector unsigned long long __a, vector unsigned long long __b) { + return __a * __b; +} +#endif + +static vector float __ATTRS_o_ai vec_mul(vector float __a, vector float __b) { + return __a * __b; +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_mul(vector double __a, vector double __b) { + return __a * __b; +} +#endif + /* The vmulos* and vmules* instructions have a big endian bias, so we must reverse the meaning of "even" and "odd" for little endian. */ @@ -3882,12 +4405,165 @@ vec_vmulouh(vector unsigned short __a, vector unsigned short __b) { #endif } +/* vec_nand */ + +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_nand(vector signed char __a, + vector signed char __b) { + return ~(__a & __b); +} + +static vector signed char __ATTRS_o_ai vec_nand(vector signed char __a, + vector bool char __b) { + return ~(__a & __b); +} + +static vector signed char __ATTRS_o_ai vec_nand(vector bool char __a, + vector signed char __b) { + return ~(__a & __b); +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector unsigned char __a, + vector unsigned char __b) { + return ~(__a & __b); +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector unsigned char __a, + vector bool char __b) { + return ~(__a & __b); + +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector bool char __a, + vector unsigned char __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector signed short __a, + vector signed short __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector signed short __a, + vector bool short __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector bool short __a, + vector signed short __b) { + return ~(__a & __b); +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector unsigned short __a, + vector unsigned short __b) { + return ~(__a & __b); +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector unsigned short __a, + vector bool short __b) { + return ~(__a & __b); + +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector bool short __a, + vector unsigned short __b) { + return ~(__a & __b); + +} + +static vector signed int __ATTRS_o_ai vec_nand(vector signed int __a, + vector signed int __b) { + return ~(__a & __b); +} + +static vector signed int __ATTRS_o_ai vec_nand(vector signed int __a, + vector bool int __b) { + return ~(__a & __b); +} + +static vector signed int __ATTRS_o_ai vec_nand(vector bool int __a, + vector signed int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector unsigned int __a, + vector unsigned int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector unsigned int __a, + vector bool int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector bool int __a, + vector unsigned int __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector signed long long __a, vector signed long long __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector signed long long __a, vector bool long long __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector bool long long __a, vector signed long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector unsigned long long __a, vector unsigned long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector unsigned long long __a, vector bool long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector bool long long __a, vector unsigned long long __b) { + return ~(__a & __b); +} + +#endif + +/* vec_nmadd */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai +vec_nmadd(vector float __a, vector float __b, vector float __c) { + return __builtin_vsx_xvnmaddasp(__a, __b, __c); +} + +static vector double __ATTRS_o_ai +vec_nmadd(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvnmaddadp(__a, __b, __c); +} +#endif + /* vec_nmsub */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_nmsub(vector float __a, vector float __b, vector float __c) { +#ifdef __VSX__ + return __builtin_vsx_xvnmsubasp(__a, __b, __c); +#else return __builtin_altivec_vnmsubfp(__a, __b, __c); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_nmsub(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvnmsubadp(__a, __b, __c); } +#endif /* vec_vnmsubfp */ @@ -3949,6 +4625,15 @@ static vector float __ATTRS_o_ai vec_nor(vector float __a, vector float __b) { return (vector float)__res; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_nor(vector double __a, vector double __b) { + vector unsigned long long __res = + ~((vector unsigned long long)__a | (vector unsigned long long)__b); + return (vector double)__res; +} +#endif + /* vec_vnor */ static vector signed char __ATTRS_o_ai vec_vnor(vector signed char __a, @@ -4141,6 +4826,22 @@ static vector float __ATTRS_o_ai vec_or(vector float __a, vector bool int __b) { } #ifdef __VSX__ +static vector double __ATTRS_o_ai vec_or(vector bool long long __a, + vector double __b) { + return (vector unsigned long long)__a | (vector unsigned long long)__b; +} + +static vector double __ATTRS_o_ai vec_or(vector double __a, + vector bool long long __b) { + return (vector unsigned long long)__a | (vector unsigned long long)__b; +} + +static vector double __ATTRS_o_ai vec_or(vector double __a, vector double __b) { + vector unsigned long long __res = + (vector unsigned long long)__a | (vector unsigned long long)__b; + return (vector double)__res; +} + static vector signed long long __ATTRS_o_ai vec_or(vector signed long long __a, vector signed long long __b) { return __a | __b; @@ -4177,6 +4878,128 @@ static vector bool long long __ATTRS_o_ai vec_or(vector bool long long __a, } #endif +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_orc(vector signed char __a, + vector signed char __b) { + return __a | ~__b; +} + +static vector signed char __ATTRS_o_ai vec_orc(vector signed char __a, + vector bool char __b) { + return __a | ~__b; +} + +static vector signed char __ATTRS_o_ai vec_orc(vector bool char __a, + vector signed char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector unsigned char __a, + vector unsigned char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector unsigned char __a, + vector bool char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector bool char __a, + vector unsigned char __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector signed short __a, + vector signed short __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector signed short __a, + vector bool short __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector bool short __a, + vector signed short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai vec_orc(vector unsigned short __a, + vector unsigned short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai vec_orc(vector unsigned short __a, + vector bool short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai +vec_orc(vector bool short __a, vector unsigned short __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector signed int __a, + vector signed int __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector signed int __a, + vector bool int __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector bool int __a, + vector signed int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector unsigned int __a, + vector unsigned int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector unsigned int __a, + vector bool int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector bool int __a, + vector unsigned int __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai +vec_orc(vector signed long long __a, vector signed long long __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai vec_orc(vector signed long long __a, + vector bool long long __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai +vec_orc(vector bool long long __a, vector signed long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector unsigned long long __a, vector unsigned long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector unsigned long long __a, vector bool long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector bool long long __a, vector unsigned long long __b) { + return __a | ~__b; +} +#endif + /* vec_vor */ static vector signed char __ATTRS_o_ai vec_vor(vector signed char __a, @@ -4431,6 +5254,53 @@ static vector bool short __ATTRS_o_ai vec_pack(vector bool int __a, #endif } +#ifdef __VSX__ +static vector signed int __ATTRS_o_ai vec_pack(vector signed long long __a, + vector signed long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector signed int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector signed int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} +static vector unsigned int __ATTRS_o_ai +vec_pack(vector unsigned long long __a, vector unsigned long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector unsigned int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector unsigned int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} + +static vector bool int __ATTRS_o_ai vec_pack(vector bool long long __a, + vector bool long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector bool int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector bool int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} + +#endif + /* vec_vpkuhum */ #define __builtin_altivec_vpkuhum vec_vpkuhum @@ -4895,17 +5765,18 @@ static vector bool char __ATTRS_o_ai vec_perm(vector bool char __a, #endif } -static vector short __ATTRS_o_ai vec_perm(vector short __a, vector short __b, +static vector short __ATTRS_o_ai vec_perm(vector signed short __a, + vector signed short __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector short)__builtin_altivec_vperm_4si((vector int)__b, - (vector int)__a, __d); + return (vector signed short)__builtin_altivec_vperm_4si((vector int)__b, + (vector int)__a, __d); #else - return (vector short)__builtin_altivec_vperm_4si((vector int)__a, - (vector int)__b, __c); + return (vector signed short)__builtin_altivec_vperm_4si((vector int)__a, + (vector int)__b, __c); #endif } @@ -4953,15 +5824,16 @@ static vector pixel __ATTRS_o_ai vec_perm(vector pixel __a, vector pixel __b, #endif } -static vector int __ATTRS_o_ai vec_perm(vector int __a, vector int __b, +static vector int __ATTRS_o_ai vec_perm(vector signed int __a, + vector signed int __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector int)__builtin_altivec_vperm_4si(__b, __a, __d); + return (vector signed int)__builtin_altivec_vperm_4si(__b, __a, __d); #else - return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c); + return (vector signed int)__builtin_altivec_vperm_4si(__a, __b, __c); #endif } @@ -5010,16 +5882,18 @@ static vector float __ATTRS_o_ai vec_perm(vector float __a, vector float __b, } #ifdef __VSX__ -static vector long long __ATTRS_o_ai vec_perm(vector long long __a, - vector long long __b, +static vector long long __ATTRS_o_ai vec_perm(vector signed long long __a, + vector signed long long __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector long long)__builtin_altivec_vperm_4si(__b, __a, __d); + return (vector signed long long)__builtin_altivec_vperm_4si( + (vector int)__b, (vector int)__a, __d); #else - return (vector long long)__builtin_altivec_vperm_4si(__a, __b, __c); + return (vector signed long long)__builtin_altivec_vperm_4si( + (vector int)__a, (vector int)__b, __c); #endif } @@ -5038,6 +5912,21 @@ vec_perm(vector unsigned long long __a, vector unsigned long long __b, #endif } +static vector bool long long __ATTRS_o_ai +vec_perm(vector bool long long __a, vector bool long long __b, + vector unsigned char __c) { +#ifdef __LITTLE_ENDIAN__ + vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255}; + __d = vec_xor(__c, __d); + return (vector bool long long)__builtin_altivec_vperm_4si( + (vector int)__b, (vector int)__a, __d); +#else + return (vector bool long long)__builtin_altivec_vperm_4si( + (vector int)__a, (vector int)__b, __c); +#endif +} + static vector double __ATTRS_o_ai vec_perm(vector double __a, vector double __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ @@ -5139,10 +6028,20 @@ static vector double __ATTRS_o_ai vec_vperm(vector double __a, /* vec_re */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_re(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvresp(__a); +#else return __builtin_altivec_vrefp(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_re(vector double __a) { + return __builtin_vsx_xvredp(__a); } +#endif /* vec_vrefp */ @@ -5232,10 +6131,41 @@ static vector unsigned int __ATTRS_o_ai vec_vrlw(vector unsigned int __a, /* vec_round */ -static vector float __attribute__((__always_inline__)) -vec_round(vector float __a) { +static vector float __ATTRS_o_ai vec_round(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspi(__a); +#else return __builtin_altivec_vrfin(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_round(vector double __a) { + return __builtin_vsx_xvrdpi(__a); +} + +/* vec_rint */ + +static vector float __ATTRS_o_ai +vec_rint(vector float __a) { + return __builtin_vsx_xvrspic(__a); +} + +static vector double __ATTRS_o_ai +vec_rint(vector double __a) { + return __builtin_vsx_xvrdpic(__a); +} + +/* vec_nearbyint */ + +static vector float __ATTRS_o_ai vec_nearbyint(vector float __a) { + return __builtin_vsx_xvrspi(__a); +} + +static vector double __ATTRS_o_ai vec_nearbyint(vector double __a) { + return __builtin_vsx_xvrdpi(__a); } +#endif /* vec_vrfin */ @@ -5244,12 +6174,34 @@ vec_vrfin(vector float __a) { return __builtin_altivec_vrfin(__a); } +/* vec_sqrt */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai vec_sqrt(vector float __a) { + return __builtin_vsx_xvsqrtsp(__a); +} + +static vector double __ATTRS_o_ai vec_sqrt(vector double __a) { + return __builtin_vsx_xvsqrtdp(__a); +} +#endif + /* vec_rsqrte */ -static __vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_rsqrte(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrsqrtesp(__a); +#else return __builtin_altivec_vrsqrtefp(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_rsqrte(vector double __a) { + return __builtin_vsx_xvrsqrtedp(__a); } +#endif /* vec_vrsqrtefp */ @@ -5381,6 +6333,22 @@ static vector float __ATTRS_o_ai vec_sel(vector float __a, vector float __b, return (vector float)__res; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_sel(vector double __a, vector double __b, + vector bool long long __c) { + vector long long __res = ((vector long long)__a & ~(vector long long)__c) | + ((vector long long)__b & (vector long long)__c); + return (vector double)__res; +} + +static vector double __ATTRS_o_ai vec_sel(vector double __a, vector double __b, + vector unsigned long long __c) { + vector long long __res = ((vector long long)__a & ~(vector long long)__c) | + ((vector long long)__b & (vector long long)__c); + return (vector double)__res; +} +#endif + /* vec_vsel */ static vector signed char __ATTRS_o_ai vec_vsel(vector signed char __a, @@ -5593,78 +6561,121 @@ static vector unsigned int __ATTRS_o_ai vec_vslw(vector unsigned int __a, static vector signed char __ATTRS_o_ai vec_sld(vector signed char __a, vector signed char __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned char __ATTRS_o_ai vec_sld(vector unsigned char __a, vector unsigned char __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } -static vector short __ATTRS_o_ai vec_sld(vector short __a, vector short __b, - unsigned char __c) { +static vector bool char __ATTRS_o_ai vec_sld(vector bool char __a, + vector bool char __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector signed short __ATTRS_o_ai vec_sld(vector signed short __a, + vector signed short __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned short __ATTRS_o_ai vec_sld(vector unsigned short __a, vector unsigned short __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector bool short __ATTRS_o_ai vec_sld(vector bool short __a, + vector bool short __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector pixel __ATTRS_o_ai vec_sld(vector pixel __a, vector pixel __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } -static vector int __ATTRS_o_ai vec_sld(vector int __a, vector int __b, - unsigned char __c) { +static vector signed int __ATTRS_o_ai vec_sld(vector signed int __a, + vector signed int __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned int __ATTRS_o_ai vec_sld(vector unsigned int __a, vector unsigned int __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector bool int __ATTRS_o_ai vec_sld(vector bool int __a, + vector bool int __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector float __ATTRS_o_ai vec_sld(vector float __a, vector float __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } /* vec_vsldoi */ @@ -6273,91 +7284,131 @@ static vector float __ATTRS_o_ai vec_vslo(vector float __a, /* vec_splat */ static vector signed char __ATTRS_o_ai vec_splat(vector signed char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } static vector unsigned char __ATTRS_o_ai vec_splat(vector unsigned char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } static vector bool char __ATTRS_o_ai vec_splat(vector bool char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } -static vector short __ATTRS_o_ai vec_splat(vector short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; +static vector signed short __ATTRS_o_ai vec_splat(vector signed short __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector unsigned short __ATTRS_o_ai vec_splat(vector unsigned short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector bool short __ATTRS_o_ai vec_splat(vector bool short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector pixel __ATTRS_o_ai vec_splat(vector pixel __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } -static vector int __ATTRS_o_ai vec_splat(vector int __a, unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; +static vector signed int __ATTRS_o_ai vec_splat(vector signed int __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector unsigned int __ATTRS_o_ai vec_splat(vector unsigned int __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector bool int __ATTRS_o_ai vec_splat(vector bool int __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector float __ATTRS_o_ai vec_splat(vector float __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_splat(vector double __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector bool long long __ATTRS_o_ai vec_splat(vector bool long long __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector signed long long __ATTRS_o_ai +vec_splat(vector signed long long __a, unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector unsigned long long __ATTRS_o_ai +vec_splat(vector unsigned long long __a, unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +#endif + /* vec_vspltb */ #define __builtin_altivec_vspltb vec_vspltb @@ -6529,7 +7580,8 @@ static vector unsigned int __ATTRS_o_ai vec_splat_u32(signed char __a) { static vector signed char __ATTRS_o_ai vec_sr(vector signed char __a, vector unsigned char __b) { - return __a >> (vector signed char)__b; + vector unsigned char __res = (vector unsigned char)__a >> __b; + return (vector signed char)__res; } static vector unsigned char __ATTRS_o_ai vec_sr(vector unsigned char __a, @@ -6537,9 +7589,10 @@ static vector unsigned char __ATTRS_o_ai vec_sr(vector unsigned char __a, return __a >> __b; } -static vector short __ATTRS_o_ai vec_sr(vector short __a, +static vector signed short __ATTRS_o_ai vec_sr(vector signed short __a, vector unsigned short __b) { - return __a >> (vector short)__b; + vector unsigned short __res = (vector unsigned short)__a >> __b; + return (vector signed short)__res; } static vector unsigned short __ATTRS_o_ai vec_sr(vector unsigned short __a, @@ -6547,8 +7600,10 @@ static vector unsigned short __ATTRS_o_ai vec_sr(vector unsigned short __a, return __a >> __b; } -static vector int __ATTRS_o_ai vec_sr(vector int __a, vector unsigned int __b) { - return __a >> (vector int)__b; +static vector signed int __ATTRS_o_ai vec_sr(vector signed int __a, + vector unsigned int __b) { + vector unsigned int __res = (vector unsigned int)__a >> __b; + return (vector signed int)__res; } static vector unsigned int __ATTRS_o_ai vec_sr(vector unsigned int __a, @@ -6559,7 +7614,8 @@ static vector unsigned int __ATTRS_o_ai vec_sr(vector unsigned int __a, #ifdef __POWER8_VECTOR__ static vector signed long long __ATTRS_o_ai vec_sr(vector signed long long __a, vector unsigned long long __b) { - return __a >> (vector long long)__b; + vector unsigned long long __res = (vector unsigned long long)__a >> __b; + return (vector signed long long)__res; } static vector unsigned long long __ATTRS_o_ai @@ -7960,6 +9016,13 @@ static vector float __ATTRS_o_ai vec_sub(vector float __a, vector float __b) { return __a - __b; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_sub(vector double __a, vector double __b) { + return __a - __b; +} +#endif + /* vec_vsububm */ #define __builtin_altivec_vsububm vec_vsububm @@ -8451,11 +9514,21 @@ vec_vsumsws(vector signed int __a, vector signed int __b) { /* vec_trunc */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_trunc(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspiz(__a); +#else return __builtin_altivec_vrfiz(__a); +#endif } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_trunc(vector double __a) { + return __builtin_vsx_xvrdpiz(__a); +} +#endif + /* vec_vrfiz */ static vector float __attribute__((__always_inline__)) @@ -8945,6 +10018,24 @@ static vector bool long long __ATTRS_o_ai vec_xor(vector bool long long __a, vector bool long long __b) { return __a ^ __b; } + +static vector double __ATTRS_o_ai +vec_xor(vector double __a, vector double __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long)__b); +} + +static vector double __ATTRS_o_ai +vec_xor(vector double __a, vector bool long long __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long) __b); +} + +static vector double __ATTRS_o_ai +vec_xor(vector bool long long __a, vector double __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long)__b); +} #endif /* vec_vxor */ diff --git a/lib/Headers/avx512vlbwintrin.h b/lib/Headers/avx512vlbwintrin.h index 59849e43fd32..eb198a5ade6f 100644 --- a/lib/Headers/avx512vlbwintrin.h +++ b/lib/Headers/avx512vlbwintrin.h @@ -777,6 +777,1051 @@ _mm_maskz_mullo_epi16 (__mmask8 __U, __m128i __A, __m128i __B) { _mm_setzero_si128 (), (__mmask8) __U); } + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_blend_epi8 (__mmask16 __U, __m128i __A, __m128i __W) +{ + return (__m128i) __builtin_ia32_blendmb_128_mask ((__v16qi) __A, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_blend_epi8 (__mmask32 __U, __m256i __A, __m256i __W) +{ + return (__m256i) __builtin_ia32_blendmb_256_mask ((__v32qi) __A, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_blend_epi16 (__mmask8 __U, __m128i __A, __m128i __W) +{ + return (__m128i) __builtin_ia32_blendmw_128_mask ((__v8hi) __A, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_blend_epi16 (__mmask16 __U, __m256i __A, __m256i __W) +{ + return (__m256i) __builtin_ia32_blendmw_256_mask ((__v16hi) __A, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_abs_epi8 (__m128i __W, __mmask16 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsb128_mask ((__v16qi) __A, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_abs_epi8 (__mmask16 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsb128_mask ((__v16qi) __A, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_abs_epi8 (__m256i __W, __mmask32 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsb256_mask ((__v32qi) __A, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_abs_epi8 (__mmask32 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsb256_mask ((__v32qi) __A, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_abs_epi16 (__m128i __W, __mmask8 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsw128_mask ((__v8hi) __A, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_abs_epi16 (__mmask8 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsw128_mask ((__v8hi) __A, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_abs_epi16 (__m256i __W, __mmask16 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsw256_mask ((__v16hi) __A, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_abs_epi16 (__mmask16 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsw256_mask ((__v16hi) __A, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packs_epi32 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packssdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) _mm_setzero_si128 (), __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packs_epi32 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packssdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) __W, __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packs_epi32 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packssdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packs_epi32 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packssdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) __W, __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packs_epi16 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packsswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packs_epi16 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packsswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) __W, + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packs_epi16 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packsswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packs_epi16 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packsswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packus_epi32 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packusdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packus_epi32 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packusdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) __W, __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packus_epi32 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packusdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packus_epi32 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packusdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packus_epi16 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packuswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packus_epi16 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packuswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) __W, + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packus_epi16 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packuswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packus_epi16 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packuswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epi16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epi16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epi16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epi16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_avg_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_avg_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_avg_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_avg_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_avg_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_avg_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_avg_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_avg_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epi8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epi8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epi8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epi8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epi16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epi16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epi16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epi16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epu8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epu8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epu8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epu8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epu16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epu16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epu16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epu16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epi8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epi8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epi8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epi8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epi16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epi16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epi16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epi16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epu8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epu8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epu8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epu8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epu16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epu16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epu16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epu16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_shuffle_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pshufb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_shuffle_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pshufb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_shuffle_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pshufb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_shuffle_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pshufb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epi16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epi16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epi16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epi16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask2_permutex2var_epi16 (__m128i __A, __m128i __I, __mmask8 __U, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermi2varhi128_mask ((__v8hi) __A, + (__v8hi) __I /* idx */ , + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask2_permutex2var_epi16 (__m256i __A, __m256i __I, + __mmask16 __U, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermi2varhi256_mask ((__v16hi) __A, + (__v16hi) __I /* idx */ , + (__v16hi) __B, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_permutex2var_epi16 (__m128i __A, __m128i __I, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_mask ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) -1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_permutex2var_epi16 (__m128i __A, __mmask8 __U, __m128i __I, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_mask ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_permutex2var_epi16 (__mmask8 __U, __m128i __A, __m128i __I, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_maskz ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_permutex2var_epi16 (__m256i __A, __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_mask ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) -1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_permutex2var_epi16 (__m256i __A, __mmask16 __U, + __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_mask ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_permutex2var_epi16 (__mmask16 __U, __m256i __A, + __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_maskz ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) __U); +} + #define _mm_cmp_epi8_mask(a, b, p) __extension__ ({ \ (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ (__v16qi)(__m128i)(b), \ diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 6c5c64bd266b..b805990eecbf 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -995,7 +995,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { return HFI; } -bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, HeaderFileInfo &Result) const { +bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, + HeaderFileInfo &Result) const { if (FE->getUID() >= FileInfo.size()) return false; const HeaderFileInfo &HFI = FileInfo[FE->getUID()]; @@ -1028,7 +1029,7 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, HeaderFileInfo &HFI = FileInfo[FE->getUID()]; HFI.isModuleHeader = true; - HFI.isCompilingModuleHeader = isCompilingModuleHeader; + HFI.isCompilingModuleHeader |= isCompilingModuleHeader; HFI.setHeaderRole(Role); } @@ -1058,15 +1059,16 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, // Next, check to see if the file is wrapped with #ifndef guards. If so, and // if the macro that guards it is defined, we know the #include has no effect. if (const IdentifierInfo *ControllingMacro - = FileInfo.getControllingMacro(ExternalLookup)) - // If the include file is part of a module, and we already know what its - // controlling macro is, then we've already parsed it and can safely just - // make it visible. This saves us needing to switch into the visibility - // state of the module just to check whether the macro is defined within it. - if (M || PP.isMacroDefined(ControllingMacro)) { + = FileInfo.getControllingMacro(ExternalLookup)) { + // If the header corresponds to a module, check whether the macro is already + // defined in that module rather than checking in the current set of visible + // modules. + if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M) + : PP.isMacroDefined(ControllingMacro)) { ++NumMultiIncludeFileOptzn; return false; } + } // Increment the number of times this file has been included. ++FileInfo.NumIncludes; diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index e6fe38927e26..96d3e4b8fe65 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -347,7 +347,7 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { // Iterate over all modules that 'File' is part of to find the best fit. for (KnownHeader &H : Known->second) { // Prefer a header from the current module over all others. - if (H.getModule() == CompilingModule) + if (H.getModule()->getTopLevelModule() == CompilingModule) return MakeResult(H); // Cannot use a module if it is unavailable. if (!H.getModule()->isAvailable()) @@ -1528,7 +1528,7 @@ void ModuleMapParser::parseModuleDecl() { /// 'extern' 'module' module-id string-literal void ModuleMapParser::parseExternModuleDecl() { assert(Tok.is(MMToken::ExternKeyword)); - consumeToken(); // 'extern' keyword + SourceLocation ExternLoc = consumeToken(); // 'extern' keyword // Parse 'module' keyword. if (!Tok.is(MMToken::ModuleKeyword)) { @@ -1567,7 +1567,7 @@ void ModuleMapParser::parseExternModuleDecl() { File, /*IsSystem=*/false, Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd ? Directory - : File->getDir()); + : File->getDir(), ExternLoc); } /// \brief Parse a requires declaration. @@ -2319,7 +2319,8 @@ bool ModuleMapParser::parseModuleMapFile() { } bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, - const DirectoryEntry *Dir) { + const DirectoryEntry *Dir, + SourceLocation ExternModuleLoc) { llvm::DenseMap<const FileEntry *, bool>::iterator Known = ParsedModuleMap.find(File); if (Known != ParsedModuleMap.end()) @@ -2327,7 +2328,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, assert(Target && "Missing target information"); auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; - FileID ID = SourceMgr.createFileID(File, SourceLocation(), FileCharacter); + FileID ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); if (!Buffer) return ParsedModuleMap[File] = true; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index d52519e3313b..64ce8c918258 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1088,6 +1088,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("objc_default_synthesize_properties", LangOpts.ObjC2) .Case("objc_fixed_enum", LangOpts.ObjC2) .Case("objc_instancetype", LangOpts.ObjC2) + .Case("objc_kindof", LangOpts.ObjC2) .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules) .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile()) .Case("objc_property_explicit_atomic", @@ -1106,6 +1107,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("arc_cf_code_audited", true) .Case("objc_bridge_id", true) .Case("objc_bridge_id_on_typedefs", true) + .Case("objc_generics", LangOpts.ObjC2) + .Case("objc_generics_variance", LangOpts.ObjC2) // C11 features .Case("c_alignas", LangOpts.C11) .Case("c_alignof", LangOpts.C11) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d843e801b634..f46af889e25d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -365,7 +365,8 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, // These may refer to the function arguments, but need to be parsed early to // participate in determining whether it's a redeclaration. std::unique_ptr<ParseScope> PrototypeScope; - if (AttrName->isStr("enable_if") && D && D->isFunctionDeclarator()) { + if (normalizeAttrName(AttrName->getName()) == "enable_if" && + D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | @@ -2144,8 +2145,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); - } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.hasAttributes()) { + } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -2602,6 +2602,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] +/// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' @@ -2886,12 +2887,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - continue; } @@ -2997,11 +2992,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object or object pointer + // type. Handle either one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + SourceLocation NewEndLoc; + TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers( + Loc, TypeRep, /*consumeLastToken=*/true, + NewEndLoc); + if (NewTypeRep.isUsable()) { + DS.UpdateTypeRep(NewTypeRep.get()); + DS.SetRangeEnd(NewEndLoc); + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -3082,6 +3085,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseNullabilityTypeSpecifiers(DS.getAttributes()); continue; + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, @@ -3418,10 +3428,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; - if (!ParseObjCProtocolQualifiers(DS)) - Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, DS.getSourceRange().getEnd()); + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + TypeResult Type = parseObjCProtocolQualifierType(EndLoc); + if (Type.isUsable()) { + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc, + PrevSpec, DiagID, Type.get(), + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + + DS.SetRangeEnd(EndLoc); + } else { + DS.SetTypeSpecError(); + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -4335,6 +4354,8 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4515,6 +4536,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4752,6 +4775,13 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, ParseNullabilityTypeSpecifiers(DS.getAttributes()); continue; + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + case tok::kw___attribute: if (AttrReqs & AR_GNUAttributesParsedAndRejected) // When GNU attributes are expressly forbidden, diagnose their usage. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 568896db42be..e347d4e27e26 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -543,10 +543,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation IdLoc = ConsumeToken(); ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); Name.setConstructorName(Type, IdLoc, IdLoc); - } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, - /*AllowDestructorName=*/ true, - /*AllowConstructorName=*/ true, ParsedType(), - TemplateKWLoc, Name)) { + } else if (ParseUnqualifiedId( + SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/NextToken().isNot(tok::equal), + ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } @@ -2814,16 +2815,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, break; } - if ((S->getFlags() & Scope::FnScope)) { - // If we're in a function or function template declared in the - // body of a class, then this is a local class rather than a - // nested class. - const Scope *Parent = S->getParent(); - if (Parent->isTemplateParamScope()) - Parent = Parent->getParent(); - if (Parent->isClassScope()) - break; - } + if ((S->getFlags() & Scope::FnScope)) + // If we're in a function or function template then this is a local + // class rather than a nested class. + break; } } @@ -3813,7 +3808,7 @@ SourceLocation Parser::SkipCXX11Attributes() { return EndLoc; } -/// Parse one or more Microsoft-style attributes [Attr] +/// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: /// '[' token-seq ']' @@ -3829,8 +3824,6 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, // FIXME: If this is actually a C++11 attribute, parse it as one. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); - if (Tok.is(tok::r_square)) - Diag(T.getOpenLocation(), diag::err_empty_attribute_block); SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); T.consumeClose(); if (endLoc) diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 02176c410592..c1dafe9b49b1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - DS.Finish(Diags, PP, Policy); return; } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 42287d68b331..4896ff0d235a 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -252,26 +252,40 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // Three cases. This is a message send to a type: [type foo] // This is a message send to super: [super foo] // This is a message sent to an expr: [super.bar foo] - switch (Sema::ObjCMessageKind Kind - = Actions.getObjCMessageKind(getCurScope(), II, IILoc, - II == Ident_super, - NextToken().is(tok::period), - ReceiverType)) { + switch (Actions.getObjCMessageKind( + getCurScope(), II, IILoc, II == Ident_super, + NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + nullptr); + case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - if (Kind == Sema::ObjCSuperMessage) - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); ConsumeToken(); // the identifier if (!ReceiverType) { SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f975f8715ed9..ed6090453daa 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { /// /// objc-class-declaration: -/// '@' 'class' identifier-list ';' +/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';' +/// +/// objc-class-forward-decl: +/// identifier objc-type-parameter-list[opt] /// Parser::DeclGroupPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" SmallVector<IdentifierInfo *, 8> ClassNames; SmallVector<SourceLocation, 8> ClassLocs; - + SmallVector<ObjCTypeParamList *, 8> ClassTypeParams; while (1) { MaybeSkipAttributes(tok::objc_class); @@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ClassLocs.push_back(Tok.getLocation()); ConsumeToken(); + // Parse the optional objc-type-parameter-list. + ObjCTypeParamList *TypeParams = nullptr; + if (Tok.is(tok::less)) { + TypeParams = parseObjCTypeParamList(); + if (TypeParams) + Actions.popObjCTypeParamList(getCurScope(), TypeParams); + } + ClassTypeParams.push_back(TypeParams); if (!TryConsumeToken(tok::comma)) break; } @@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), ClassLocs.data(), + ClassTypeParams, ClassNames.size()); } @@ -154,20 +166,20 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) /// objc-category-interface /// /// objc-class-interface: -/// '@' 'interface' identifier objc-superclass[opt] -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// objc-superclass[opt] objc-protocol-refs[opt] /// objc-class-instance-variables[opt] /// objc-interface-decl-list /// @end /// /// objc-category-interface: -/// '@' 'interface' identifier '(' identifier[opt] ')' -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// '(' identifier[opt] ')' objc-protocol-refs[opt] /// objc-interface-decl-list /// @end /// /// objc-superclass: -/// ':' identifier +/// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) @@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - if (Tok.is(tok::l_paren) && + + // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter + // case, LAngleLoc will be valid and ProtocolIdents will capture the + // protocol references (that have not yet been resolved). + SourceLocation LAngleLoc, EndProtoLoc; + SmallVector<IdentifierLocPair, 8> ProtocolIdents; + ObjCTypeParamList *typeParameterList = nullptr; + if (Tok.is(tok::less)) { + typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc, + ProtocolIdents, + EndProtoLoc); + } + + if (Tok.is(tok::l_paren) && !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -237,17 +262,19 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } // Next, we need to check for any protocol references. - SourceLocation LAngleLoc, EndProtoLoc; + assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols"); SmallVector<Decl *, 8> ProtocolRefs; SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, - LAngleLoc, EndProtoLoc)) + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return nullptr; Decl *CategoryType = Actions.ActOnStartCategoryInterface(AtLoc, nameId, nameLoc, + typeParameterList, categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), @@ -258,12 +285,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc); ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return CategoryType; } // Parse a class interface. IdentifierInfo *superClassId = nullptr; SourceLocation superClassLoc; - + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); @@ -281,30 +316,64 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); + + // Type arguments for the superclass or protocol conformances. + if (Tok.is(tok::less)) { + parseObjCTypeArgsOrProtocolQualifiers(ParsedType(), + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + LAngleLoc, + protocols, + protocolLocs, + EndProtoLoc, + /*consumeLastToken=*/true, + /*warnOnIncompleteProtocols=*/true); + } } + // Next, we need to check for any protocol references. - SmallVector<Decl *, 8> ProtocolRefs; - SmallVector<SourceLocation, 8> ProtocolLocs; - SourceLocation LAngleLoc, EndProtoLoc; - if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, - LAngleLoc, EndProtoLoc)) + if (LAngleLoc.isValid()) { + if (!ProtocolIdents.empty()) { + // We already parsed the protocols named when we thought we had a + // type parameter list. Translate them into actual protocol references. + for (const auto &pair : ProtocolIdents) { + protocolLocs.push_back(pair.second); + } + Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true, + /*ForObjCContainer=*/true, + &ProtocolIdents[0], ProtocolIdents.size(), + protocols); + } + } else if (protocols.empty() && Tok.is(tok::less) && + ParseObjCProtocolReferences(protocols, protocolLocs, true, true, + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) { return nullptr; + } if (Tok.isNot(tok::less)) - Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); + Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc); Decl *ClsType = - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, - superClassId, superClassLoc, - ProtocolRefs.data(), ProtocolRefs.size(), - ProtocolLocs.data(), + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, + typeParameterList, superClassId, + superClassLoc, + typeArgs, + SourceRange(typeArgsLAngleLoc, + typeArgsRAngleLoc), + protocols.data(), protocols.size(), + protocolLocs.data(), EndProtoLoc, attrs.getList()); if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc); ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return ClsType; } @@ -339,6 +408,203 @@ static void addContextSensitiveTypeNullability(Parser &P, } } +/// Parse an Objective-C type parameter list, if present, or capture +/// the locations of the protocol identifiers for a list of protocol +/// references. +/// +/// objc-type-parameter-list: +/// '<' objc-type-parameter (',' objc-type-parameter)* '>' +/// +/// objc-type-parameter: +/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt] +/// +/// objc-type-parameter-bound: +/// ':' type-name +/// +/// objc-type-parameter-variance: +/// '__covariant' +/// '__contravariant' +/// +/// \param lAngleLoc The location of the starting '<'. +/// +/// \param protocolIdents Will capture the list of identifiers, if the +/// angle brackets contain a list of protocol references rather than a +/// type parameter list. +/// +/// \param rAngleLoc The location of the ending '>'. +ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( + SourceLocation &lAngleLoc, + SmallVectorImpl<IdentifierLocPair> &protocolIdents, + SourceLocation &rAngleLoc, + bool mayBeProtocolList) { + assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list"); + + // Within the type parameter list, don't treat '>' as an operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + + // Local function to "flush" the protocol identifiers, turning them into + // type parameters. + SmallVector<Decl *, 4> typeParams; + auto makeProtocolIdentsIntoTypeParameters = [&]() { + unsigned index = 0; + for (const auto &pair : protocolIdents) { + DeclResult typeParam = Actions.actOnObjCTypeParam( + getCurScope(), + ObjCTypeParamVariance::Invariant, + SourceLocation(), + index++, + pair.first, + pair.second, + SourceLocation(), + ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } + + protocolIdents.clear(); + mayBeProtocolList = false; + }; + + bool invalid = false; + lAngleLoc = ConsumeToken(); + + do { + // Parse the variance, if any. + SourceLocation varianceLoc; + ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant; + if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) { + variance = Tok.is(tok::kw___covariant) + ? ObjCTypeParamVariance::Covariant + : ObjCTypeParamVariance::Contravariant; + varianceLoc = ConsumeToken(); + + // Once we've seen a variance specific , we know this is not a + // list of protocol references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + } + + // Parse the identifier. + if (!Tok.is(tok::identifier)) { + // Code completion. + if (Tok.is(tok::code_completion)) { + // FIXME: If these aren't protocol references, we'll need different + // completions. + Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(), + protocolIdents.size()); + cutOffParsing(); + + // FIXME: Better recovery here?. + return nullptr; + } + + Diag(Tok, diag::err_objc_expected_type_parameter); + invalid = true; + break; + } + + IdentifierInfo *paramName = Tok.getIdentifierInfo(); + SourceLocation paramLoc = ConsumeToken(); + + // If there is a bound, parse it. + SourceLocation colonLoc; + TypeResult boundType; + if (TryConsumeToken(tok::colon, colonLoc)) { + // Once we've seen a bound, we know this is not a list of protocol + // references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + + // type-name + boundType = ParseTypeName(); + if (boundType.isInvalid()) + invalid = true; + } else if (mayBeProtocolList) { + // If this could still be a protocol list, just capture the identifier. + // We don't want to turn it into a parameter. + protocolIdents.push_back(std::make_pair(paramName, paramLoc)); + continue; + } + + // Create the type parameter. + DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), + variance, + varianceLoc, + typeParams.size(), + paramName, + paramLoc, + colonLoc, + boundType.isUsable() + ? boundType.get() + : ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } while (TryConsumeToken(tok::comma)); + + // Parse the '>'. + if (invalid) { + SkipUntil(tok::greater, tok::at, StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } else if (ParseGreaterThanInTemplateList(rAngleLoc, + /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true)) { + Diag(lAngleLoc, diag::note_matching) << "'<'"; + SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus, + tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace, + tok::comma, tok::semi }, + StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } + + if (mayBeProtocolList) { + // A type parameter list must be followed by either a ':' (indicating the + // presence of a superclass) or a '(' (indicating that this is a category + // or extension). This disambiguates between an objc-type-parameter-list + // and a objc-protocol-refs. + if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) { + // Returning null indicates that we don't have a type parameter list. + // The results the caller needs to handle the protocol references are + // captured in the reference parameters already. + return nullptr; + } + + // We have a type parameter list that looks like a list of protocol + // references. Turn that parameter list into type parameters. + makeProtocolIdentsIntoTypeParameters(); + } + + // Form the type parameter list. + ObjCTypeParamList *list = Actions.actOnObjCTypeParamList( + getCurScope(), + lAngleLoc, + typeParams, + rAngleLoc); + + // Clear out the angle locations; they're used by the caller to indicate + // whether there are any protocol references. + lAngleLoc = SourceLocation(); + rAngleLoc = SourceLocation(); + return list; +} + +/// Parse an objc-type-parameter-list. +ObjCTypeParamList *Parser::parseObjCTypeParamList() { + SourceLocation lAngleLoc; + SmallVector<IdentifierLocPair, 1> protocolIdents; + SourceLocation rAngleLoc; + return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc, + /*mayBeProtocolList=*/false); +} + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -1281,7 +1547,8 @@ bool Parser:: ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, SmallVectorImpl<SourceLocation> &ProtocolLocs, bool WarnOnDeclarations, bool ForObjCContainer, - SourceLocation &LAngleLoc, SourceLocation &EndLoc) { + SourceLocation &LAngleLoc, SourceLocation &EndLoc, + bool consumeLastToken) { assert(Tok.is(tok::less) && "expected <"); LAngleLoc = ConsumeToken(); // the "<" @@ -1311,7 +1578,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true)) + if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, + /*ObjCGenericList=*/false)) return true; // Convert the list of protocols identifiers into a list of protocol decls. @@ -1321,22 +1589,263 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, return false; } -/// \brief Parse the Objective-C protocol qualifiers that follow a typename -/// in a decl-specifier-seq, starting at the '<'. -bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { +TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) { assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C"); - SourceLocation LAngleLoc, EndProtoLoc; - SmallVector<Decl *, 8> ProtocolDecl; - SmallVector<SourceLocation, 8> ProtocolLocs; - bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - if (EndProtoLoc.isValid()) - DS.SetRangeEnd(EndProtoLoc); - return Result; + + SourceLocation lAngleLoc; + SmallVector<Decl *, 8> protocols; + SmallVector<SourceLocation, 8> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false, + lAngleLoc, rAngleLoc, + /*consumeLastToken=*/true); + TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc, + protocols, + protocolLocs, + rAngleLoc); + if (result.isUsable()) { + Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::CreateInsertion(lAngleLoc, "id") + << SourceRange(lAngleLoc, rAngleLoc); + } + + return result; +} + +/// Parse Objective-C type arguments or protocol qualifiers. +/// +/// objc-type-arguments: +/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' +/// +void Parser::parseObjCTypeArgsOrProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken, + bool warnOnIncompleteProtocols) { + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); + SourceLocation lAngleLoc = ConsumeToken(); + + // Whether all of the elements we've parsed thus far are single + // identifiers, which might be types or might be protocols. + bool allSingleIdentifiers = true; + SmallVector<IdentifierInfo *, 4> identifiers; + SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs; + + // Parse a list of comma-separated identifiers, bailing out if we + // see something different. + do { + // Parse a single identifier. + if (Tok.is(tok::identifier) && + (NextToken().is(tok::comma) || + NextToken().is(tok::greater) || + NextToken().is(tok::greatergreater))) { + identifiers.push_back(Tok.getIdentifierInfo()); + identifierLocs.push_back(ConsumeToken()); + continue; + } + + if (Tok.is(tok::code_completion)) { + // FIXME: Also include types here. + SmallVector<IdentifierLocPair, 4> identifierLocPairs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], + identifierLocs[i])); + } + + QualType BaseT = Actions.GetTypeFromParser(baseType); + if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + } else { + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + } + cutOffParsing(); + return; + } + + allSingleIdentifiers = false; + break; + } while (TryConsumeToken(tok::comma)); + + // If we parsed an identifier list, semantic analysis sorts out + // whether it refers to protocols or to type arguments. + if (allSingleIdentifiers) { + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + // Let Sema figure out what we parsed. + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), + baseType, + lAngleLoc, + identifiers, + identifierLocs, + rAngleLoc, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolRAngleLoc, + warnOnIncompleteProtocols); + return; + } + + // We syntactically matched a type argument, so commit to parsing + // type arguments. + + // Convert the identifiers into type arguments. + bool invalid = false; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ParsedType typeArg + = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); + if (typeArg) { + DeclSpec DS(AttrFactory); + const char *prevSpec = nullptr; + unsigned diagID; + DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID, + typeArg, Actions.getASTContext().getPrintingPolicy()); + + // Form a declarator to turn this into a type. + Declarator D(DS, Declarator::TypeNameContext); + TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D); + if (fullTypeArg.isUsable()) + typeArgs.push_back(fullTypeArg.get()); + else + invalid = true; + } else { + invalid = true; + } + } + + // Continue parsing type-names. + do { + TypeResult typeArg = ParseTypeName(); + + // Consume the '...' for a pack expansion. + SourceLocation ellipsisLoc; + TryConsumeToken(tok::ellipsis, ellipsisLoc); + if (typeArg.isUsable() && ellipsisLoc.isValid()) { + typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc); + } + + if (typeArg.isUsable()) { + typeArgs.push_back(typeArg.get()); + } else { + invalid = true; + } + } while (TryConsumeToken(tok::comma)); + + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + if (invalid) { + typeArgs.clear(); + return; + } + + // Record left/right angle locations. + typeArgsLAngleLoc = lAngleLoc; + typeArgsRAngleLoc = rAngleLoc; +} + +void Parser::parseObjCTypeArgsAndProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken) { + assert(Tok.is(tok::less)); + + // Parse the first angle-bracket-delimited clause. + parseObjCTypeArgsOrProtocolQualifiers(baseType, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc, + consumeLastToken, + /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if ((consumeLastToken && Tok.is(tok::less)) || + (!consumeLastToken && NextToken().is(tok::less))) { + // If we aren't consuming the last token, the prior '>' is still hanging + // there. Consume it before we parse the protocol qualifiers. + if (!consumeLastToken) + ConsumeToken(); + + if (!protocols.empty()) { + SkipUntilFlags skipFlags = SkipUntilFlags(); + if (!consumeLastToken) + skipFlags = skipFlags | StopBeforeMatch; + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(protocolLAngleLoc, protocolRAngleLoc); + SkipUntil(tok::greater, tok::greatergreater, skipFlags); + } else { + ParseObjCProtocolReferences(protocols, protocolLocs, + /*WarnOnDeclarations=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + consumeLastToken); + } + } +} + +TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers( + SourceLocation loc, + ParsedType type, + bool consumeLastToken, + SourceLocation &endLoc) { + assert(Tok.is(tok::less)); + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SourceLocation protocolLAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + SourceLocation protocolRAngleLoc; + + // Parse type arguments and protocol qualifiers. + parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs, + typeArgsRAngleLoc, protocolLAngleLoc, + protocols, protocolLocs, + protocolRAngleLoc, consumeLastToken); + + // Compute the location of the last token. + if (consumeLastToken) + endLoc = PrevTokLocation; + else + endLoc = Tok.getLocation(); + + return Actions.actOnObjCTypeArgsAndProtocolQualifiers( + getCurScope(), + loc, + type, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc); } void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, @@ -1548,7 +2057,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true, - LAngleLoc, EndProtoLoc)) + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return DeclGroupPtrTy(); Decl *ProtoType = @@ -1598,6 +2108,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { SourceLocation nameLoc = ConsumeToken(); // consume class or category name Decl *ObjCImpDecl = nullptr; + // Neither a type parameter list nor a list of protocol references is + // permitted here. Parse and diagnose them. + if (Tok.is(tok::less)) { + SourceLocation lAngleLoc, rAngleLoc; + SmallVector<IdentifierLocPair, 8> protocolIdents; + SourceLocation diagLoc = Tok.getLocation(); + if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc)) { + Diag(diagLoc, diag::err_objc_parameterized_implementation) + << SourceRange(diagLoc, PrevTokLocation); + } else if (lAngleLoc.isValid()) { + Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier) + << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc)); + } + } + if (Tok.is(tok::l_paren)) { // we have a category implementation. ConsumeParen(); @@ -1626,9 +2152,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { rparenLoc = ConsumeParen(); if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( AtLoc, nameId, nameLoc, categoryId, @@ -1656,10 +2187,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); else if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - // try to recover. - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } } assert(ObjCImpDecl); @@ -2477,6 +3013,21 @@ ExprResult Parser::ParseObjCMessageExpression() { ConsumeToken(); // the type name + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 2a9becbc8570..3a964dd20528 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -738,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, /// /// \param RAngleLoc the location of the consumed '>'. /// -/// \param ConsumeLastToken if true, the '>' is not consumed. +/// \param ConsumeLastToken if true, the '>' is consumed. +/// +/// \param ObjCGenericList if true, this is the '>' closing an Objective-C +/// type parameter or type argument list, rather than a C++ template parameter +/// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, - bool ConsumeLastToken) { + bool ConsumeLastToken, + bool ObjCGenericList) { // What will be left once we've consumed the '>'. tok::TokenKind RemainingToken; const char *ReplacementStr = "> >"; @@ -783,40 +788,44 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, // the token isn't '>>' or '>>>'. // '>>>' is for CUDA, where this sequence of characters is parsed into // tok::greatergreatergreater, rather than two separate tokens. - + // + // We always allow this for Objective-C type parameter and type argument + // lists. RAngleLoc = Tok.getLocation(); - - // The source range of the '>>' or '>=' at the start of the token. - CharSourceRange ReplacementRange = - CharSourceRange::getCharRange(RAngleLoc, - Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), - getLangOpts())); - - // A hint to put a space between the '>>'s. In order to make the hint as - // clear as possible, we include the characters either side of the space in - // the replacement, rather than just inserting a space at SecondCharLoc. - FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, - ReplacementStr); - - // A hint to put another space after the token, if it would otherwise be - // lexed differently. - FixItHint Hint2; Token Next = NextToken(); - if ((RemainingToken == tok::greater || - RemainingToken == tok::greatergreater) && - Next.isOneOf(tok::greater, tok::greatergreater, - tok::greatergreatergreater, tok::equal, tok::greaterequal, - tok::greatergreaterequal, tok::equalequal) && - areTokensAdjacent(Tok, Next)) - Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); - - unsigned DiagId = diag::err_two_right_angle_brackets_need_space; - if (getLangOpts().CPlusPlus11 && - Tok.isOneOf(tok::greatergreater, tok::greatergreatergreater)) - DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; - else if (Tok.is(tok::greaterequal)) - DiagId = diag::err_right_angle_bracket_equal_needs_space; - Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + if (!ObjCGenericList) { + // The source range of the '>>' or '>=' at the start of the token. + CharSourceRange ReplacementRange = + CharSourceRange::getCharRange(RAngleLoc, + Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), + getLangOpts())); + + // A hint to put a space between the '>>'s. In order to make the hint as + // clear as possible, we include the characters either side of the space in + // the replacement, rather than just inserting a space at SecondCharLoc. + FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, + ReplacementStr); + + // A hint to put another space after the token, if it would otherwise be + // lexed differently. + FixItHint Hint2; + if ((RemainingToken == tok::greater || + RemainingToken == tok::greatergreater) && + (Next.isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater, tok::equal, + tok::greaterequal, tok::greatergreaterequal, + tok::equalequal)) && + areTokensAdjacent(Tok, Next)) + Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); + + unsigned DiagId = diag::err_two_right_angle_brackets_need_space; + if (getLangOpts().CPlusPlus11 && + (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater))) + DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; + else if (Tok.is(tok::greaterequal)) + DiagId = diag::err_right_angle_bracket_equal_needs_space; + Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + } // Strip the initial '>' from the token. if (RemainingToken == tok::equal && Next.is(tok::equal) && @@ -895,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, } } - return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken); + return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken, + /*ObjCGenericList=*/false); } /// \brief Replace the tokens that form a simple-template-id with an diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 368cb934bbaf..9d2a2b931e88 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1281,6 +1281,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw__Nonnull: case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: return TPResult::True; // Borland @@ -1384,7 +1385,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the + // Tentatively parse the protocol qualifiers. TentativeParsingAction PA(*this); ConsumeToken(); // The type token diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e32df95548d9..e76f767786f0 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1413,14 +1413,35 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, // It's not something we know about. Leave it unannotated. break; - case Sema::NC_Type: - Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Classification.getType()); - Tok.setAnnotationEndLoc(NameLoc); + case Sema::NC_Type: { + SourceLocation BeginLoc = NameLoc; if (SS.isNotEmpty()) - Tok.setLocation(SS.getBeginLoc()); + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + ParsedType Ty = Classification.getType(); + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Ty); + Tok.setAnnotationEndLoc(Tok.getLocation()); + Tok.setLocation(BeginLoc); PP.AnnotateCachedTokens(Tok); return ANK_Success; + } case Sema::NC_Expression: Tok.setKind(tok::annot_primary_expr); @@ -1627,13 +1648,33 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // A FixIt was applied as a result of typo correction if (CorrectedII) Tok.setIdentifierInfo(CorrectedII); + + SourceLocation BeginLoc = Tok.getLocation(); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Ty); Tok.setAnnotationEndLoc(Tok.getLocation()); - if (SS.isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(SS.getBeginLoc()); + Tok.setLocation(BeginLoc); // In case the tokens were cached, have Preprocessor replace // them with the annotation token. diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 69ae4f01dc7b..18e9a5911641 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -444,7 +444,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(), + = Results[I].CreateCodeCompletionString(SemaRef, Context, + getAllocator(), CCTUInfo, includeBriefComments())) { OS << " : " << CCS->getAsString(); @@ -462,7 +463,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, case CodeCompletionResult::RK_Macro: { OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(), + = Results[I].CreateCodeCompletionString(SemaRef, Context, + getAllocator(), CCTUInfo, includeBriefComments())) { OS << " : " << CCS->getAsString(); diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d5c8871cac87..ea3872f42700 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -905,20 +905,6 @@ bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, return false; } -void DeclSpec::setProtocolQualifiers(Decl * const *Protos, - unsigned NP, - SourceLocation *ProtoLocs, - SourceLocation LAngleLoc) { - if (NP == 0) return; - Decl **ProtoQuals = new Decl*[NP]; - memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP); - ProtocolQualifiers = ProtoQuals; - ProtocolLocs = new SourceLocation[NP]; - memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); - NumProtocolQualifiers = NP; - ProtocolLAngleLoc = LAngleLoc; -} - void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Sign = getTypeSpecSign(); writtenBS.Width = getTypeSpecWidth(); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index d9dc4df9f271..c0754ba7902a 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -975,7 +975,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, if (tcr != TC_NotApplicable) return tcr; - // C++0x [expr.static.cast]p3: + // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, @@ -1133,7 +1133,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, CastKind &Kind, CXXCastPath &BasePath, unsigned &msg) { - // C++0x [expr.static.cast]p3: + // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". const RValueReferenceType *R = DestType->getAs<RValueReferenceType>(); @@ -1161,6 +1161,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, DerivedToBase, ObjCConversion, ObjCLifetimeConversion) < Sema::Ref_Compatible_With_Added_Qualification) { + if (CStyle) + return TC_NotApplicable; msg = diag::err_bad_lvalue_to_rvalue_cast; return TC_Failed; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index bdfff80c7f20..d9d26e2af602 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -6884,6 +6884,101 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, S.getFixItZeroLiteralForType(T, Loc)); } +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); +static void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); + +/// Check a single element within a collection literal against the +/// target element type. +static void checkObjCCollectionLiteralElement(Sema &S, + QualType TargetElementType, + Expr *Element, + unsigned ElementKind) { + // Skip a bitcast to 'id' or qualified 'id'. + if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { + if (ICE->getCastKind() == CK_BitCast && + ICE->getSubExpr()->getType()->getAs<ObjCObjectPointerType>()) + Element = ICE->getSubExpr(); + } + + QualType ElementType = Element->getType(); + ExprResult ElementResult(Element); + if (ElementType->getAs<ObjCObjectPointerType>() && + S.CheckSingleAssignmentConstraints(TargetElementType, + ElementResult, + false, false) + != Sema::Compatible) { + S.Diag(Element->getLocStart(), + diag::warn_objc_collection_literal_element) + << ElementType << ElementKind << TargetElementType + << Element->getSourceRange(); + } + + if (auto ArrayLiteral = dyn_cast<ObjCArrayLiteral>(Element)) + checkObjCArrayLiteral(S, TargetElementType, ArrayLiteral); + else if (auto DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(Element)) + checkObjCDictionaryLiteral(S, TargetElementType, DictionaryLiteral); +} + +/// Check an Objective-C array literal being converted to the given +/// target type. +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { + if (!S.NSArrayDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs<ObjCObjectPointerType>(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() + != S.NSArrayDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 1) + return; + + QualType TargetElementType = TypeArgs[0]; + for (unsigned I = 0, N = ArrayLiteral->getNumElements(); I != N; ++I) { + checkObjCCollectionLiteralElement(S, TargetElementType, + ArrayLiteral->getElement(I), + 0); + } +} + +/// Check an Objective-C dictionary literal being converted to the given +/// target type. +static void checkObjCDictionaryLiteral( + Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { + if (!S.NSDictionaryDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs<ObjCObjectPointerType>(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() + != S.NSDictionaryDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 2) + return; + + QualType TargetKeyType = TypeArgs[0]; + QualType TargetObjectType = TypeArgs[1]; + for (unsigned I = 0, N = DictionaryLiteral->getNumElements(); I != N; ++I) { + auto Element = DictionaryLiteral->getKeyValueElement(I); + checkObjCCollectionLiteralElement(S, TargetKeyType, Element.Key, 1); + checkObjCCollectionLiteralElement(S, TargetObjectType, Element.Value, 2); + } +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -6923,6 +7018,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } + // Check implicit casts from Objective-C collection literals to specialized + // collection types, e.g., NSArray<NSString *> *. + if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E)) + checkObjCArrayLiteral(S, QualType(Target, 0), ArrayLiteral); + else if (auto *DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(E)) + checkObjCDictionaryLiteral(S, QualType(Target, 0), DictionaryLiteral); + // Strip vector types. if (isa<VectorType>(Source)) { if (!isa<VectorType>(Target)) { diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ff6a3eed8c25..86265275d05e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2057,6 +2057,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, static void AddResultTypeChunk(ASTContext &Context, const PrintingPolicy &Policy, const NamedDecl *ND, + QualType BaseType, CodeCompletionBuilder &Result) { if (!ND) return; @@ -2070,16 +2071,28 @@ static void AddResultTypeChunk(ASTContext &Context, QualType T; if (const FunctionDecl *Function = ND->getAsFunction()) T = Function->getReturnType(); - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) - T = Method->getReturnType(); - else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) { + if (!BaseType.isNull()) + T = Method->getSendResultType(BaseType); + else + T = Method->getReturnType(); + } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); else if (isa<UnresolvedUsingValueDecl>(ND)) { /* Do nothing: ignore unresolved using declarations*/ + } else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { + if (!BaseType.isNull()) + T = Ivar->getUsageType(BaseType); + else + T = Ivar->getType(); } else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND)) { T = Value->getType(); - } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) - T = Property->getType(); + } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) { + if (!BaseType.isNull()) + T = Property->getUsageType(BaseType); + else + T = Property->getType(); + } if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; @@ -2140,7 +2153,8 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals, static std::string FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, - bool SuppressBlock = false) { + bool SuppressBlock = false, + Optional<ArrayRef<QualType>> ObjCSubsts = None) { bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -2152,6 +2166,9 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Result = Param->getIdentifier()->getName(); QualType Type = Param->getType(); + if (ObjCSubsts) + Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, + ObjCSubstitutionContext::Parameter); if (ObjCMethodParam) { Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); @@ -2187,6 +2204,11 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, TL = QualifiedTL.getUnqualifiedLoc(); continue; } + + if (AttributedTypeLoc AttrTL = TL.getAs<AttributedTypeLoc>()) { + TL = AttrTL.getModifiedLoc(); + continue; + } } // Try to get the function prototype behind the block pointer type, @@ -2226,6 +2248,10 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, // written in the source. std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); + if (ObjCSubsts) + ResultType = ResultType.substObjCTypeArgs(Param->getASTContext(), + *ObjCSubsts, + ObjCSubstitutionContext::Result); if (!ResultType->isVoidType() || SuppressBlock) ResultType.getAsStringInternal(Result, Policy); @@ -2243,7 +2269,8 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Params += ", "; Params += FormatFunctionParameter(Policy, Block.getParam(I), /*SuppressName=*/false, - /*SuppressBlock=*/true); + /*SuppressBlock=*/true, + ObjCSubsts); if (I == N - 1 && BlockProto.getTypePtr()->isVariadic()) Params += ", ..."; @@ -2537,11 +2564,12 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, } CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { - return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo, - IncludeBriefComments); + return CreateCodeCompletionString(S.Context, S.PP, CCContext, Allocator, + CCTUInfo, IncludeBriefComments); } /// \brief If possible, create a new code completion string for the given @@ -2553,6 +2581,7 @@ CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S, CodeCompletionString * CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Preprocessor &PP, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { @@ -2666,7 +2695,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, for (const auto *I : ND->specific_attrs<AnnotateAttr>()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, Result); + AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, @@ -2786,14 +2815,22 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, continue; std::string Arg; - - if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) - Arg = FormatFunctionParameter(Policy, *P, true); + QualType ParamType = (*P)->getType(); + Optional<ArrayRef<QualType>> ObjCSubsts; + if (!CCContext.getBaseType().isNull()) + ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method); + + if (ParamType->isBlockPointerType() && !DeclaringEntity) + Arg = FormatFunctionParameter(Policy, *P, true, + /*SuppressBlock=*/false, + ObjCSubsts); else { - QualType Type = (*P)->getType(); + if (ObjCSubsts) + ParamType = ParamType.substObjCTypeArgs(Ctx, *ObjCSubsts, + ObjCSubstitutionContext::Parameter); Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), - Type); - Arg += Type.getAsString(Policy) + ")"; + ParamType); + Arg += ParamType.getAsString(Policy) + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); @@ -2930,7 +2967,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( if (auto RC = S.getASTContext().getRawCommentForAnyRedecl( FDecl->getParamDecl(CurrentArg))) Result.addBriefComment(RC->getBriefText(S.getASTContext())); - AddResultTypeChunk(S.Context, Policy, FDecl, Result); + AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result); Result.AddTextChunk( Result.getAllocator().CopyString(FDecl->getNameAsString())); } else { @@ -3029,7 +3066,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { case Decl::Import: return CXCursor_ModuleImportDecl; - + + case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter; + default: if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { @@ -3520,7 +3559,8 @@ static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { return Container; } -static void AddObjCProperties(ObjCContainerDecl *Container, +static void AddObjCProperties(const CodeCompletionContext &CCContext, + ObjCContainerDecl *Container, bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext, @@ -3547,7 +3587,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container, if (AddedProperties.insert(Name).second) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - AddResultTypeChunk(Context, Policy, M, Builder); + AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), + Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Name->getName())); @@ -3562,32 +3603,32 @@ static void AddObjCProperties(ObjCContainerDecl *Container, // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (auto *P : Protocol->protocols()) - AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (auto *Cat : IFace->known_categories()) - AddObjCProperties(Cat, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } // Look through protocols. for (auto *I : IFace->all_referenced_protocols()) - AddObjCProperties(I, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); // Look in the superclass. if (IFace->getSuperClass()) - AddObjCProperties(IFace->getSuperClass(), AllowCategories, + AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { // Look through protocols. for (auto *P : Category->protocols()) - AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } } @@ -3629,11 +3670,11 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } - + + CodeCompletionContext CCContext(contextKind, BaseType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext(contextKind, - BaseType), + CCContext, &ResultBuilder::IsMember); Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { @@ -3673,14 +3714,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, + AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results); // Add properties from the protocols in a qualified interface. for (auto *I : ObjCPtr->quals()) - AddObjCProperties(I, true, /*AllowNullaryMethods=*/true, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, + CurContext, AddedProperties, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -4368,9 +4409,12 @@ void Sema::CodeCompleteOperatorName(Scope *S) { void Sema::CodeCompleteConstructorInitializer( Decl *ConstructorD, ArrayRef <CXXCtorInitializer *> Initializers) { - PrintingPolicy Policy = getCompletionPrintingPolicy(*this); - CXXConstructorDecl *Constructor - = static_cast<CXXConstructorDecl *>(ConstructorD); + if (!ConstructorD) + return; + + AdjustDeclIfTemplate(ConstructorD); + + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorD); if (!Constructor) return; @@ -4394,6 +4438,7 @@ void Sema::CodeCompleteConstructorInitializer( // Add completions for base classes. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); bool SawLastInitializer = Initializers.empty(); CXXRecordDecl *ClassDecl = Constructor->getParent(); for (const auto &Base : ClassDecl->bases()) { @@ -5334,7 +5379,8 @@ static ObjCMethodDecl *AddSuperSendCompletion( Results.getCodeCompletionTUInfo()); // Give this completion a return type. - AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + Results.getCompletionContext().getBaseType(), Builder); // If we need the "super" keyword, add it (plus some spacing). @@ -6088,9 +6134,10 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, } void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { + CodeCompletionContext CCContext(CodeCompletionContext::CCC_Other); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext::CCC_Other); + CCContext); // Figure out where this @synthesize lives. ObjCContainerDecl *Container @@ -6111,11 +6158,12 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) - AddObjCProperties(ClassImpl->getClassInterface(), false, + AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else - AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), + AddObjCProperties(CCContext, + cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); Results.ExitScope(); @@ -7032,7 +7080,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Method->getReturnType(), + AddObjCPassingTypeChunk(Method->getSendResultType() + .stripObjCKindOfType(Context), Method->getObjCDeclQualifier(), Context, Policy, Builder); @@ -7063,6 +7112,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ParamType = (*P)->getType(); else ParamType = (*P)->getOriginalType(); + ParamType = ParamType.substObjCTypeArgs(Context, {}, + ObjCSubstitutionContext::Parameter); AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context, Policy, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6508d6f04bb2..99d4a79c4669 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2577,6 +2577,48 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { return false; } +template<typename T> static bool isExternC(T *D) { return D->isExternC(); } +static bool isExternC(VarTemplateDecl *) { return false; } + +/// \brief Check whether a redeclaration of an entity introduced by a +/// using-declaration is valid, given that we know it's not an overload +/// (nor a hidden tag declaration). +template<typename ExpectedDecl> +static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS, + ExpectedDecl *New) { + // C++11 [basic.scope.declarative]p4: + // Given a set of declarations in a single declarative region, each of + // which specifies the same unqualified name, + // -- they shall all refer to the same entity, or all refer to functions + // and function templates; or + // -- exactly one declaration shall declare a class name or enumeration + // name that is not a typedef name and the other declarations shall all + // refer to the same variable or enumerator, or all refer to functions + // and function templates; in this case the class name or enumeration + // name is hidden (3.3.10). + + // C++11 [namespace.udecl]p14: + // If a function declaration in namespace scope or block scope has the + // same name and the same parameter-type-list as a function introduced + // by a using-declaration, and the declarations do not declare the same + // function, the program is ill-formed. + + auto *Old = dyn_cast<ExpectedDecl>(OldS->getTargetDecl()); + if (Old && + !Old->getDeclContext()->getRedeclContext()->Equals( + New->getDeclContext()->getRedeclContext()) && + !(isExternC(Old) && isExternC(New))) + Old = nullptr; + + if (!Old) { + S.Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); + S.Diag(OldS->getTargetDecl()->getLocation(), diag::note_using_decl_target); + S.Diag(OldS->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + return true; + } + return false; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2603,28 +2645,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, return true; } - // C++11 [namespace.udecl]p14: - // If a function declaration in namespace scope or block scope has the - // same name and the same parameter-type-list as a function introduced - // by a using-declaration, and the declarations do not declare the same - // function, the program is ill-formed. - // Check whether the two declarations might declare the same function. - Old = dyn_cast<FunctionDecl>(Shadow->getTargetDecl()); - if (Old && - !Old->getDeclContext()->getRedeclContext()->Equals( - New->getDeclContext()->getRedeclContext()) && - !(Old->isExternC() && New->isExternC())) - Old = nullptr; - - if (!Old) { - Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); - Diag(Shadow->getTargetDecl()->getLocation(), - diag::note_using_decl_target); - Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + if (checkUsingShadowRedecl<FunctionDecl>(*this, Shadow, New)) return true; - } - OldD = Old; + OldD = Old = cast<FunctionDecl>(Shadow->getTargetDecl()); } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); @@ -3246,9 +3270,16 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, // // Neither C nor C++ requires a diagnostic for this, but we should still try // to diagnose it. - Diag(New->getLocation(), diag::err_redefinition_different_type) - << New->getDeclName() << New->getType() << Old->getType(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(New->getLocation(), New->isThisDeclarationADefinition() + ? diag::err_redefinition_different_type + : diag::err_redeclaration_different_type) + << New->getDeclName() << New->getType() << Old->getType(); + + diag::kind PrevDiag; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) = + getNoteDiagForInvalidRedeclaration(Old, New); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } @@ -3309,8 +3340,19 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (NewTemplate) { OldTemplate = dyn_cast<VarTemplateDecl>(Previous.getFoundDecl()); Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr; - } else + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarTemplateDecl>(*this, Shadow, NewTemplate)) + return New->setInvalidDecl(); + } else { Old = dyn_cast<VarDecl>(Previous.getFoundDecl()); + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarDecl>(*this, Shadow, New)) + return New->setInvalidDecl(); + } } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) @@ -4742,15 +4784,16 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, } } - if (DiagnoseClassNameShadow(DC, NameInfo)) + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType R = TInfo->getType(); + + if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo)) // If this is a typedef, we'll end up spewing multiple diagnostics. - // Just return early; it's safer. + // Just return early; it's safer. If this is a function, let the + // "constructor cannot have a return type" diagnostic handle it. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return nullptr; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType R = TInfo->getType(); - if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); @@ -9785,6 +9828,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { FinalizeVarWithDestructor(var, recordType); } +/// \brief Determines if a variable's alignment is dependent. +static bool hasDependentAlignment(VarDecl *VD) { + if (VD->getType()->isDependentType()) + return true; + for (auto *I : VD->specific_attrs<AlignedAttr>()) + if (I->isAlignmentDependent()) + return true; + return false; +} + /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. void @@ -9798,6 +9851,22 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { checkAttributesAfterMerging(*this, *VD); + // Perform TLS alignment check here after attributes attached to the variable + // which may affect the alignment have been processed. Only perform the check + // if the target has a maximum TLS alignment (zero means no constraints). + if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { + // Protect the check so that it's not performed on dependent types and + // dependent alignments (we can't determine the alignment in that case). + if (VD->getTLSKind() && !hasDependentAlignment(VD)) { + CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); + if (Context.getDeclAlign(VD) > MaxAlignChars) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD + << (unsigned)MaxAlignChars.getQuantity(); + } + } + } + // Static locals inherit dll attributes from their function. if (VD->isStaticLocal()) { if (FunctionDecl *FD = @@ -11258,7 +11327,7 @@ static bool isClassCompatTagKind(TagTypeKind Tag) bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, - const IdentifierInfo &Name) { + const IdentifierInfo *Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the @@ -11287,7 +11356,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); return true; } @@ -11306,7 +11375,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) @@ -11328,7 +11397,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); @@ -11388,6 +11457,27 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, return FixItHint::CreateInsertion(NameLoc, Insertion); } +/// \brief Determine whether a tag originally declared in context \p OldDC can +/// be redeclared with an unqualfied name in \p NewDC (assuming name lookup +/// found a declaration in \p OldDC as a previous decl, perhaps through a +/// using-declaration). +static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, + DeclContext *NewDC) { + OldDC = OldDC->getRedeclContext(); + NewDC = NewDC->getRedeclContext(); + + if (OldDC->Equals(NewDC)) + return true; + + // In MSVC mode, we allow a redeclaration if the contexts are related (either + // encloses the other). + if (S.getLangOpts().MSVCCompat && + (OldDC->Encloses(NewDC) || NewDC->Encloses(OldDC))) + return true; + + return false; +} + /// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a @@ -11559,6 +11649,14 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, goto CreateNewDecl; } } else if (Name) { + // C++14 [class.mem]p14: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // -- every member of class T that is itself a type + if (TUK != TUK_Reference && TUK != TUK_Friend && + DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc))) + return nullptr; + // If this is a named struct, check to see if there was a previous forward // declaration or definition. // FIXME: We're looking into outer scopes here, even when we @@ -11724,8 +11822,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!Previous.empty()) { NamedDecl *PrevDecl = Previous.getFoundDecl(); - NamedDecl *DirectPrevDecl = - getLangOpts().MSVCCompat ? *Previous.begin() : PrevDecl; + NamedDecl *DirectPrevDecl = Previous.getRepresentativeDecl(); // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this @@ -11752,6 +11849,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If this is a redeclaration of a using shadow declaration, it must + // declare a tag in the same context. In MSVC mode, we allow a + // redefinition if either context is within the other. + if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { + auto *OldTag = dyn_cast<TagDecl>(PrevDecl); + if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && + isDeclInScope(Shadow, SearchDC, S, isExplicitSpecialization) && + !(OldTag && isAcceptableTagRedeclContext( + *this, OldTag->getDeclContext(), SearchDC))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) + << 0; + // Recover by ignoring the old declaration. + Previous.clear(); + goto CreateNewDecl; + } + } + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -11763,7 +11880,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, TUK == TUK_Definition, KWLoc, - *Name)) { + Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); @@ -11940,7 +12057,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Invalid = true; // Otherwise, only diagnose if the declaration is in scope. - } else if (!isDeclInScope(PrevDecl, SearchDC, S, + } else if (!isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isExplicitSpecialization)) { // do nothing @@ -13619,12 +13736,9 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type - if (CXXRecordDecl *Record - = dyn_cast<CXXRecordDecl>( - TheEnumDecl->getDeclContext()->getRedeclContext())) - if (!TheEnumDecl->isScoped() && - Record->getIdentifier() && Record->getIdentifier() == Id) - Diag(IdLoc, diag::err_member_name_of_class) << Id; + if (!TheEnumDecl->isScoped()) + DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), + DeclarationNameInfo(Id, IdLoc)); EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index b8d083068593..191dbd05c9bd 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2985,11 +2985,27 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, // specifier shall have no effect // C11 6.7.5p6: // An alignment specification of zero has no effect. - if (!(TmpAttr.isAlignas() && !Alignment) && - !llvm::isPowerOf2_64(Alignment.getZExtValue())) { - Diag(AttrLoc, diag::err_alignment_not_power_of_two) - << E->getSourceRange(); - return; + if (!(TmpAttr.isAlignas() && !Alignment)) { + if(!llvm::isPowerOf2_64(Alignment.getZExtValue())) { + Diag(AttrLoc, diag::err_alignment_not_power_of_two) + << E->getSourceRange(); + return; + } + if (Context.getTargetInfo().isTLSSupported()) { + if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->getTLSKind()) { + CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); + if (Alignment.getSExtValue() > MaxAlignChars.getQuantity()) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)Alignment.getZExtValue() << VD + << (unsigned)MaxAlignChars.getQuantity(); + return; + } + } + } + } + } } // Alignment calculations can wrap around if it's greater than 2**28. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index d0b299877e0f..f42c4b7546ce 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -20,12 +20,15 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "TypeLocBuilder.h" using namespace clang; @@ -461,10 +464,424 @@ static void diagnoseUseOfProtocols(Sema &TheSema, } } +void Sema:: +ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange) { + // Check if a different kind of symbol declared in this scope. + NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name without correcting + // to the class we're defining. + if (TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(SuperName, SuperLoc), + LookupOrdinaryName, TUScope, + NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) + << SuperName << ClassName); + PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); + } + } + + if (declaresSameEntity(PrevDecl, IDecl)) { + Diag(SuperLoc, diag::err_recursive_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + IDecl->setEndOfDefinitionLoc(ClassLoc); + } else { + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + QualType SuperClassType; + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) { + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + SuperClassType = Context.getObjCInterfaceType(SuperClassDecl); + } + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // typedef. If we do, get the underlying class type. + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + SuperClassType = Context.getTypeDeclType(TDecl); + + // This handles the following case: + // @interface NewI @end + // typedef NewI DeprI __attribute__((deprecated("blah"))) + // @interface SI : DeprI /* warn here */ @end + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); + } + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + } + + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (RequireCompleteType(SuperLoc, + SuperClassType, + diag::err_forward_superclass, + SuperClassDecl->getDeclName(), + ClassName, + SourceRange(AtInterfaceLoc, ClassLoc))) { + SuperClassDecl = 0; + SuperClassType = QualType(); + } + } + + if (SuperClassType.isNull()) { + assert(!SuperClassDecl && "Failed to set SuperClassType?"); + return; + } + + // Handle type arguments on the superclass. + TypeSourceInfo *SuperClassTInfo = nullptr; + if (!SuperTypeArgs.empty()) { + TypeResult fullSuperClassType = actOnObjCTypeArgsAndProtocolQualifiers( + S, + SuperLoc, + CreateParsedType(SuperClassType, + nullptr), + SuperTypeArgsRange.getBegin(), + SuperTypeArgs, + SuperTypeArgsRange.getEnd(), + SourceLocation(), + { }, + { }, + SourceLocation()); + if (!fullSuperClassType.isUsable()) + return; + + SuperClassType = GetTypeFromParser(fullSuperClassType.get(), + &SuperClassTInfo); + } + + if (!SuperClassTInfo) { + SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, + SuperLoc); + } + + IDecl->setSuperClass(SuperClassTInfo); + IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd()); + } +} + +DeclResult Sema::actOnObjCTypeParam(Scope *S, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + IdentifierInfo *paramName, + SourceLocation paramLoc, + SourceLocation colonLoc, + ParsedType parsedTypeBound) { + // If there was an explicitly-provided type bound, check it. + TypeSourceInfo *typeBoundInfo = nullptr; + if (parsedTypeBound) { + // The type bound can be any Objective-C pointer type. + QualType typeBound = GetTypeFromParser(parsedTypeBound, &typeBoundInfo); + if (typeBound->isObjCObjectPointerType()) { + // okay + } else if (typeBound->isObjCObjectType()) { + // The user forgot the * on an Objective-C pointer type, e.g., + // "T : NSView". + SourceLocation starLoc = PP.getLocForEndOfToken( + typeBoundInfo->getTypeLoc().getEndLoc()); + Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), + diag::err_objc_type_param_bound_missing_pointer) + << typeBound << paramName + << FixItHint::CreateInsertion(starLoc, " *"); + + // Create a new type location builder so we can update the type + // location information we have. + TypeLocBuilder builder; + builder.pushFullCopy(typeBoundInfo->getTypeLoc()); + + // Create the Objective-C pointer type. + typeBound = Context.getObjCObjectPointerType(typeBound); + ObjCObjectPointerTypeLoc newT + = builder.push<ObjCObjectPointerTypeLoc>(typeBound); + newT.setStarLoc(starLoc); + + // Form the new type source information. + typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound); + } else { + // Not a valid type bound. + Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), + diag::err_objc_type_param_bound_nonobject) + << typeBound << paramName; + + // Forget the bound; we'll default to id later. + typeBoundInfo = nullptr; + } + + // Type bounds cannot have explicit nullability. + if (typeBoundInfo) { + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeBound)) { + // Look at the type location information to find the nullability + // specifier so we can zap it. + SourceLocation nullabilityLoc + = typeBoundInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc + = nullabilityLoc.isValid()? nullabilityLoc + : typeBoundInfo->getTypeLoc().getLocStart(); + Diag(diagLoc, diag::err_type_param_bound_explicit_nullability) + << paramName << typeBoundInfo->getType() + << FixItHint::CreateRemoval(nullabilityLoc); + } + } + } + + // If there was no explicit type bound (or we removed it due to an error), + // use 'id' instead. + if (!typeBoundInfo) { + colonLoc = SourceLocation(); + typeBoundInfo = Context.getTrivialTypeSourceInfo(Context.getObjCIdType()); + } + + // Create the type parameter. + return ObjCTypeParamDecl::Create(Context, CurContext, variance, varianceLoc, + index, paramLoc, paramName, colonLoc, + typeBoundInfo); +} + +ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S, + SourceLocation lAngleLoc, + ArrayRef<Decl *> typeParamsIn, + SourceLocation rAngleLoc) { + // We know that the array only contains Objective-C type parameters. + ArrayRef<ObjCTypeParamDecl *> + typeParams( + reinterpret_cast<ObjCTypeParamDecl * const *>(typeParamsIn.data()), + typeParamsIn.size()); + + // Diagnose redeclarations of type parameters. + // We do this now because Objective-C type parameters aren't pushed into + // scope until later (after the instance variable block), but we want the + // diagnostics to occur right after we parse the type parameter list. + llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams; + for (auto typeParam : typeParams) { + auto known = knownParams.find(typeParam->getIdentifier()); + if (known != knownParams.end()) { + Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl) + << typeParam->getIdentifier() + << SourceRange(known->second->getLocation()); + + typeParam->setInvalidDecl(); + } else { + knownParams.insert(std::make_pair(typeParam->getIdentifier(), typeParam)); + + // Push the type parameter into scope. + PushOnScopeChains(typeParam, S, /*AddToContext=*/false); + } + } + + // Create the parameter list. + return ObjCTypeParamList::create(Context, lAngleLoc, typeParams, rAngleLoc); +} + +void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) { + for (auto typeParam : *typeParamList) { + if (!typeParam->isInvalidDecl()) { + S->RemoveDecl(typeParam); + IdResolver.RemoveDecl(typeParam); + } + } +} + +namespace { + /// The context in which an Objective-C type parameter list occurs, for use + /// in diagnostics. + enum class TypeParamListContext { + ForwardDeclaration, + Definition, + Category, + Extension + }; +} + +/// Check consistency between two Objective-C type parameter lists, e.g., +/// between a category/extension and an \@interface or between an \@class and an +/// \@interface. +static bool checkTypeParamListConsistency(Sema &S, + ObjCTypeParamList *prevTypeParams, + ObjCTypeParamList *newTypeParams, + TypeParamListContext newContext) { + // If the sizes don't match, complain about that. + if (prevTypeParams->size() != newTypeParams->size()) { + SourceLocation diagLoc; + if (newTypeParams->size() > prevTypeParams->size()) { + diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation(); + } else { + diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd()); + } + + S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch) + << static_cast<unsigned>(newContext) + << (newTypeParams->size() > prevTypeParams->size()) + << prevTypeParams->size() + << newTypeParams->size(); + + return true; + } + + // Match up the type parameters. + for (unsigned i = 0, n = prevTypeParams->size(); i != n; ++i) { + ObjCTypeParamDecl *prevTypeParam = prevTypeParams->begin()[i]; + ObjCTypeParamDecl *newTypeParam = newTypeParams->begin()[i]; + + // Check for consistency of the variance. + if (newTypeParam->getVariance() != prevTypeParam->getVariance()) { + if (newTypeParam->getVariance() == ObjCTypeParamVariance::Invariant && + newContext != TypeParamListContext::Definition) { + // When the new type parameter is invariant and is not part + // of the definition, just propagate the variance. + newTypeParam->setVariance(prevTypeParam->getVariance()); + } else if (prevTypeParam->getVariance() + == ObjCTypeParamVariance::Invariant && + !(isa<ObjCInterfaceDecl>(prevTypeParam->getDeclContext()) && + cast<ObjCInterfaceDecl>(prevTypeParam->getDeclContext()) + ->getDefinition() == prevTypeParam->getDeclContext())) { + // When the old parameter is invariant and was not part of the + // definition, just ignore the difference because it doesn't + // matter. + } else { + { + // Diagnose the conflict and update the second declaration. + SourceLocation diagLoc = newTypeParam->getVarianceLoc(); + if (diagLoc.isInvalid()) + diagLoc = newTypeParam->getLocStart(); + + auto diag = S.Diag(diagLoc, + diag::err_objc_type_param_variance_conflict) + << static_cast<unsigned>(newTypeParam->getVariance()) + << newTypeParam->getDeclName() + << static_cast<unsigned>(prevTypeParam->getVariance()) + << prevTypeParam->getDeclName(); + switch (prevTypeParam->getVariance()) { + case ObjCTypeParamVariance::Invariant: + diag << FixItHint::CreateRemoval(newTypeParam->getVarianceLoc()); + break; + + case ObjCTypeParamVariance::Covariant: + case ObjCTypeParamVariance::Contravariant: { + StringRef newVarianceStr + = prevTypeParam->getVariance() == ObjCTypeParamVariance::Covariant + ? "__covariant" + : "__contravariant"; + if (newTypeParam->getVariance() + == ObjCTypeParamVariance::Invariant) { + diag << FixItHint::CreateInsertion(newTypeParam->getLocStart(), + (newVarianceStr + " ").str()); + } else { + diag << FixItHint::CreateReplacement(newTypeParam->getVarianceLoc(), + newVarianceStr); + } + } + } + } + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + + // Override the variance. + newTypeParam->setVariance(prevTypeParam->getVariance()); + } + } + + // If the bound types match, there's nothing to do. + if (S.Context.hasSameType(prevTypeParam->getUnderlyingType(), + newTypeParam->getUnderlyingType())) + continue; + + // If the new type parameter's bound was explicit, complain about it being + // different from the original. + if (newTypeParam->hasExplicitBound()) { + SourceRange newBoundRange = newTypeParam->getTypeSourceInfo() + ->getTypeLoc().getSourceRange(); + S.Diag(newBoundRange.getBegin(), diag::err_objc_type_param_bound_conflict) + << newTypeParam->getUnderlyingType() + << newTypeParam->getDeclName() + << prevTypeParam->hasExplicitBound() + << prevTypeParam->getUnderlyingType() + << (newTypeParam->getDeclName() == prevTypeParam->getDeclName()) + << prevTypeParam->getDeclName() + << FixItHint::CreateReplacement( + newBoundRange, + prevTypeParam->getUnderlyingType().getAsString( + S.Context.getPrintingPolicy())); + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + + // Override the new type parameter's bound type with the previous type, + // so that it's consistent. + newTypeParam->setTypeSourceInfo( + S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + continue; + } + + // The new type parameter got the implicit bound of 'id'. That's okay for + // categories and extensions (overwrite it later), but not for forward + // declarations and @interfaces, because those must be standalone. + if (newContext == TypeParamListContext::ForwardDeclaration || + newContext == TypeParamListContext::Definition) { + // Diagnose this problem for forward declarations and definitions. + SourceLocation insertionLoc + = S.PP.getLocForEndOfToken(newTypeParam->getLocation()); + std::string newCode + = " : " + prevTypeParam->getUnderlyingType().getAsString( + S.Context.getPrintingPolicy()); + S.Diag(newTypeParam->getLocation(), + diag::err_objc_type_param_bound_missing) + << prevTypeParam->getUnderlyingType() + << newTypeParam->getDeclName() + << (newContext == TypeParamListContext::ForwardDeclaration) + << FixItHint::CreateInsertion(insertionLoc, newCode); + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + } + + // Update the new type parameter's bound to match the previous one. + newTypeParam->setTypeSourceInfo( + S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + } + + return false; +} + Decl *Sema:: -ActOnStartClassInterface(SourceLocation AtInterfaceLoc, +ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { @@ -498,10 +915,50 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, ClassName = PrevIDecl->getIdentifier(); } + // If there was a forward declaration with type parameters, check + // for consistency. + if (PrevIDecl) { + if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) { + if (typeParamList) { + // Both have type parameter lists; check for consistency. + if (checkTypeParamListConsistency(*this, prevTypeParamList, + typeParamList, + TypeParamListContext::Definition)) { + typeParamList = nullptr; + } + } else { + Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first) + << ClassName; + Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl) + << ClassName; + + // Clone the type parameter list. + SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams; + for (auto typeParam : *prevTypeParamList) { + clonedTypeParams.push_back( + ObjCTypeParamDecl::Create( + Context, + CurContext, + typeParam->getVariance(), + SourceLocation(), + typeParam->getIndex(), + SourceLocation(), + typeParam->getIdentifier(), + SourceLocation(), + Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType()))); + } + + typeParamList = ObjCTypeParamList::create(Context, + SourceLocation(), + clonedTypeParams, + SourceLocation()); + } + } + } + ObjCInterfaceDecl *IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName, - PrevIDecl, ClassLoc); - + typeParamList, PrevIDecl, ClassLoc); if (PrevIDecl) { // Class already seen. Was it a definition? if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) { @@ -522,84 +979,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->startDefinition(); if (SuperName) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, - LookupOrdinaryName); - - if (!PrevDecl) { - // Try to correct for a typo in the superclass name without correcting - // to the class we're defining. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), - LookupOrdinaryName, TUScope, nullptr, - llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), - CTK_ErrorRecovery)) { - diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) - << SuperName << ClassName); - PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); - } - } - - if (declaresSameEntity(PrevDecl, IDecl)) { - Diag(SuperLoc, diag::err_recursive_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - IDecl->setEndOfDefinitionLoc(ClassLoc); - } else { - ObjCInterfaceDecl *SuperClassDecl = - dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - - // Diagnose availability in the context of the @interface. - ContextRAII SavedContext(*this, IDecl); - // Diagnose classes that inherit from deprecated classes. - if (SuperClassDecl) - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - - if (PrevDecl && !SuperClassDecl) { - // The previous declaration was not a class decl. Check if we have a - // typedef. If we do, get the underlying class type. - if (const TypedefNameDecl *TDecl = - dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - QualType T = TDecl->getUnderlyingType(); - if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); - // This handles the following case: - // @interface NewI @end - // typedef NewI DeprI __attribute__((deprecated("blah"))) - // @interface SI : DeprI /* warn here */ @end - (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); - } - } - } + // Diagnose availability in the context of the @interface. + ContextRAII SavedContext(*this, IDecl); - // This handles the following case: - // - // typedef int SuperClass; - // @interface MyClass : SuperClass {} @end - // - if (!SuperClassDecl) { - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } - } - - if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - if (!SuperClassDecl) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (RequireCompleteType(SuperLoc, - Context.getObjCInterfaceType(SuperClassDecl), - diag::err_forward_superclass, - SuperClassDecl->getDeclName(), - ClassName, - SourceRange(AtInterfaceLoc, ClassLoc))) { - SuperClassDecl = nullptr; - } - } - IDecl->setSuperClass(SuperClassDecl); - IDecl->setSuperClassLoc(SuperLoc); - IDecl->setEndOfDefinitionLoc(SuperLoc); - } + ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, + ClassName, ClassLoc, + SuperName, SuperLoc, SuperTypeArgs, + SuperTypeArgsRange); } else { // we have a root class. IDecl->setEndOfDefinitionLoc(ClassLoc); } @@ -846,6 +1232,400 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, } } +namespace { +// Callback to only accept typo corrections that are either +// Objective-C protocols or valid Objective-C type arguments. +class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { + ASTContext &Context; + Sema::LookupNameKind LookupKind; + public: + ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context, + Sema::LookupNameKind lookupKind) + : Context(context), LookupKind(lookupKind) { } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + // If we're allowed to find protocols and we have a protocol, accept it. + if (LookupKind != Sema::LookupOrdinaryName) { + if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>()) + return true; + } + + // If we're allowed to find type names and we have one, accept it. + if (LookupKind != Sema::LookupObjCProtocolName) { + // If we have a type declaration, we might accept this result. + if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) { + // If we found a tag declaration outside of C++, skip it. This + // can happy because we look for any name when there is no + // bias to protocol or type names. + if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus) + return false; + + // Make sure the type is something we would accept as a type + // argument. + auto type = Context.getTypeDeclType(typeDecl); + if (type->isObjCObjectPointerType() || + type->isBlockPointerType() || + type->isDependentType() || + type->isObjCObjectType()) + return true; + + return false; + } + + // If we have an Objective-C class type, accept it; there will + // be another fix to add the '*'. + if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>()) + return true; + + return false; + } + + return false; + } +}; +} // end anonymous namespace + +void Sema::actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + ParsedType baseType, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SourceLocation &protocolRAngleLoc, + bool warnOnIncompleteProtocols) { + // Local function that updates the declaration specifiers with + // protocol information. + unsigned numProtocolsResolved = 0; + auto resolvedAsProtocols = [&] { + assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols"); + + // Determine whether the base type is a parameterized class, in + // which case we want to warn about typos such as + // "NSArray<NSObject>" (that should be NSArray<NSObject *>). + ObjCInterfaceDecl *baseClass = nullptr; + QualType base = GetTypeFromParser(baseType, nullptr); + bool allAreTypeNames = false; + SourceLocation firstClassNameLoc; + if (!base.isNull()) { + if (const auto *objcObjectType = base->getAs<ObjCObjectType>()) { + baseClass = objcObjectType->getInterface(); + if (baseClass) { + if (auto typeParams = baseClass->getTypeParamList()) { + if (typeParams->size() == numProtocolsResolved) { + // Note that we should be looking for type names, too. + allAreTypeNames = true; + } + } + } + } + } + + for (unsigned i = 0, n = protocols.size(); i != n; ++i) { + ObjCProtocolDecl *&proto + = reinterpret_cast<ObjCProtocolDecl *&>(protocols[i]); + // For an objc container, delay protocol reference checking until after we + // can set the objc decl as the availability context, otherwise check now. + if (!warnOnIncompleteProtocols) { + (void)DiagnoseUseOfDecl(proto, identifierLocs[i]); + } + + // If this is a forward protocol declaration, get its definition. + if (!proto->isThisDeclarationADefinition() && proto->getDefinition()) + proto = proto->getDefinition(); + + // If this is a forward declaration and we are supposed to warn in this + // case, do it. + // FIXME: Recover nicely in the hidden case. + ObjCProtocolDecl *forwardDecl = nullptr; + if (warnOnIncompleteProtocols && + NestedProtocolHasNoDefinition(proto, forwardDecl)) { + Diag(identifierLocs[i], diag::warn_undef_protocolref) + << proto->getDeclName(); + Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined) + << forwardDecl; + } + + // If everything this far has been a type name (and we care + // about such things), check whether this name refers to a type + // as well. + if (allAreTypeNames) { + if (auto *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName)) { + if (isa<ObjCInterfaceDecl>(decl)) { + if (firstClassNameLoc.isInvalid()) + firstClassNameLoc = identifierLocs[i]; + } else if (!isa<TypeDecl>(decl)) { + // Not a type. + allAreTypeNames = false; + } + } else { + allAreTypeNames = false; + } + } + } + + // All of the protocols listed also have type names, and at least + // one is an Objective-C class name. Check whether all of the + // protocol conformances are declared by the base class itself, in + // which case we warn. + if (allAreTypeNames && firstClassNameLoc.isValid()) { + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols; + Context.CollectInheritedProtocols(baseClass, knownProtocols); + bool allProtocolsDeclared = true; + for (auto proto : protocols) { + if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) { + allProtocolsDeclared = false; + break; + } + } + + if (allProtocolsDeclared) { + Diag(firstClassNameLoc, diag::warn_objc_redundant_qualified_class_type) + << baseClass->getDeclName() << SourceRange(lAngleLoc, rAngleLoc) + << FixItHint::CreateInsertion( + PP.getLocForEndOfToken(firstClassNameLoc), " *"); + } + } + + protocolLAngleLoc = lAngleLoc; + protocolRAngleLoc = rAngleLoc; + assert(protocols.size() == identifierLocs.size()); + }; + + // Attempt to resolve all of the identifiers as protocols. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], identifierLocs[i]); + protocols.push_back(proto); + if (proto) + ++numProtocolsResolved; + } + + // If all of the names were protocols, these were protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Attempt to resolve all of the identifiers as type names or + // Objective-C class names. The latter is technically ill-formed, + // but is probably something like \c NSArray<NSView *> missing the + // \c*. + typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> TypeOrClassDecl; + SmallVector<TypeOrClassDecl, 4> typeDecls; + unsigned numTypeDeclsResolved = 0; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName); + if (!decl) { + typeDecls.push_back(TypeOrClassDecl()); + continue; + } + + if (auto typeDecl = dyn_cast<TypeDecl>(decl)) { + typeDecls.push_back(typeDecl); + ++numTypeDeclsResolved; + continue; + } + + if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) { + typeDecls.push_back(objcClass); + ++numTypeDeclsResolved; + continue; + } + + typeDecls.push_back(TypeOrClassDecl()); + } + + AttributeFactory attrFactory; + + // Local function that forms a reference to the given type or + // Objective-C class declaration. + auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation loc) + -> TypeResult { + // Form declaration specifiers. They simply refer to the type. + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + QualType type; + if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>()) + type = Context.getTypeDeclType(actualTypeDecl); + else + type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl *>()); + TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, loc); + ParsedType parsedType = CreateParsedType(type, parsedTSInfo); + DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + // Use the identifier location for the type source range. + DS.SetRangeStart(loc); + DS.SetRangeEnd(loc); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + // If we have a typedef of an Objective-C class type that is missing a '*', + // add the '*'. + if (type->getAs<ObjCInterfaceType>()) { + SourceLocation starLoc = PP.getLocForEndOfToken(loc); + ParsedAttributes parsedAttrs(attrFactory); + D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, + SourceLocation(), + SourceLocation(), + SourceLocation(), + SourceLocation()), + parsedAttrs, + starLoc); + + // Diagnose the missing '*'. + Diag(loc, diag::err_objc_type_arg_missing_star) + << type + << FixItHint::CreateInsertion(starLoc, " *"); + } + + // Convert this to a type. + return ActOnTypeName(S, D); + }; + + // Local function that updates the declaration specifiers with + // type argument information. + auto resolvedAsTypeDecls = [&] { + // We did not resolve these as protocols. + protocols.clear(); + + assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl"); + // Map type declarations to type arguments. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // Map type reference to a type. + TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]); + if (!type.isUsable()) { + typeArgs.clear(); + return; + } + + typeArgs.push_back(type.get()); + } + + typeArgsLAngleLoc = lAngleLoc; + typeArgsRAngleLoc = rAngleLoc; + }; + + // If all of the identifiers can be resolved as type names or + // Objective-C class names, we have type arguments. + if (numTypeDeclsResolved == identifiers.size()) + return resolvedAsTypeDecls(); + + // Error recovery: some names weren't found, or we have a mix of + // type and protocol names. Go resolve all of the unresolved names + // and complain if we can't find a consistent answer. + LookupNameKind lookupKind = LookupAnyName; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // If we already have a protocol or type. Check whether it is the + // right thing. + if (protocols[i] || typeDecls[i]) { + // If we haven't figured out whether we want types or protocols + // yet, try to figure it out from this name. + if (lookupKind == LookupAnyName) { + // If this name refers to both a protocol and a type (e.g., \c + // NSObject), don't conclude anything yet. + if (protocols[i] && typeDecls[i]) + continue; + + // Otherwise, let this name decide whether we'll be correcting + // toward types or protocols. + lookupKind = protocols[i] ? LookupObjCProtocolName + : LookupOrdinaryName; + continue; + } + + // If we want protocols and we have a protocol, there's nothing + // more to do. + if (lookupKind == LookupObjCProtocolName && protocols[i]) + continue; + + // If we want types and we have a type declaration, there's + // nothing more to do. + if (lookupKind == LookupOrdinaryName && typeDecls[i]) + continue; + + // We have a conflict: some names refer to protocols and others + // refer to types. + Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) + << (protocols[i] != nullptr) + << identifiers[i] + << identifiers[0] + << SourceRange(identifierLocs[0]); + + protocols.clear(); + typeArgs.clear(); + return; + } + + // Perform typo correction on the name. + TypoCorrection corrected = CorrectTypo( + DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S, + nullptr, + llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, + lookupKind), + CTK_ErrorRecovery); + if (corrected) { + // Did we find a protocol? + if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << identifiers[i]); + lookupKind = LookupObjCProtocolName; + protocols[i] = proto; + ++numProtocolsResolved; + continue; + } + + // Did we find a type? + if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_typename_suggest) + << identifiers[i]); + lookupKind = LookupOrdinaryName; + typeDecls[i] = typeDecl; + ++numTypeDeclsResolved; + continue; + } + + // Did we find an Objective-C class? + if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_type_or_class_name_suggest) + << identifiers[i] << true); + lookupKind = LookupOrdinaryName; + typeDecls[i] = objcClass; + ++numTypeDeclsResolved; + continue; + } + } + + // We couldn't find anything. + Diag(identifierLocs[i], + (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing + : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol + : diag::err_unknown_typename)) + << identifiers[i]; + protocols.clear(); + typeArgs.clear(); + return; + } + + // If all of the names were (corrected to) protocols, these were + // protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Otherwise, all of the names were (corrected to) types. + assert(numTypeDeclsResolved == identifiers.size() && "Not all types?"); + return resolvedAsTypeDecls(); +} + /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -906,6 +1686,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, Decl *Sema:: ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, @@ -925,7 +1706,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // the enclosing method declarations. We mark the decl invalid // to make it clear that this isn't a valid AST. CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName,IDecl); + ClassLoc, CategoryLoc, CategoryName, + IDecl, typeParamList); CDecl->setInvalidDecl(); CurContext->addDecl(CDecl); @@ -951,8 +1733,28 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } } + // If we have a type parameter list, check it. + if (typeParamList) { + if (auto prevTypeParamList = IDecl->getTypeParamList()) { + if (checkTypeParamListConsistency(*this, prevTypeParamList, typeParamList, + CategoryName + ? TypeParamListContext::Category + : TypeParamListContext::Extension)) + typeParamList = nullptr; + } else { + Diag(typeParamList->getLAngleLoc(), + diag::err_objc_parameterized_category_nonclass) + << (CategoryName != nullptr) + << ClassName + << typeParamList->getSourceRange(); + + typeParamList = nullptr; + } + } + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName, IDecl); + ClassLoc, CategoryLoc, CategoryName, IDecl, + typeParamList); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -987,7 +1789,8 @@ Decl *Sema::ActOnStartCategoryImplementation( // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc, ClassLoc, CatLoc, - CatName, IDecl); + CatName, IDecl, + /*typeParamList=*/nullptr); CatIDecl->setImplicit(); } } @@ -1101,12 +1904,14 @@ Decl *Sema::ActOnStartClassImplementation( // FIXME: Do we support attributes on the @implementation? If so we should // copy them over. IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, - ClassName, /*PrevDecl=*/nullptr, ClassLoc, + ClassName, /*typeParamList=*/nullptr, + /*PrevDecl=*/nullptr, ClassLoc, true); IDecl->startDefinition(); if (SDecl) { - IDecl->setSuperClass(SDecl); - IDecl->setSuperClassLoc(SuperClassLoc); + IDecl->setSuperClass(Context.getTrivialTypeSourceInfo( + Context.getObjCInterfaceType(SDecl), + SuperClassLoc)); IDecl->setEndOfDefinitionLoc(SuperClassLoc); } else { IDecl->setEndOfDefinitionLoc(ClassLoc); @@ -2083,6 +2888,7 @@ Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, + ArrayRef<ObjCTypeParamList *> TypeParamLists, unsigned NumElts) { SmallVector<Decl *, 8> DeclsInGroup; for (unsigned i = 0; i != NumElts; ++i) { @@ -2137,9 +2943,33 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, ClassName = PrevIDecl->getIdentifier(); } + // If this forward declaration has type parameters, compare them with the + // type parameters of the previous declaration. + ObjCTypeParamList *TypeParams = TypeParamLists[i]; + if (PrevIDecl && TypeParams) { + if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) { + // Check for consistency with the previous declaration. + if (checkTypeParamListConsistency( + *this, PrevTypeParams, TypeParams, + TypeParamListContext::ForwardDeclaration)) { + TypeParams = nullptr; + } + } else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) { + // The @interface does not have type parameters. Complain. + Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class) + << ClassName + << TypeParams->getSourceRange(); + Diag(Def->getLocation(), diag::note_defined_here) + << ClassName; + + TypeParams = nullptr; + } + } + ObjCInterfaceDecl *IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, - ClassName, PrevIDecl, IdentLocs[i]); + ClassName, TypeParams, PrevIDecl, + IdentLocs[i]); IDecl->setAtEndRange(IdentLocs[i]); PushOnScopeChains(IDecl, TUScope); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 2e3e63e00a32..094187025df0 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -397,7 +397,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // - both are dynamic-exception-specifications that have the same set of // adjusted types. // - // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is + // C++0x [except.spec]p12: An exception-specification is non-throwing if it is // of the form throw(), noexcept, or noexcept(constant-expression) where the // constant-expression yields true. // diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c023c8523a39..1ae983cad227 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2466,8 +2466,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); ObjCIvarRefExpr *Result = new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(), - SelfExpr.get(), true, true); + ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, + IV->getLocation(), SelfExpr.get(), true, true); if (getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -5185,17 +5185,17 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } /// Do an explicit extend of the given block pointer if we're in ARC. -static void maybeExtendBlockObject(Sema &S, ExprResult &E) { +void Sema::maybeExtendBlockObject(ExprResult &E) { assert(E.get()->getType()->isBlockPointerType()); assert(E.get()->isRValue()); // Only do this in an r-value context. - if (!S.getLangOpts().ObjCAutoRefCount) return; + if (!getLangOpts().ObjCAutoRefCount) return; - E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + E = ImplicitCastExpr::Create(Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), /*base path*/ nullptr, VK_RValue); - S.ExprNeedsCleanups = true; + ExprNeedsCleanups = true; } /// Prepare a conversion of the given expression to an ObjC object @@ -5205,7 +5205,7 @@ CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { if (type->isObjCObjectPointerType()) { return CK_BitCast; } else if (type->isBlockPointerType()) { - maybeExtendBlockObject(*this, E); + maybeExtendBlockObject(E); return CK_BlockPointerToObjCPointerCast; } else { assert(type->isPointerType()); @@ -5247,7 +5247,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { return CK_BitCast; if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; - maybeExtendBlockObject(*this, Src); + maybeExtendBlockObject(Src); return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; @@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return ResultTy; } -/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or -/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally -/// implements 'NSObject' and/or NSCopying' protocols (and nothing else). -static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) { - if (QT->isObjCIdType()) - return true; - - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); - if (!OPT) - return false; - - if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() != &C.Idents.get("NSObject")) - return false; - - ObjCProtocolDecl* PNSCopying = - S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation()); - ObjCProtocolDecl* PNSObject = - S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation()); - - for (auto *Proto : OPT->quals()) { - if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) || - (PNSObject && declaresSameEntity(Proto, PNSObject))) - ; - else - return false; - } - return true; -} - /// \brief Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, @@ -6303,7 +6273,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. - if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { + if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) { + // Nothing more to do. + } else if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; @@ -6317,10 +6290,7 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else if (!(compositeType = - Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) - ; - else { + } else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -7008,9 +6978,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Only under strict condition T^ is compatible with an Objective-C pointer. - if (RHSType->isBlockPointerType() && - isObjCPtrBlockCompatible(*this, Context, LHSType)) { - maybeExtendBlockObject(*this, RHS); + if (RHSType->isBlockPointerType() && + LHSType->isBlockCompatibleObjCPointerType(Context)) { + maybeExtendBlockObject(RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -7937,9 +7907,19 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // representable in the result type, so never warn for those. llvm::APSInt Left; if (LHS.get()->isValueDependent() || - !LHS.get()->isIntegerConstantExpr(Left, S.Context) || - LHSType->hasUnsignedIntegerRepresentation()) + LHSType->hasUnsignedIntegerRepresentation() || + !LHS.get()->EvaluateAsInt(Left, S.Context)) return; + + // If LHS does not have a signed type and non-negative value + // then, the behavior is undefined. Warn about it. + if (Left.isNegative()) { + S.DiagRuntimeBehavior(Loc, LHS.get(), + S.PDiag(diag::warn_shift_lhs_negative) + << LHS.get()->getSourceRange()); + return; + } + llvm::APInt ResultBits = static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); if (LeftBits.uge(ResultBits)) @@ -8209,9 +8189,6 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { // Get the LHS object's interface type. QualType InterfaceType = Type->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - InterfaceType->getAsObjCQualifiedInterfaceType()) - InterfaceType = iQFaceTy->getBaseType(); // If the RHS isn't an Objective-C object, bail out. if (!RHS->getType()->isObjCObjectPointerType()) @@ -12556,6 +12533,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, // By default, capture variables by reference. bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). + if (S.getLangOpts().OpenMP && S.IsOpenMPCapturedVar(Var)) + DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = S.Context.getLValueReferenceType(DeclRefType); Expr *CopyExpr = nullptr; if (BuildAndDiagnose) { @@ -12789,6 +12768,7 @@ bool Sema::tryCaptureVariable( if (RSI->CapRegionKind == CR_OpenMP) { if (isOpenMPPrivateVar(Var, OpenMPLevel)) { Nested = true; + DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); break; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index e421349338b1..a9f1919e18a8 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1378,7 +1378,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr( - IV, IV->getType(), MemberLoc, OpLoc, BaseExpr.get(), IsArrow); + IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(), + IsArrow); if (S.getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c52b6f55a957..6cd062621951 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ ObjCInterfaceDecl::Create (Context, Context.getTranslationUnitDecl(), SourceLocation(), NSIdent, - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); Ty = Context.getObjCInterfaceType(NSStringIDecl); Context.setObjCNSStringType(Ty); } @@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.NSNumberDecl = ObjCInterfaceDecl::Create(CX, CX.getTranslationUnitDecl(), SourceLocation(), NSNumberId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { // Otherwise, require a declaration of NSNumber. S.Diag(Loc, diag::err_undeclared_nsnumber); @@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { NSStringDecl = ObjCInterfaceDecl::Create(Context, TU, SourceLocation(), NSStringId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { Diag(SR.getBegin(), diag::err_undeclared_nsstring); return ExprError(); @@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { DeclContext *TU = Context.getTranslationUnitDecl(); NSValueDecl = ObjCInterfaceDecl::Create(Context, TU, SourceLocation(), NSValueId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { // Otherwise, require a declaration of NSValue. Diag(SR.getBegin(), diag::err_undeclared_nsvalue); @@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context.getTranslationUnitDecl(), SourceLocation(), NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray), - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); if (!NSArrayDecl) { Diag(SR.getBegin(), diag::err_undeclared_nsarray); @@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, Context.getTranslationUnitDecl(), SourceLocation(), NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary), - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); if (!NSDictionaryDecl) { Diag(SR.getBegin(), diag::err_undeclared_nsdictionary); @@ -956,8 +959,11 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ,1); + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl**) PQ, + 1), + false); QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); } } @@ -1276,7 +1282,7 @@ static QualType getBaseMessageSendResultType(Sema &S, bool isSuperMessage) { assert(Method && "Must have a method"); if (!Method->hasRelatedResultType()) - return Method->getSendResultType(); + return Method->getSendResultType(ReceiverType); ASTContext &Context = S.Context; @@ -1284,7 +1290,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // result type to the returned result. auto transferNullability = [&](QualType type) -> QualType { // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType()->getNullability(Context)){ + if (auto nullability = Method->getSendResultType(ReceiverType) + ->getNullability(Context)){ // Strip off any outer nullability sugar from the provided type. (void)AttributedType::stripOuterNullability(type); @@ -1303,7 +1310,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is super, T is a pointer to the class of the // enclosing method definition @@ -1317,14 +1325,14 @@ static QualType getBaseMessageSendResultType(Sema &S, } // - if the receiver is the name of a class U, T is a pointer to U - if (ReceiverType->getAs<ObjCInterfaceType>() || - ReceiverType->isObjCQualifiedInterfaceType()) + if (ReceiverType->getAsObjCInterfaceType()) return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise @@ -1587,6 +1595,10 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, return false; } + // Compute the set of type arguments to be substituted into each parameter + // type. + Optional<ArrayRef<QualType>> typeArgs + = ReceiverType->getObjCSubstitutions(Method->getDeclContext()); bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { // We can't do any type-checking on a type-dependent argument. @@ -1620,18 +1632,37 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, continue; } + QualType origParamType = param->getType(); + QualType paramType = param->getType(); + if (typeArgs) + paramType = paramType.substObjCTypeArgs( + Context, + *typeArgs, + ObjCSubstitutionContext::Parameter); + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), - param->getType(), + paramType, diag::err_call_incomplete_argument, argExpr)) return true; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - param); + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, param, paramType); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); if (ArgE.isInvalid()) IsError = true; - else + else { Args[i] = ArgE.getAs<Expr>(); + + // If we are type-erasing a block to a block-compatible + // Objective-C pointer type, we may need to extend the lifetime + // of the block object. + if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() && + origParamType->isBlockCompatibleObjCPointerType(Context)) { + ExprResult arg = Args[i]; + maybeExtendBlockObject(arg); + Args[i] = arg.get(); + } + } } // Promote additional arguments to variadic methods. @@ -1899,27 +1930,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); - bool IsSuper = false; + QualType SuperType; if (!IFace) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { - IsSuper = true; - if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + if (auto classDecl = CurMethod->getClassInterface()) { + SuperType = QualType(classDecl->getSuperClassType(), 0); if (CurMethod->isInstanceMethod()) { - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + if (SuperType.isNull()) { // The current class does not have a superclass. Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) - << Class->getIdentifier(); + << CurMethod->getClassInterface()->getIdentifier(); return ExprError(); } - QualType T = Context.getObjCInterfaceType(Super); - T = Context.getObjCObjectPointerType(T); + QualType T = Context.getObjCObjectPointerType(SuperType); - return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(), /*BaseExpr*/nullptr, SourceLocation()/*OpLoc*/, &propertyName, @@ -1929,7 +1957,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Otherwise, if this is a class method, try dispatching to our // superclass. - IFace = Class->getSuperClass(); + IFace = CurMethod->getClassInterface()->getSuperClass(); } } } @@ -1959,7 +1987,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterSelector(PP.getIdentifierTable(), - PP.getSelectorTable(), + PP.getSelectorTable(), &propertyName); ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); @@ -1976,11 +2004,11 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, return ExprError(); if (Getter || Setter) { - if (IsSuper) + if (!SuperType.isNull()) return new (Context) ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, propertyNameLoc, receiverNameLoc, - Context.getObjCInterfaceType(IFace)); + SuperType); return new (Context) ObjCPropertyRefExpr( Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, @@ -2127,8 +2155,8 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return ExprError(); } - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + QualType SuperTy(Class->getSuperClassType(), 0); + if (SuperTy.isNull()) { // The current class does not have a superclass. Diag(SuperLoc, diag::error_root_class_cannot_use_super) << Class->getIdentifier(); @@ -2143,7 +2171,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, if (Method->isInstanceMethod()) { // Since we are in an instance method, this is an instance // message to the superclass instance. - QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(nullptr, SuperTy, SuperLoc, Sel, /*Method=*/nullptr, @@ -2153,7 +2180,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // Since we are in a class method, this is a class message to // the superclass. return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr, - Context.getObjCInterfaceType(Super), + SuperTy, SuperLoc, Sel, /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc, Args); } @@ -2594,35 +2621,41 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // of the more detailed type-checking on the receiver. if (!Method) { - // Handle messages to id. - bool receiverIsId = ReceiverType->isObjCIdType(); - if (receiverIsId || ReceiverType->isBlockPointerType() || + // Handle messages to id and __kindof types (where we use the + // global method pool). + // FIXME: The type bound is currently ignored by lookup in the + // global pool. + const ObjCObjectType *typeBound = nullptr; + bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context, + typeBound); + if (receiverIsIdLike || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), - receiverIsId); + receiverIsIdLike); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc,RBracLoc), - receiverIsId); + receiverIsIdLike); if (Method) { if (ObjCMethodDecl *BestMethod = SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) Method = BestMethod; if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - receiverIsId)) { + receiverIsIdLike)) { DiagnoseUseOfDecl(Method, SelLoc); } } - } else if (ReceiverType->isObjCClassType() || + } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. // We allow sending a message to a qualified Class ("Class<foo>"), which // is ok as long as one of the protocols implements the selector (if not, // warn). - if (const ObjCObjectPointerType *QClassTy - = ReceiverType->getAsObjCQualifiedClassType()) { + if (!ReceiverType->isObjCClassOrClassKindOfType()) { + const ObjCObjectPointerType *QClassTy + = ReceiverType->getAsObjCQualifiedClassType(); // Search protocols for class methods. Method = LookupMethodInQualifiedType(Sel, QClassTy, false); if (!Method) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 0f88abcdf9ea..f139c83c734b 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1157,7 +1157,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *IvarRefExpr = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ExprResult Res = PerformCopyInitialization( @@ -1207,7 +1209,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *lhs = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 867cb9f3c830..4030d9e66e02 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -21,6 +21,7 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -472,7 +473,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if (D->getTLSKind() != VarDecl::TLS_None || + if ((D->getTLSKind() != VarDecl::TLS_None && + !(D->hasAttr<OMPThreadPrivateDeclAttr>() && + SemaRef.getLangOpts().OpenMPUseTLS && + SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() && !D->isLocalVarDecl())) { addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), @@ -959,8 +963,12 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { continue; } - // Check if this is a TLS variable. - if (VD->getTLSKind() != VarDecl::TLS_None || + // Check if this is a TLS variable. If TLS is not being supported, produce + // the corresponding diagnostic. + if ((VD->getTLSKind() != VarDecl::TLS_None && + !(VD->hasAttr<OMPThreadPrivateDeclAttr>() && + getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported())) || (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) { Diag(ILoc, diag::err_omp_var_thread_local) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a0fdcd78e596..31f581dc15b6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2152,23 +2152,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, FromObjCPtr->getPointeeType())) return false; - // Check for compatible - // Objective C++: We're able to convert between "id" or "Class" and a - // pointer to any interface (in both directions). - if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); - return true; - } - // Conversions with Objective-C's id<...>. - if ((FromObjCPtr->isObjCQualifiedIdType() || - ToObjCPtr->isObjCQualifiedIdType()) && - Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, - /*compare=*/false)) { - ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); - return true; - } - // Objective C++: We're able to convert from a pointer to an - // interface to a pointer to a different interface. + // Conversion between Objective-C pointers. if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType(); const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 3e465af9632c..fec97488f531 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -689,15 +689,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingGetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); if (!Getter->isImplicit()) S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true); // Build a message-send. @@ -730,21 +722,17 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingSetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); // Use assignment constraints when possible; they give us better // diagnostics. "When possible" basically means anything except a // C++ class type. if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) { - QualType paramType = (*Setter->param_begin())->getType(); + QualType paramType = (*Setter->param_begin())->getType() + .substObjCMemberType( + receiverType, + Setter->getDeclContext(), + ObjCSubstitutionContext::Parameter); if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) { ExprResult opResult = op; Sema::AssignConvertType assignResult @@ -819,7 +807,9 @@ ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { // As a special case, if the method returns 'id', try to get // a better type from the property. if (RefExpr->isExplicitProperty() && result.get()->isRValue()) { - QualType propType = RefExpr->getExplicitProperty()->getType(); + QualType receiverType = RefExpr->getReceiverType(S.Context); + QualType propType = RefExpr->getExplicitProperty() + ->getUsageType(receiverType); if (result.get()->getType()->isObjCIdType()) { if (const ObjCObjectPointerType *ptr = propType->getAs<ObjCObjectPointerType>()) { @@ -1119,9 +1109,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = S.CheckSubscriptingKind(RefExpr->getKeyExpr()); @@ -1228,9 +1215,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6fca974d5b36..c4f6fd8df1c4 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -25,6 +25,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -3649,6 +3650,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, else Diag(TryLoc, diag::err_seh_try_outside_functions); + // Reject __try on unsupported targets. + if (!Context.getTargetInfo().isSEHTrySupported()) + Diag(TryLoc, diag::err_seh_try_unsupported); + return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index d19d8819d8e2..8e3e89f1e572 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -254,17 +254,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, << Info.getConstraintStr() << InputExpr->getSourceRange()); } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { - llvm::APSInt Result; - if (!InputExpr->EvaluateAsInt(Result, Context)) - return StmtError( - Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - if (Result.slt(Info.getImmConstantMin()) || - Result.sgt(Info.getImmConstantMax())) - return StmtError(Diag(InputExpr->getLocStart(), - diag::err_invalid_asm_value_for_constraint) - << Result.toString(10) << Info.getConstraintStr() - << InputExpr->getSourceRange()); + if (!InputExpr->isValueDependent()) { + llvm::APSInt Result; + if (!InputExpr->EvaluateAsInt(Result, Context)) + return StmtError( + Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) + << Info.getConstraintStr() << InputExpr->getSourceRange()); + if (Result.slt(Info.getImmConstantMin()) || + Result.sgt(Info.getImmConstantMax())) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_invalid_asm_value_for_constraint) + << Result.toString(10) << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f4740a5cd855..035c37cfe6e9 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -893,6 +893,16 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; + + // C++14 [class.mem]p14: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // -- every member template of class T + if (TUK != TUK_Friend && + DiagnoseClassNameShadow(SemanticContext, + DeclarationNameInfo(Name, NameLoc))) + return true; + LookupName(Previous, S); } @@ -947,8 +957,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Check that the chosen semantic context doesn't already contain a // declaration of this name as a non-tag type. - LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); + Previous.clear(LookupOrdinaryName); DeclContext *LookupContext = SemanticContext; while (LookupContext->isTransparentContext()) LookupContext = LookupContext->getLookupParent(); @@ -962,9 +971,25 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } } else if (PrevDecl && - !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid())) + !isDeclInScope(Previous.getRepresentativeDecl(), SemanticContext, + S, SS.isValid())) PrevDecl = PrevClassTemplate = nullptr; + if (auto *Shadow = dyn_cast_or_null<UsingShadowDecl>( + PrevDecl ? Previous.getRepresentativeDecl() : nullptr)) { + if (SS.isEmpty() && + !(PrevClassTemplate && + PrevClassTemplate->getDeclContext()->getRedeclContext()->Equals( + SemanticContext->getRedeclContext()))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + // Recover by ignoring the old declaration. + PrevDecl = PrevClassTemplate = nullptr; + } + } + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -983,7 +1008,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, - TUK == TUK_Definition, KWLoc, *Name)) { + TUK == TUK_Definition, KWLoc, Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -2285,7 +2310,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, assert(Id && "templated class must have an identifier"); if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, - TagLoc, *Id)) { + TagLoc, Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); @@ -6174,7 +6199,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, TUK == TUK_Definition, KWLoc, - *ClassTemplate->getIdentifier())) { + ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate << FixItHint::CreateReplacement(KWLoc, @@ -7210,7 +7235,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, /*isDefinition*/false, KWLoc, - *ClassTemplate->getIdentifier())) { + ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate << FixItHint::CreateReplacement(KWLoc, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7d58017a9bf0..c1961e516ddf 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -989,7 +989,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, if (Id && Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, - TagLocation, *Id)) { + TagLocation, Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id << FixItHint::CreateReplacement(SourceRange(TagLocation), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8d76f6920252..02a31ef8d79c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -643,6 +643,9 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, NULLABILITY_TYPE_ATTRS_CASELIST: // Nullability specifiers cannot go after the declarator-id. + + // Objective-C __kindof does not get distributed. + case AttributeList::AT_ObjCKindOf: continue; default: @@ -738,6 +741,419 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, } } +/// Apply Objective-C type arguments to the given type. +static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, + ArrayRef<TypeSourceInfo *> typeArgs, + SourceRange typeArgsRange, + bool failOnError = false) { + // We can only apply type arguments to an Objective-C class type. + const auto *objcObjectType = type->getAs<ObjCObjectType>(); + if (!objcObjectType || !objcObjectType->getInterface()) { + S.Diag(loc, diag::err_objc_type_args_non_class) + << type + << typeArgsRange; + + if (failOnError) + return QualType(); + return type; + } + + // The class type must be parameterized. + ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); + ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); + if (!typeParams) { + S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) + << objcClass->getDeclName() + << FixItHint::CreateRemoval(typeArgsRange); + + if (failOnError) + return QualType(); + + return type; + } + + // The type must not already be specialized. + if (objcObjectType->isSpecialized()) { + S.Diag(loc, diag::err_objc_type_args_specialized_class) + << type + << FixItHint::CreateRemoval(typeArgsRange); + + if (failOnError) + return QualType(); + + return type; + } + + // Check the type arguments. + SmallVector<QualType, 4> finalTypeArgs; + unsigned numTypeParams = typeParams->size(); + bool anyPackExpansions = false; + for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = typeArgs[i]; + QualType typeArg = typeArgInfo->getType(); + + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeArg)) { + SourceLocation nullabilityLoc + = typeArgInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc = nullabilityLoc.isValid()? nullabilityLoc + : typeArgInfo->getTypeLoc().getLocStart(); + S.Diag(diagLoc, + diag::err_type_arg_explicit_nullability) + << typeArg + << FixItHint::CreateRemoval(nullabilityLoc); + } + + finalTypeArgs.push_back(typeArg); + + if (typeArg->getAs<PackExpansionType>()) + anyPackExpansions = true; + + // Find the corresponding type parameter, if there is one. + ObjCTypeParamDecl *typeParam = nullptr; + if (!anyPackExpansions) { + if (i < numTypeParams) { + typeParam = typeParams->begin()[i]; + } else { + // Too many arguments. + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << false + << objcClass->getDeclName() + << (unsigned)typeArgs.size() + << numTypeParams; + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + + if (failOnError) + return QualType(); + + return type; + } + } + + // Objective-C object pointer types must be substitutable for the bounds. + if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { + // If we don't have a type parameter to match against, assume + // everything is fine. There was a prior pack expansion that + // means we won't be able to match anything. + if (!typeParam) { + assert(anyPackExpansions && "Too many arguments?"); + continue; + } + + // Retrieve the bound. + QualType bound = typeParam->getUnderlyingType(); + const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + + // Determine whether the type argument is substitutable for the bound. + if (typeArgObjC->isObjCIdType()) { + // When the type argument is 'id', the only acceptable type + // parameter bound is 'id'. + if (boundObjC->isObjCIdType()) + continue; + } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { + // Otherwise, we follow the assignability rules. + continue; + } + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + if (failOnError) + return QualType(); + + return type; + } + + // Block pointer types are permitted for unqualified 'id' bounds. + if (typeArg->isBlockPointerType()) { + // If we don't have a type parameter to match against, assume + // everything is fine. There was a prior pack expansion that + // means we won't be able to match anything. + if (!typeParam) { + assert(anyPackExpansions && "Too many arguments?"); + continue; + } + + // Retrieve the bound. + QualType bound = typeParam->getUnderlyingType(); + if (bound->isBlockCompatibleObjCPointerType(S.Context)) + continue; + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + if (failOnError) + return QualType(); + + return type; + } + + // Dependent types will be checked at instantiation time. + if (typeArg->isDependentType()) { + continue; + } + + // Diagnose non-id-compatible type arguments. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_not_id_compatible) + << typeArg + << typeArgInfo->getTypeLoc().getSourceRange(); + + if (failOnError) + return QualType(); + + return type; + } + + // Make sure we didn't have the wrong number of arguments. + if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) { + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << (typeArgs.size() < typeParams->size()) + << objcClass->getDeclName() + << (unsigned)finalTypeArgs.size() + << (unsigned)numTypeParams; + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + + if (failOnError) + return QualType(); + + return type; + } + + // Success. Form the specialized type. + return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false); +} + +/// Apply Objective-C protocol qualifiers to the given type. +static QualType applyObjCProtocolQualifiers( + Sema &S, SourceLocation loc, SourceRange range, QualType type, + ArrayRef<ObjCProtocolDecl *> protocols, + const SourceLocation *protocolLocs, + bool failOnError = false) { + ASTContext &ctx = S.Context; + if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ + // FIXME: Check for protocols to which the class type is already + // known to conform. + + return ctx.getObjCObjectType(objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols, + objT->isKindOfTypeAsWritten()); + } + + if (type->isObjCObjectType()) { + // Silently overwrite any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + + // FIXME: Check for protocols to which the class type is already + // known to conform. + return ctx.getObjCObjectType(type, { }, protocols, false); + } + + // id<protocol-list> + if (type->isObjCIdType()) { + const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols, + objPtr->isKindOfType()); + return ctx.getObjCObjectPointerType(type); + } + + // Class<protocol-list> + if (type->isObjCClassType()) { + const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols, + objPtr->isKindOfType()); + return ctx.getObjCObjectPointerType(type); + } + + S.Diag(loc, diag::err_invalid_protocol_qualifiers) + << range; + + if (failOnError) + return QualType(); + + return type; +} + +QualType Sema::BuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError) { + QualType Result = BaseType; + if (!TypeArgs.empty()) { + Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, + SourceRange(TypeArgsLAngleLoc, + TypeArgsRAngleLoc), + FailOnError); + if (FailOnError && Result.isNull()) + return QualType(); + } + + if (!Protocols.empty()) { + Result = applyObjCProtocolQualifiers(*this, Loc, + SourceRange(ProtocolLAngleLoc, + ProtocolRAngleLoc), + Result, Protocols, + ProtocolLocs.data(), + FailOnError); + if (FailOnError && Result.isNull()) + return QualType(); + } + + return Result; +} + +TypeResult Sema::actOnObjCProtocolQualifierType( + SourceLocation lAngleLoc, + ArrayRef<Decl *> protocols, + ArrayRef<SourceLocation> protocolLocs, + SourceLocation rAngleLoc) { + // Form id<protocol-list>. + QualType Result = Context.getObjCObjectType( + Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl * const *)protocols.data(), + protocols.size()), + false); + Result = Context.getObjCObjectPointerType(Result); + + TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); + TypeLoc ResultTL = ResultTInfo->getTypeLoc(); + + auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>(); + ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit + + auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc() + .castAs<ObjCObjectTypeLoc>(); + ObjCObjectTL.setHasBaseTypeAsWritten(false); + ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation()); + + // No type arguments. + ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); + ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); + + // Fill in protocol qualifiers. + ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc); + ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc); + for (unsigned i = 0, n = protocols.size(); i != n; ++i) + ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]); + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); +} + +TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<ParsedType> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<Decl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + TypeSourceInfo *BaseTypeInfo = nullptr; + QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo); + if (T.isNull()) + return true; + + // Handle missing type-source info. + if (!BaseTypeInfo) + BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc); + + // Extract type arguments. + SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos; + for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) { + TypeSourceInfo *TypeArgInfo = nullptr; + QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo); + if (TypeArg.isNull()) { + ActualTypeArgInfos.clear(); + break; + } + + assert(TypeArgInfo && "No type source info?"); + ActualTypeArgInfos.push_back(TypeArgInfo); + } + + // Build the object type. + QualType Result = BuildObjCObjectType( + T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), + TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, + ProtocolLAngleLoc, + llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), + Protocols.size()), + ProtocolLocs, ProtocolRAngleLoc, + /*FailOnError=*/false); + + if (Result == T) + return BaseType; + + // Create source information for this type. + TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); + TypeLoc ResultTL = ResultTInfo->getTypeLoc(); + + // For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an + // object pointer type. Fill in source information for it. + if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) { + // The '*' is implicit. + ObjCObjectPointerTL.setStarLoc(SourceLocation()); + ResultTL = ObjCObjectPointerTL.getPointeeLoc(); + } + + auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>(); + + // Type argument information. + if (ObjCObjectTL.getNumTypeArgs() > 0) { + assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size()); + ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc); + ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc); + for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i) + ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]); + } else { + ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); + ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); + } + + // Protocol qualifier information. + if (ObjCObjectTL.getNumProtocols() > 0) { + assert(ObjCObjectTL.getNumProtocols() == Protocols.size()); + ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc); + ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc); + for (unsigned i = 0, n = Protocols.size(); i != n; ++i) + ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]); + } else { + ObjCObjectTL.setProtocolLAngleLoc(SourceLocation()); + ObjCObjectTL.setProtocolRAngleLoc(SourceLocation()); + } + + // Base type. + ObjCObjectTL.setHasBaseTypeAsWritten(true); + if (ObjCObjectTL.getType() == T) + ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc()); + else + ObjCObjectTL.getBaseLoc().initialize(Context, Loc); + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -801,15 +1217,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.Char32Ty; break; case DeclSpec::TST_unspecified: - // "<proto1,proto2>" is an objc qualified ID with a missing id. - if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*)PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - break; - } - // If this is a missing declspec in a block literal return context, then it // is inferred from the return statements inside the block. // The declspec is always missing in a lambda expr context; it is either @@ -967,37 +1374,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = S.GetTypeFromParser(DS.getRepAsType()); - if (Result.isNull()) + if (Result.isNull()) { declarator.setInvalidType(true); - else if (DeclSpec::ProtocolQualifierListTy PQ - = DS.getProtocolQualifiers()) { - if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { - // Silently drop any existing protocol qualifiers. - // TODO: determine whether that's the right thing to do. - if (ObjT->getNumProtocols()) - Result = ObjT->getBaseType(); - - if (DS.getNumProtocolQualifiers()) - Result = Context.getObjCObjectType(Result, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) { - // id<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else if (Result->isObjCClassType()) { - // Class<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else { - S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) - << DS.getSourceRange(); - declarator.setInvalidType(true); - } } else if (S.getLangOpts().OpenCL) { if (const AtomicType *AT = Result->getAs<AtomicType>()) { const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>(); @@ -3097,6 +3475,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, spliceAttrIntoList(*nullabilityAttr, attrs); + if (inferNullabilityCS) { + state.getDeclarator().getMutableDeclSpec().getObjCQualifiers() + ->setObjCDeclQualifier(ObjCDeclSpec::DQ_CSNullability); + } + if (inferNullabilityInnerOnly) inferNullabilityInnerOnlyComplete = true; return nullabilityAttr; @@ -3116,7 +3499,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_Yes: checkNullabilityConsistency(state, pointerKind, pointerLoc); } - return nullptr; }; @@ -4058,6 +4440,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_TypeNullable; case AttributedType::attr_null_unspecified: return AttributeList::AT_TypeNullUnspecified; + case AttributedType::attr_objc_kindof: + return AttributeList::AT_ObjCKindOf; } llvm_unreachable("unexpected attribute kind!"); } @@ -4129,32 +4513,14 @@ namespace { TL.setNameEndLoc(DS.getLocEnd()); } void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - // Handle the base type, which might not have been written explicitly. - if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { - TL.setHasBaseTypeAsWritten(false); - TL.getBaseLoc().initialize(Context, SourceLocation()); - } else { - TL.setHasBaseTypeAsWritten(true); - Visit(TL.getBaseLoc()); - } - - // Protocol qualifiers. - if (DS.getProtocolQualifiers()) { - assert(TL.getNumProtocols() > 0); - assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); - TL.setRAngleLoc(DS.getSourceRange().getEnd()); - for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) - TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); - } else { - assert(TL.getNumProtocols() == 0); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); - } + TypeSourceInfo *RepTInfo = nullptr; + Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo); + TL.copy(RepTInfo->getTypeLoc()); } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - TL.setStarLoc(SourceLocation()); - Visit(TL.getPointeeLoc()); + TypeSourceInfo *RepTInfo = nullptr; + Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo); + TL.copy(RepTInfo->getTypeLoc()); } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { TypeSourceInfo *TInfo = nullptr; @@ -5160,6 +5526,44 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, return false; } +bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { + // Find out if it's an Objective-C object or object pointer type; + const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>(); + const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() + : type->getAs<ObjCObjectType>(); + + // If not, we can't apply __kindof. + if (!objType) { + // FIXME: Handle dependent types that aren't yet object types. + Diag(loc, diag::err_objc_kindof_nonobject) + << type; + return true; + } + + // Rebuild the "equivalent" type, which pushes __kindof down into + // the object type. + QualType equivType = Context.getObjCObjectType(objType->getBaseType(), + objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/true); + + // If we started with an object pointer type, rebuild it. + if (ptrType) { + equivType = Context.getObjCObjectPointerType(equivType); + if (auto nullability = type->getNullability(Context)) { + auto attrKind = AttributedType::getNullabilityAttrKind(*nullability); + equivType = Context.getAttributedType(attrKind, equivType, equivType); + } + } + + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, + equivType); + + return false; +} + /// Map a nullability attribute kind to a nullability kind. static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) { switch (kind) { @@ -5770,6 +6174,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; + NULLABILITY_TYPE_ATTRS_CASELIST: // Either add nullability here or try to distribute it. We // don't want to distribute the nullability specifier past any @@ -5788,6 +6193,28 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } break; + case AttributeList::AT_ObjCKindOf: + // '__kindof' must be part of the decl-specifiers. + switch (TAL) { + case TAL_DeclSpec: + break; + + case TAL_DeclChunk: + case TAL_DeclName: + state.getSema().Diag(attr.getLoc(), + diag::err_objc_kindof_wrong_position) + << FixItHint::CreateRemoval(attr.getLoc()) + << FixItHint::CreateInsertion( + state.getDeclarator().getDeclSpec().getLocStart(), "__kindof "); + break; + } + + // Apply it regardless. + if (state.getSema().checkObjCKindOfType(type, attr.getLoc())) + attr.setInvalid(); + attr.setUsedAsTypeAttr(); + break; + case AttributeList::AT_NSReturnsRetained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) break; @@ -5942,7 +6369,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// \param D The definition of the entity. /// \param Suggested Filled in with the declaration that should be made visible /// in order to provide a definition of this entity. -bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { +/// \param OnlyNeedComplete If \c true, we only need the type to be complete, +/// not defined. This only matters for enums with a fixed underlying +/// type, since in all other cases, a type is complete if and only if it +/// is defined. +bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { // Easy case: if we don't have modules, all declarations are visible. if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility) return true; @@ -5960,11 +6392,13 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { } else if (auto *ED = dyn_cast<EnumDecl>(D)) { while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - if (ED->isFixed()) { - // If the enum has a fixed underlying type, any declaration of it will do. + if (OnlyNeedComplete && ED->isFixed()) { + // If the enum has a fixed underlying type, and we're only looking for a + // complete type (not a definition), any visible declaration of it will + // do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { - if (LookupResult::isVisible(*this, Redecl)) + if (isVisible(Redecl)) return true; if (Redecl->isThisDeclarationADefinition() || (Redecl->isCanonicalDecl() && !*Suggested)) @@ -5977,14 +6411,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { assert(D && "missing definition for pattern of instantiated definition"); *Suggested = D; - if (LookupResult::isVisible(*this, D)) + if (isVisible(D)) return true; // The external source may have additional definitions of this type that are // visible, so complete the redeclaration chain now and ask again. if (auto *Source = Context.getExternalSource()) { Source->CompleteRedeclChain(D); - return LookupResult::isVisible(*this, D); + return isVisible(D); } return false; @@ -6038,7 +6472,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (!Diagnoser.Suppressed && Def && - !hasVisibleDefinition(Def, &SuggestedDef)) + !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true); // We lock in the inheritance model once somebody has asked us to ensure diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 80896be981d1..6e193a3529c9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -685,6 +685,27 @@ public: QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); + /// \brief Build an Objective-C object type. + /// + /// By default, performs semantic analysis when building the object type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// \brief Build a new Objective-C object pointer type given the pointee type. + /// + /// By default, directly builds the pointer type, with no additional semantic + /// analysis. + QualType RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Star); + /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -989,7 +1010,7 @@ public: } if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, - IdLoc, *Id)) { + IdLoc, Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); @@ -5606,18 +5627,153 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, ObjCObjectTypeLoc TL) { - // ObjCObjectType is never dependent. - TLB.pushFullCopy(TL); - return TL.getType(); + // Transform base type. + QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc()); + if (BaseType.isNull()) + return QualType(); + + bool AnyChanged = BaseType != TL.getBaseLoc().getType(); + + // Transform type arguments. + SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos; + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { + TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i); + TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc(); + QualType TypeArg = TypeArgInfo->getType(); + if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) { + AnyChanged = true; + + // We have a pack expansion. Instantiate it. + const auto *PackExpansion = PackExpansionLoc.getType() + ->castAs<PackExpansionType>(); + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can + // and should be expanded. + TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc(); + bool Expand = false; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + if (getDerived().TryExpandParameterPacks( + PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) + return QualType(); + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); + QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, + PatternLoc); + if (NewPatternType.isNull()) + return QualType(); + + QualType NewExpansionType = SemaRef.Context.getPackExpansionType( + NewPatternType, NumExpansions); + auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType); + NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc()); + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType)); + continue; + } + + // Substitute into the pack expansion pattern for each slice of the + // pack. + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); + + QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, + PatternLoc); + if (NewTypeArg.isNull()) + return QualType(); + + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); + } + + continue; + } + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); + QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); + if (NewTypeArg.isNull()) + return QualType(); + + // If nothing changed, just keep the old TypeSourceInfo. + if (NewTypeArg == TypeArg) { + NewTypeArgInfos.push_back(TypeArgInfo); + continue; + } + + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); + AnyChanged = true; + } + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || AnyChanged) { + // Rebuild the type. + Result = getDerived().RebuildObjCObjectType( + BaseType, + TL.getLocStart(), + TL.getTypeArgsLAngleLoc(), + NewTypeArgInfos, + TL.getTypeArgsRAngleLoc(), + TL.getProtocolLAngleLoc(), + llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), + TL.getNumProtocols()), + TL.getProtocolLocs(), + TL.getProtocolRAngleLoc()); + + if (Result.isNull()) + return QualType(); + } + + ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result); + assert(TL.hasBaseTypeAsWritten() && "Can't be dependent"); + NewT.setHasBaseTypeAsWritten(true); + NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc()); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]); + NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc()); + NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc()); + for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) + NewT.setProtocolLoc(i, TL.getProtocolLoc(i)); + NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL) { - // ObjCObjectPointerType is never dependent. - TLB.pushFullCopy(TL); - return TL.getType(); + QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != TL.getPointeeLoc().getType()) { + Result = getDerived().RebuildObjCObjectPointerType(PointeeType, + TL.getStarLoc()); + if (Result.isNull()) + return QualType(); + } + + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getStarLoc()); + return Result; } //===----------------------------------------------------------------------===// @@ -10494,6 +10650,31 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildObjCObjectType( + QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, + TypeArgs, TypeArgsRAngleLoc, + ProtocolLAngleLoc, Protocols, ProtocolLocs, + ProtocolRAngleLoc, + /*FailOnError=*/true); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildObjCObjectPointerType( + QualType PointeeType, + SourceLocation Star) { + return SemaRef.Context.getObjCObjectPointerType(PointeeType); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 85c574c2021a..b1bf4a6bff8b 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { // redeclarable. case Decl::ImplicitParam: case Decl::ParmVar: + case Decl::ObjCTypeParam: return false; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 48a898cb30da..3045629a333e 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -845,7 +845,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, } unsigned -ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { +ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) { llvm::FoldingSetNodeID ID; ID.AddInteger(Key.Kind); @@ -874,7 +874,7 @@ ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::GetInternalKey( - const external_key_type& Name) const { + const external_key_type& Name) { DeclNameKey Key; Key.Kind = Name.getNameKind(); switch (Name.getNameKind()) { @@ -1644,6 +1644,7 @@ namespace { /// \brief Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; + unsigned NameHash; unsigned PriorGeneration; unsigned &NumIdentifierLookups; unsigned &NumIdentifierLookupHits; @@ -1653,7 +1654,8 @@ namespace { IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, unsigned &NumIdentifierLookups, unsigned &NumIdentifierLookupHits) - : Name(Name), PriorGeneration(PriorGeneration), + : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), + PriorGeneration(PriorGeneration), NumIdentifierLookups(NumIdentifierLookups), NumIdentifierLookupHits(NumIdentifierLookupHits), Found() @@ -1676,7 +1678,8 @@ namespace { ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, This->Found); ++This->NumIdentifierLookups; - ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait); + ASTIdentifierLookupTable::iterator Pos = + IdTable->find_hashed(This->Name, This->NameHash, &Trait); if (Pos == IdTable->end()) return false; @@ -3976,8 +3979,7 @@ bool ASTReader::readASTFileControlBlock( // Initialize the stream llvm::BitstreamReader StreamFile; - StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(), - (const unsigned char *)(*Buffer)->getBufferEnd()); + PCHContainerOps.ExtractPCH((*Buffer)->getMemBufferRef(), StreamFile); BitstreamCursor Stream(StreamFile); // Sniff for the signature. @@ -5263,11 +5265,16 @@ QualType ASTReader::readTypeRecord(unsigned Index) { case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumTypeArgs = Record[Idx++]; + SmallVector<QualType, 4> TypeArgs; + for (unsigned I = 0; I != NumTypeArgs; ++I) + TypeArgs.push_back(readType(*Loc.F, Record, Idx)); unsigned NumProtos = Record[Idx++]; SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); + bool IsKindOf = Record[Idx++]; + return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf); } case TYPE_OBJC_OBJECT_POINTER: { @@ -5646,8 +5653,12 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx)); + TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); } @@ -5987,9 +5998,8 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, if (ID < NUM_PREDEF_DECL_IDS) return false; - GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); - assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); - return &M == I->second; + return ID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && + ID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls; } ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { @@ -6063,7 +6073,7 @@ Decl *ASTReader::GetExistingDecl(DeclID ID) { if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. - auto &Merged = MergedDecls[D->getCanonicalDecl()]; + auto &Merged = KeyDecls[D->getCanonicalDecl()]; if (Merged.empty()) Merged.push_back(ID); } @@ -6288,6 +6298,27 @@ void ASTReader::FindFileRegionDecls(FileID File, Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); } +/// \brief Retrieve the "definitive" module file for the definition of the +/// given declaration context, if there is one. +/// +/// The "definitive" module file is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive module files +/// associated with them. C++ namespaces, on the other hand, can have +/// definitions in multiple different module files. +/// +/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's +/// NDEBUG checking. +static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, + ASTReader &Reader) { + if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) + return Reader.getOwningModuleFile(cast<Decl>(DefDC)); + + return nullptr; +} + namespace { /// \brief ModuleFile visitor used to perform name lookup into a /// declaration context. @@ -6295,18 +6326,38 @@ namespace { ASTReader &Reader; ArrayRef<const DeclContext *> Contexts; DeclarationName Name; + ASTDeclContextNameLookupTrait::DeclNameKey NameKey; + unsigned NameHash; SmallVectorImpl<NamedDecl *> &Decls; llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet; public: DeclContextNameLookupVisitor(ASTReader &Reader, - ArrayRef<const DeclContext *> Contexts, DeclarationName Name, SmallVectorImpl<NamedDecl *> &Decls, llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet) - : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls), - DeclSet(DeclSet) { } + : Reader(Reader), Name(Name), + NameKey(ASTDeclContextNameLookupTrait::GetInternalKey(Name)), + NameHash(ASTDeclContextNameLookupTrait::ComputeHash(NameKey)), + Decls(Decls), DeclSet(DeclSet) {} + + void visitContexts(ArrayRef<const DeclContext*> Contexts) { + if (Contexts.empty()) + return; + this->Contexts = Contexts; + + // If we can definitively determine which module file to look into, + // only look there. Otherwise, look in all module files. + ModuleFile *Definitive; + if (Contexts.size() == 1 && + (Definitive = getDefinitiveModuleFileFor(Contexts[0], Reader))) { + visit(*Definitive, this); + } else { + Reader.getModuleManager().visit(&visit, this); + } + } + private: static bool visit(ModuleFile &M, void *UserData) { DeclContextNameLookupVisitor *This = static_cast<DeclContextNameLookupVisitor *>(UserData); @@ -6331,7 +6382,7 @@ namespace { ASTDeclContextNameLookupTable *LookupTable = Info->second.NameLookupTableData; ASTDeclContextNameLookupTable::iterator Pos - = LookupTable->find(This->Name); + = LookupTable->find_hashed(This->NameKey, This->NameHash); if (Pos == LookupTable->end()) return false; @@ -6363,27 +6414,6 @@ namespace { }; } -/// \brief Retrieve the "definitive" module file for the definition of the -/// given declaration context, if there is one. -/// -/// The "definitive" module file is the only place where we need to look to -/// find information about the declarations within the given declaration -/// context. For example, C++ and Objective-C classes, C structs/unions, and -/// Objective-C protocols, categories, and extensions are all defined in a -/// single place in the source code, so they have definitive module files -/// associated with them. C++ namespaces, on the other hand, can have -/// definitions in multiple different module files. -/// -/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's -/// NDEBUG checking. -static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, - ASTReader &Reader) { - if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) - return Reader.getOwningModuleFile(cast<Decl>(DefDC)); - - return nullptr; -} - bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { @@ -6405,28 +6435,15 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, Contexts.push_back(DC); if (DC->isNamespace()) { - auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + auto Key = KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Key != KeyDecls.end()) { + for (unsigned I = 0, N = Key->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); } } - auto LookUpInContexts = [&](ArrayRef<const DeclContext*> Contexts) { - DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls, DeclSet); - - // If we can definitively determine which module file to look into, - // only look there. Otherwise, look in all module files. - ModuleFile *Definitive; - if (Contexts.size() == 1 && - (Definitive = getDefinitiveModuleFileFor(Contexts[0], *this))) { - DeclContextNameLookupVisitor::visit(*Definitive, &Visitor); - } else { - ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); - } - }; - - LookUpInContexts(Contexts); + DeclContextNameLookupVisitor Visitor(*this, Name, Decls, DeclSet); + Visitor.visitContexts(Contexts); // If this might be an implicit special member function, then also search // all merged definitions of the surrounding class. We need to search them @@ -6437,7 +6454,7 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, if (Merged != MergedLookups.end()) { for (unsigned I = 0; I != Merged->second.size(); ++I) { const DeclContext *Context = Merged->second[I]; - LookUpInContexts(Context); + Visitor.visitContexts(Context); // We might have just added some more merged lookups. If so, our // iterator is now invalid, so grab a fresh one before continuing. Merged = MergedLookups.find(DC); @@ -6525,11 +6542,11 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { Contexts.push_back(DC); if (DC->isNamespace()) { - MergedDeclsMap::iterator Merged - = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + KeyDeclsMap::iterator Key = + KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Key != KeyDecls.end()) { + for (unsigned I = 0, N = Key->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); } } @@ -8389,6 +8406,11 @@ void ASTReader::diagnoseOdrViolations() { } } +void ASTReader::StartedDeserializing() { + if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get()) + ReadTimer->startTimer(); +} + void ASTReader::FinishedDeserializing() { assert(NumCurrentElementsDeserializing && "FinishedDeserializing not paired with StartedDeserializing"); @@ -8413,6 +8435,9 @@ void ASTReader::FinishedDeserializing() { diagnoseOdrViolations(); + if (ReadTimer) + ReadTimer->stopTimer(); + // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) @@ -8451,12 +8476,14 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool AllowConfigurationMismatch, bool ValidateSystemInputs, - bool UseGlobalIndex) + bool UseGlobalIndex, + std::unique_ptr<llvm::Timer> ReadTimer) : Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr), OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerOps(PCHContainerOps), Diags(PP.getDiagnostics()), SemaObj(nullptr), PP(PP), Context(Context), Consumer(nullptr), ModuleMgr(PP.getFileManager(), PCHContainerOps), + ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index b23c33c55188..1a0c5b58e7f6 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -128,20 +128,22 @@ namespace clang { GlobalDeclID FirstID; Decl *MergeWith; mutable bool Owning; + bool IsKeyDecl; Decl::Kind DeclKind; void operator=(RedeclarableResult &) = delete; public: RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID, - Decl *MergeWith, Decl::Kind DeclKind) + Decl *MergeWith, Decl::Kind DeclKind, + bool IsKeyDecl) : Reader(Reader), FirstID(FirstID), MergeWith(MergeWith), - Owning(true), DeclKind(DeclKind) {} + Owning(true), IsKeyDecl(IsKeyDecl), DeclKind(DeclKind) {} RedeclarableResult(RedeclarableResult &&Other) : Reader(Other.Reader), FirstID(Other.FirstID), MergeWith(Other.MergeWith), Owning(Other.Owning), - DeclKind(Other.DeclKind) { + IsKeyDecl(Other.IsKeyDecl), DeclKind(Other.DeclKind) { Other.Owning = false; } @@ -156,6 +158,9 @@ namespace clang { /// \brief Retrieve the first ID. GlobalDeclID getFirstID() const { return FirstID; } + /// \brief Is this declaration the key declaration? + bool isKeyDecl() const { return IsKeyDecl; } + /// \brief Get a known declaration that this should be merged with, if /// any. Decl *getKnownMergeTarget() const { return MergeWith; } @@ -348,10 +353,13 @@ namespace clang { void mergeTemplatePattern(RedeclarableTemplateDecl *D, RedeclarableTemplateDecl *Existing, - DeclID DsID); + DeclID DsID, bool IsKeyDecl); + + ObjCTypeParamList *ReadObjCTypeParamList(); // FIXME: Reorder according to DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); @@ -899,18 +907,49 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs); } +void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + D->Variance = Record[Idx++]; + D->Index = Record[Idx++]; + D->VarianceLoc = ReadSourceLocation(Record, Idx); + D->ColonLoc = ReadSourceLocation(Record, Idx); +} + void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); CD->setAtStartLoc(ReadSourceLocation(Record, Idx)); CD->setAtEndRange(ReadSourceRange(Record, Idx)); } +ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { + unsigned numParams = Record[Idx++]; + if (numParams == 0) + return nullptr; + + SmallVector<ObjCTypeParamDecl *, 4> typeParams; + typeParams.reserve(numParams); + for (unsigned i = 0; i != numParams; ++i) { + auto typeParam = ReadDeclAs<ObjCTypeParamDecl>(Record, Idx); + if (!typeParam) + return nullptr; + + typeParams.push_back(typeParam); + } + + SourceLocation lAngleLoc = ReadSourceLocation(Record, Idx); + SourceLocation rAngleLoc = ReadSourceLocation(Record, Idx); + + return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc, + typeParams, rAngleLoc); +} + void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { RedeclarableResult Redecl = VisitRedeclarable(ID); VisitObjCContainerDecl(ID); TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]); mergeRedeclarable(ID, Redecl); - + + ID->TypeParamList = ReadObjCTypeParamList(); if (Record[Idx++]) { // Read the definition. ID->allocateDefinitionData(); @@ -922,8 +961,7 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { ObjCInterfaceDecl::DefinitionData &Data = ID->data(); // Read the superclass. - Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); - Data.SuperClassLoc = ReadSourceLocation(Record, Idx); + Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx); Data.EndLoc = ReadSourceLocation(Record, Idx); Data.HasDesignatedInitializers = Record[Idx++]; @@ -1020,6 +1058,7 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { Reader.CategoriesDeserialized.insert(CD); CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); + CD->TypeParamList = ReadObjCTypeParamList(); unsigned NumProtoRefs = Record[Idx++]; SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); @@ -2139,12 +2178,16 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { DeclID FirstDeclID = ReadDeclID(Record, Idx); Decl *MergeWith = nullptr; + bool IsKeyDecl = ThisDeclID == FirstDeclID; // 0 indicates that this declaration was the only declaration of its entity, // and is used for space optimization. - if (FirstDeclID == 0) + if (FirstDeclID == 0) { FirstDeclID = ThisDeclID; - else if (unsigned N = Record[Idx++]) { + IsKeyDecl = true; + } else if (unsigned N = Record[Idx++]) { + IsKeyDecl = false; + // We have some declarations that must be before us in our redeclaration // chain. Read them now, and remember that we ought to merge with one of // them. @@ -2170,7 +2213,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { // The result structure takes care to note that we need to load the // other declaration chains for this ID. return RedeclarableResult(Reader, FirstDeclID, MergeWith, - static_cast<T *>(D)->getKind()); + static_cast<T *>(D)->getKind(), IsKeyDecl); } /// \brief Attempts to merge the given declaration (D) with another declaration @@ -2209,11 +2252,12 @@ template<typename T> static T assert_cast(...) { /// declarations. void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D, RedeclarableTemplateDecl *Existing, - DeclID DsID) { + DeclID DsID, bool IsKeyDecl) { auto *DPattern = D->getTemplatedDecl(); auto *ExistingPattern = Existing->getTemplatedDecl(); RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(), - /*MergeWith*/ExistingPattern, DPattern->getKind()); + /*MergeWith*/ExistingPattern, DPattern->getKind(), + IsKeyDecl); if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) { // Merge with any existing definition. @@ -2276,11 +2320,11 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D)) mergeTemplatePattern( DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon), - TemplatePatternID); + TemplatePatternID, Redecl.isKeyDecl()); - // If this declaration was the canonical declaration, make a note of that. - if (DCanon == D) { - Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID()); + // If this declaration is a key declaration, make a note of that. + if (Redecl.isKeyDecl()) { + Reader.KeyDecls[ExistingCanon].push_back(Redecl.getFirstID()); if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) Reader.PendingDeclChains.push_back(ExistingCanon); } @@ -3259,6 +3303,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; + case DECL_OBJC_TYPE_PARAM: + D = ObjCTypeParamDecl::CreateDeserialized(Context, ID); + break; } assert(D && "Unknown declaration reading AST file"); @@ -3418,20 +3465,9 @@ namespace { M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare); if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap || - Result->FirstID != ID) { - // If we have a previously-canonical singleton declaration that was - // merged into another redeclaration chain, create a trivial chain - // for this single declaration so that it will get wired into the - // complete redeclaration chain. - if (GlobalID != CanonID && - GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && - GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) { - addToChain(Reader.GetDecl(GlobalID)); - } - + Result->FirstID != ID) return; - } - + // Dig out all of the redeclarations. unsigned Offset = Result->Offset; unsigned N = M.RedeclarationChains[Offset]; @@ -3472,8 +3508,6 @@ namespace { // Visit each of the declarations. for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) searchForID(M, SearchDecls[I]); - // FIXME: If none of the SearchDecls had local IDs in this module, can - // we avoid searching any ancestor module files? return false; } @@ -3494,9 +3528,9 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) { GlobalDeclID CanonID = CanonDecl->getGlobalID(); if (CanonID) SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first. - MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl); - if (MergedPos != MergedDecls.end()) - SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end()); + KeyDeclsMap::iterator KeyPos = KeyDecls.find(CanonDecl); + if (KeyPos != KeyDecls.end()) + SearchDecls.append(KeyPos->second.begin(), KeyPos->second.end()); // Build up the list of redeclarations. RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID); diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index d1b032b27ac2..5b1c4f4963e4 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -68,8 +68,8 @@ public: return a.Kind == b.Kind && a.Data == b.Data; } - hash_value_type ComputeHash(const DeclNameKey &Key) const; - internal_key_type GetInternalKey(const external_key_type& Name) const; + static hash_value_type ComputeHash(const DeclNameKey &Key); + static internal_key_type GetInternalKey(const external_key_type& Name); static std::pair<unsigned, unsigned> ReadKeyDataLength(const unsigned char*& d); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 0d15b17c7cec..8b6863822c69 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -421,9 +421,13 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getTypeArgsAsWritten().size()); + for (auto TypeArg : T->getTypeArgsAsWritten()) + Writer.AddTypeRef(TypeArg, Record); Record.push_back(T->getNumProtocols()); for (const auto *I : T->quals()) Writer.AddDeclRef(I, Record); + Record.push_back(T->isKindOfTypeAsWritten()); Code = TYPE_OBJC_OBJECT; } @@ -648,8 +652,12 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record); + Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } @@ -3626,6 +3634,55 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, /// bitstream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC) { + // If we imported a key declaration of this namespace, write the visible + // lookup results as an update record for it rather than including them + // on this declaration. We will only look at key declarations on reload. + if (isa<NamespaceDecl>(DC) && Chain && + Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) { + // Only do this once, for the first local declaration of the namespace. + for (NamespaceDecl *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) + if (!Prev->isFromASTFile()) + return 0; + + // Note that we need to emit an update record for the primary context. + UpdatedDeclContexts.insert(DC->getPrimaryContext()); + + // Make sure all visible decls are written. They will be recorded later. We + // do this using a side data structure so we can sort the names into + // a deterministic order. + StoredDeclsMap *Map = DC->getPrimaryContext()->buildLookup(); + SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16> + LookupResults; + if (Map) { + LookupResults.reserve(Map->size()); + for (auto &Entry : *Map) + LookupResults.push_back( + std::make_pair(Entry.first, Entry.second.getLookupResult())); + } + + std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first()); + for (auto &NameAndResult : LookupResults) { + DeclarationName Name = NameAndResult.first; + DeclContext::lookup_result Result = NameAndResult.second; + if (Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + // We have to work around a name lookup bug here where negative lookup + // results for these names get cached in namespace lookup tables (these + // names should never be looked up in a namespace). + assert(Result.empty() && "Cannot have a constructor or conversion " + "function name in a namespace!"); + continue; + } + + for (NamedDecl *ND : Result) + if (!ND->isFromASTFile()) + GetDeclRef(ND); + } + + return 0; + } + if (DC->getPrimaryContext() != DC) return 0; @@ -3677,6 +3734,11 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { SmallString<4096> LookupTable; uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); + // If we're updating a namespace, select a key declaration as the key for the + // update record; those are the only ones that will be checked on reload. + if (isa<NamespaceDecl>(DC)) + DC = cast<DeclContext>(Chain->getKeyDeclaration(cast<Decl>(DC))); + // Write the lookup table RecordData Record; Record.push_back(UPDATE_VISIBLE); @@ -3709,11 +3771,17 @@ void ASTWriter::WriteRedeclarations() { SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap; for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { - Decl *First = Redeclarations[I]; - assert(First->isFirstDecl() && "Not the first declaration?"); - - Decl *MostRecent = First->getMostRecentDecl(); - + const Decl *Key = Redeclarations[I]; + assert((Chain ? Chain->getKeyDeclaration(Key) == Key + : Key->isFirstDecl()) && + "not the key declaration"); + + const Decl *First = Key->getCanonicalDecl(); + const Decl *MostRecent = First->getMostRecentDecl(); + + assert((getDeclID(First) >= NUM_PREDEF_DECL_IDS || First == Key) && + "should not have imported key decls for predefined decl"); + // If we only have a single declaration, there is no point in storing // a redeclaration chain. if (First == MostRecent) @@ -3722,34 +3790,34 @@ void ASTWriter::WriteRedeclarations() { unsigned Offset = LocalRedeclChains.size(); unsigned Size = 0; LocalRedeclChains.push_back(0); // Placeholder for the size. - + // Collect the set of local redeclarations of this declaration. - for (Decl *Prev = MostRecent; Prev != First; + for (const Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) { - if (!Prev->isFromASTFile()) { + if (!Prev->isFromASTFile() && Prev != Key) { AddDeclRef(Prev, LocalRedeclChains); ++Size; } } LocalRedeclChains[Offset] = Size; - + // Reverse the set of local redeclarations, so that we store them in // order (since we found them in reverse order). std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end()); - + // Add the mapping from the first ID from the AST to the set of local // declarations. - LocalRedeclarationsInfo Info = { getDeclID(First), Offset }; + LocalRedeclarationsInfo Info = { getDeclID(Key), Offset }; LocalRedeclsMap.push_back(Info); - + assert(N == Redeclarations.size() && "Deserialized a declaration we shouldn't have"); } - + if (LocalRedeclChains.empty()) return; - + // Sort the local redeclarations map by the first declaration ID, // since the reader will be performing binary searches on this information. llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end()); @@ -4045,25 +4113,27 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Preprocessor &PP = SemaRef.PP; // Set up predefined declaration IDs. - DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID; - if (Context.ObjCIdDecl) - DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID; - if (Context.ObjCSelDecl) - DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID; - if (Context.ObjCClassDecl) - DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID; - if (Context.ObjCProtocolClassDecl) - DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID; - if (Context.Int128Decl) - DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID; - if (Context.UInt128Decl) - DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID; - if (Context.ObjCInstanceTypeDecl) - DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; - if (Context.BuiltinVaListDecl) - DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID; - if (Context.ExternCContext) - DeclIDs[Context.ExternCContext] = PREDEF_DECL_EXTERN_C_CONTEXT_ID; + auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) { + if (D) { + assert(D->isCanonicalDecl() && "predefined decl is not canonical"); + DeclIDs[D] = ID; + if (D->getMostRecentDecl() != D) + Redeclarations.push_back(D); + } + }; + RegisterPredefDecl(Context.getTranslationUnitDecl(), + PREDEF_DECL_TRANSLATION_UNIT_ID); + RegisterPredefDecl(Context.ObjCIdDecl, PREDEF_DECL_OBJC_ID_ID); + RegisterPredefDecl(Context.ObjCSelDecl, PREDEF_DECL_OBJC_SEL_ID); + RegisterPredefDecl(Context.ObjCClassDecl, PREDEF_DECL_OBJC_CLASS_ID); + RegisterPredefDecl(Context.ObjCProtocolClassDecl, + PREDEF_DECL_OBJC_PROTOCOL_ID); + RegisterPredefDecl(Context.Int128Decl, PREDEF_DECL_INT_128_ID); + RegisterPredefDecl(Context.UInt128Decl, PREDEF_DECL_UNSIGNED_INT_128_ID); + RegisterPredefDecl(Context.ObjCInstanceTypeDecl, + PREDEF_DECL_OBJC_INSTANCETYPE_ID); + RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); + RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); // Build a record containing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for @@ -5667,7 +5737,7 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { // If we don't already know the exception specification for this redecl // chain, add an update record for it. if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D) @@ -5681,7 +5751,7 @@ void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { assert(!WritingAST && "Already writing the AST!"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { DeclUpdates[D].push_back( DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); }); @@ -5692,7 +5762,7 @@ void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, assert(!WritingAST && "Already writing the AST!"); assert(Delete && "Not given an operator delete"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(DD, [&](const Decl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); }); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 6c5bc5bbd483..fd6708dd5c3f 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -117,6 +117,7 @@ namespace clang { // FIXME: Put in the same order is DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); @@ -131,6 +132,22 @@ namespace clang { void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + /// Add an Objective-C type parameter list to the given record. + void AddObjCTypeParamList(ObjCTypeParamList *typeParams) { + // Empty type parameter list. + if (!typeParams) { + Record.push_back(0); + return; + } + + Record.push_back(typeParams->size()); + for (auto typeParam : *typeParams) { + Writer.AddDeclRef(typeParam, Record); + } + Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record); + Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record); + } + void AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { @@ -237,6 +254,8 @@ void ASTDeclWriter::VisitDecl(Decl *D) { // // This happens when we instantiate a class with a friend declaration or a // function with a local extern declaration, for instance. + // + // FIXME: Can we handle this in AddedVisibleDecl instead? if (D->isOutOfLine()) { auto *DC = D->getDeclContext(); while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) { @@ -562,6 +581,16 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Code = serialization::DECL_OBJC_METHOD; } +void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + Record.push_back(D->Variance); + Record.push_back(D->Index); + Writer.AddSourceLocation(D->VarianceLoc, Record); + Writer.AddSourceLocation(D->ColonLoc, Record); + + Code = serialization::DECL_OBJC_TYPE_PARAM; +} + void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtStartLoc(), Record); @@ -573,14 +602,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { VisitRedeclarable(D); VisitObjCContainerDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); + AddObjCTypeParamList(D->TypeParamList); Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) { // Write the DefinitionData ObjCInterfaceDecl::DefinitionData &Data = D->data(); - Writer.AddDeclRef(D->getSuperClass(), Record); - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); + Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record); Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); Record.push_back(Data.HasDesignatedInitializers); @@ -660,6 +689,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddDeclRef(D->getClassInterface(), Record); + AddObjCTypeParamList(D->TypeParamList); Record.push_back(D->protocol_size()); for (const auto *I : D->protocols()) Writer.AddDeclRef(I, Record); @@ -977,40 +1007,6 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { Writer.AddDeclRef(D->getAnonymousNamespace(), Record); Code = serialization::DECL_NAMESPACE; - if (Writer.hasChain() && !D->isOriginalNamespace() && - D->getOriginalNamespace()->isFromASTFile()) { - NamespaceDecl *NS = D->getOriginalNamespace(); - Writer.UpdatedDeclContexts.insert(NS); - - // Make sure all visible decls are written. They will be recorded later. We - // do this using a side data structure so we can sort the names into - // a deterministic order. - StoredDeclsMap *Map = NS->buildLookup(); - SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16> - LookupResults; - LookupResults.reserve(Map->size()); - for (auto &Entry : *Map) - LookupResults.push_back( - std::make_pair(Entry.first, Entry.second.getLookupResult())); - - std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first()); - for (auto &NameAndResult : LookupResults) { - DeclarationName Name = NameAndResult.first; - DeclContext::lookup_result Result = NameAndResult.second; - if (Name.getNameKind() == DeclarationName::CXXConstructorName || - Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - // We have to work around a name lookup bug here where negative lookup - // results for these names get cached in namespace lookup tables. - assert(Result.empty() && "Cannot have a constructor or conversion " - "function name in a namespace!"); - continue; - } - - for (NamedDecl *ND : Result) - Writer.GetDeclRef(ND); - } - } - if (Writer.hasChain() && D->isAnonymousNamespace() && D == D->getMostRecentDecl()) { // This is a most recent reopening of the anonymous namespace. If its parent @@ -1482,6 +1478,17 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, Record.push_back(VisibleOffset); } +/// Determine whether D is the first declaration in its redeclaration chain that +/// is not from an AST file. +template <typename T> +static bool isFirstLocalDecl(Redeclarable<T> *D) { + assert(D && !static_cast<T*>(D)->isFromASTFile()); + do + D = D->getPreviousDecl(); + while (D && static_cast<T*>(D)->isFromASTFile()); + return !D; +} + template <typename T> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { T *First = D->getFirstDecl(); @@ -1490,41 +1497,30 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) && "Not considered redeclarable?"); - // There is more than one declaration of this entity, so we will need to - // write a redeclaration chain. Writer.AddDeclRef(First, Record); - Writer.Redeclarations.insert(First); - auto *Previous = D->getPreviousDecl(); - - // In a modules build, we can have imported declarations after a local - // canonical declaration. If this is the first local declaration, emit - // a list of all such imported declarations so that we can ensure they - // are loaded before we are. This allows us to rebuild the redecl chain - // in the right order on reload (all declarations imported by a module - // should be before all declarations provided by that module). - bool EmitImportedMergedCanonicalDecls = false; + // In a modules build, emit a list of all imported key declarations + // (excluding First, if it was imported), so that we can be sure that all + // redeclarations visible to this module are before D in the redecl chain. + unsigned I = Record.size(); + Record.push_back(0); if (Context.getLangOpts().Modules && Writer.Chain) { - auto *PreviousLocal = Previous; - while (PreviousLocal && PreviousLocal->isFromASTFile()) - PreviousLocal = PreviousLocal->getPreviousDecl(); - if (!PreviousLocal) - EmitImportedMergedCanonicalDecls = true; + if (isFirstLocalDecl(D)) { + Writer.Chain->forEachImportedKeyDecl(First, [&](const Decl *D) { + if (D != First) + Writer.AddDeclRef(D, Record); + }); + Record[I] = Record.size() - I - 1; + + // Write a redeclaration chain, attached to the first key decl. + Writer.Redeclarations.push_back(Writer.Chain->getKeyDeclaration(First)); + } + } else if (D == First || D->getPreviousDecl()->isFromASTFile()) { + assert(isFirstLocalDecl(D) && "imported decl after local decl"); + + // Write a redeclaration chain attached to the first decl. + Writer.Redeclarations.push_back(First); } - if (EmitImportedMergedCanonicalDecls) { - llvm::SmallMapVector<ModuleFile*, Decl*, 16> FirstInModule; - for (auto *Redecl = MostRecent; Redecl; - Redecl = Redecl->getPreviousDecl()) - if (Redecl->isFromASTFile()) - FirstInModule[Writer.Chain->getOwningModuleFile(Redecl)] = Redecl; - // FIXME: If FirstInModule has entries for modules A and B, and B imports - // A (directly or indirectly), we don't need to write the entry for A. - Record.push_back(FirstInModule.size()); - for (auto I = FirstInModule.rbegin(), E = FirstInModule.rend(); - I != E; ++I) - Writer.AddDeclRef(I->second, Record); - } else - Record.push_back(0); // Make sure that we serialize both the previous and the most-recent // declarations, which (transitively) ensures that all declarations in the @@ -1532,7 +1528,7 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { // // FIXME: This is not correct; when we reach an imported declaration we // won't emit its previous declaration. - (void)Writer.GetDeclRef(Previous); + (void)Writer.GetDeclRef(D->getPreviousDecl()); (void)Writer.GetDeclRef(MostRecent); } else { // We use the sentinel value 0 to indicate an only declaration. diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp index a2cf8e10d09b..016cb146f84e 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -34,7 +34,6 @@ struct SelectorDescriptor { const char *SelectorName; unsigned ArgumentCount; }; -} //===----------------------------------------------------------------------===// // FindSuperCallVisitor - Identify specific calls to the superclass. @@ -63,7 +62,6 @@ private: // ObjCSuperCallChecker //===----------------------------------------------------------------------===// -namespace { class ObjCSuperCallChecker : public Checker< check::ASTDecl<ObjCImplementationDecl> > { public: diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index b64e30b31007..6ba64f52d183 100644 --- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -8,7 +8,10 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/CheckerRegistry.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/raw_ostream.h" @@ -111,6 +114,28 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, } } +void CheckerRegistry::validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const { + for (auto &config : opts.Config) { + size_t pos = config.getKey().find(':'); + if (pos == StringRef::npos) + continue; + + bool hasChecker = false; + StringRef checkerName = config.getKey().substr(0, pos); + for (auto &checker : Checkers) { + if (checker.FullName.startswith(checkerName) && + (checker.FullName.size() == pos || checker.FullName[pos] == '.')) { + hasChecker = true; + break; + } + } + if (!hasChecker) { + diags.Report(diag::err_unknown_analyzer_checker) << checkerName; + } + } +} + void CheckerRegistry::printHelp(raw_ostream &out, size_t maxNameChars) const { // FIXME: Alphabetical sort puts 'experimental' in the middle. diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 1fa675433b56..5ac845825c8d 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -824,9 +824,12 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, QualType T; if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) T = TSI->getType(); - else - T = getContext().getFunctionNoProtoType(getContext().VoidTy); - + if (T.isNull()) + T = getContext().VoidTy; + if (!T->getAs<FunctionType>()) + T = getContext().getFunctionNoProtoType(T); + T = getContext().getBlockPointerType(T); + const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(T), STC->getAnalysisDeclContext()); diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index b3ff79750b49..7fced1e5c71a 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -114,6 +114,7 @@ ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ClangCheckerRegistry allCheckers(plugins, &diags); allCheckers.initializeManager(*checkerMgr, checkerOpts); + allCheckers.validateCheckerOptions(opts, diags); checkerMgr->finishedCheckerRegistration(); for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { diff --git a/test/ARCMT/check-with-pch.m b/test/ARCMT/check-with-pch.m index 1a94dda796b9..5e843ff08df7 100644 --- a/test/ARCMT/check-with-pch.m +++ b/test/ARCMT/check-with-pch.m @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 %S/Common.h -emit-pch -o %t.pch // RUN: %clang_cc1 -include-pch %t.pch -arcmt-check -verify -triple x86_64-apple-darwin10 -fblocks -Werror %s +// REQUIRES: x86-registered-target // rdar://9601437 @interface I9601437 { diff --git a/test/ARCMT/migrate-on-pch-and-module.m b/test/ARCMT/migrate-on-pch-and-module.m index 51babf6cf483..42e01ea91a9c 100644 --- a/test/ARCMT/migrate-on-pch-and-module.m +++ b/test/ARCMT/migrate-on-pch-and-module.m @@ -1,7 +1,7 @@ // RUN: rm -rf %t-mcp // RUN: %clang_cc1 -objcmt-migrate-subscripting -emit-pch -o %t.pch %s -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -F %S/Inputs -fmodules -fimplicit-module-maps -fmodules-cache-path=%t-mcp -w // RUN: %clang_cc1 -objcmt-migrate-subscripting -include-pch %t.pch %s -migrate -o %t.remap -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -F %S/Inputs -fmodules -fimplicit-module-maps -fmodules-cache-path=%t-mcp - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/ARCMT/objcmt-with-pch.m b/test/ARCMT/objcmt-with-pch.m index fac42c851235..61c87a2b007d 100644 --- a/test/ARCMT/objcmt-with-pch.m +++ b/test/ARCMT/objcmt-with-pch.m @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: rm -rf %t // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %S/Common.h -emit-pch -o %t.pch // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -include-pch %t.pch diff --git a/test/ARCMT/objcmt-with-pch.m.result b/test/ARCMT/objcmt-with-pch.m.result index 04eadc9d3fa4..7e2570cfc456 100644 --- a/test/ARCMT/objcmt-with-pch.m.result +++ b/test/ARCMT/objcmt-with-pch.m.result @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: rm -rf %t // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %S/Common.h -emit-pch -o %t.pch // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -include-pch %t.pch diff --git a/test/Analysis/analyzer-checker-config.c b/test/Analysis/analyzer-checker-config.c new file mode 100644 index 000000000000..642c96c996d5 --- /dev/null +++ b/test/Analysis/analyzer-checker-config.c @@ -0,0 +1,12 @@ +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.mallo:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni.:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config ..:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unrelated:Optimistic=true 2>&1 | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.Malloc:Optimistic=true + +// Just to test clang is working. +# foo + +// CHECK: error: diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m index 62d53607b533..4dbe95172073 100644 --- a/test/Analysis/blocks.m +++ b/test/Analysis/blocks.m @@ -162,3 +162,51 @@ void blockCapturesItselfInTheLoop(int x, int m) { } assignData(x); } + +// Blocks that called the function they were contained in that also have +// static locals caused crashes. +// rdar://problem/21698099 +void takeNonnullBlock(void (^)(void)) __attribute__((nonnull)); +void takeNonnullIntBlock(int (^)(void)) __attribute__((nonnull)); + +void testCallContainingWithSignature1() +{ + takeNonnullBlock(^{ + static const char str[] = "Lost connection to sharingd"; + testCallContainingWithSignature1(); + }); +} + +void testCallContainingWithSignature2() +{ + takeNonnullBlock(^void{ + static const char str[] = "Lost connection to sharingd"; + testCallContainingWithSignature2(); + }); +} + +void testCallContainingWithSignature3() +{ + takeNonnullBlock(^void(){ + static const char str[] = "Lost connection to sharingd"; + testCallContainingWithSignature3(); + }); +} + +void testCallContainingWithSignature4() +{ + takeNonnullBlock(^void(void){ + static const char str[] = "Lost connection to sharingd"; + testCallContainingWithSignature4(); + }); +} + +void testCallContainingWithSignature5() +{ + takeNonnullIntBlock(^{ + static const char str[] = "Lost connection to sharingd"; + testCallContainingWithSignature5(); + return 0; + }); +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 591a9272ae6d..526f129bab58 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,7 +58,7 @@ set(CLANG_TEST_PARAMS if( NOT CLANG_BUILT_STANDALONE ) list(APPEND CLANG_TEST_DEPS llvm-config - llc opt FileCheck count not llvm-symbolizer llvm-profdata + llc opt FileCheck count not llvm-symbolizer llvm-profdata llvm-objdump ) endif() diff --git a/test/CXX/class/class.mem/p13.cpp b/test/CXX/class/class.mem/p13.cpp index 84885848870e..1d7b9bc81551 100644 --- a/test/CXX/class/class.mem/p13.cpp +++ b/test/CXX/class/class.mem/p13.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s // If T is the name of a class, then each of the following shall have // a name different from T: @@ -9,23 +9,53 @@ struct X0 { }; // - every member function of class T -// (Cannot be tested) +struct Xa { + int Xa() {} // expected-error{{constructor cannot have a return type}} +}; // - every member of class T that is itself a type; -struct X1 { // expected-note{{previous use is here}} - enum X1 { }; // expected-error{{use of 'X1' with tag type that does not match previous declaration}} +struct X1 { + enum X1 { }; // expected-error{{member 'X1' has the same name as its class}} +}; + +struct X1a { + struct X1a; // expected-error{{member 'X1a' has the same name as its class}} }; struct X2 { typedef int X2; // expected-error{{member 'X2' has the same name as its class}} }; -// - every enumerator of every member of class T that is an enumerated type; and +struct X2a { + using X2a = int; // expected-error{{member 'X2a' has the same name as its class}} +}; + +// - every member template of class T + +struct X2b { + template<typename T> struct X2b; // expected-error{{member 'X2b' has the same name as its class}} +}; +struct X2c { + template<typename T> void X2c(); // expected-error{{constructor cannot have a return type}} +}; +struct X2d { + template<typename T> static int X2d; // expected-error{{member 'X2d' has the same name as its class}} +}; +struct X2e { + template<typename T> using X2e = int; // expected-error{{member 'X2e' has the same name as its class}} +}; + +// - every enumerator of every member of class T that is an unscoped enumerated type; and struct X3 { enum E { X3 // expected-error{{member 'X3' has the same name as its class}} }; }; +struct X3a { + enum class E { + X3a // ok + }; +}; // - every member of every anonymous union that is a member of class T. struct X4 { @@ -37,4 +67,3 @@ struct X4 { }; }; }; - diff --git a/test/CXX/class/class.mem/p2.cpp b/test/CXX/class/class.mem/p2.cpp index d45c03860654..1f0dfd05a20d 100644 --- a/test/CXX/class/class.mem/p2.cpp +++ b/test/CXX/class/class.mem/p2.cpp @@ -76,13 +76,10 @@ namespace PR12629 { namespace PR12688 { struct S { - // FIXME: Producing one error saying this can't have the same name - // as the class because it's not a constructor, then producing - // another error saying this can't have a return type because - // it is a constructor, is redundant and inconsistent. + // FIXME: Maybe suppress the "constructor cannot have a return type" error + // if the return type is invalid. nonsense S() throw (more_nonsense); // \ // expected-error {{'nonsense'}} \ - // expected-error {{has the same name as its class}} \ // expected-error {{constructor cannot have a return type}} }; } diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp index 865abb081a44..20b5104f83be 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp @@ -83,12 +83,10 @@ namespace InFunctions { namespace ClassNameRedecl { class C0 { - // FIXME: this diagnostic is pretty poor - using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}} + using C0 = int; // expected-error {{member 'C0' has the same name as its class}} }; class C1 { - // FIXME: this diagnostic is pretty poor - using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}} + using C1 = C1; // expected-error {{member 'C1' has the same name as its class}} }; class C2 { using C0 = C1; // ok diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp index e040d5b2642b..4686b1c961ec 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp @@ -158,7 +158,7 @@ namespace dependent { } template<typename T> void n() { - extern T n_var; // expected-error {{redefinition of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}} + extern T n_var; // expected-error {{redeclaration of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}} extern T n_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} expected-note {{previous}} } template void n<int>(); diff --git a/test/CXX/drs/dr19xx.cpp b/test/CXX/drs/dr19xx.cpp index 9c2d3e7c1770..368e7b341652 100644 --- a/test/CXX/drs/dr19xx.cpp +++ b/test/CXX/drs/dr19xx.cpp @@ -39,6 +39,21 @@ namespace dr1902 { // dr1902: 3.7 #endif } +namespace dr1909 { // dr1909: yes + struct A { + template<typename T> struct A {}; // expected-error {{member 'A' has the same name as its class}} + }; + struct B { + template<typename T> void B() {} // expected-error {{constructor cannot have a return type}} + }; + struct C { + template<typename T> static int C; // expected-error {{member 'C' has the same name as its class}} expected-error 0-1{{extension}} + }; + struct D { + template<typename T> using D = int; // expected-error {{member 'D' has the same name as its class}} expected-error 0-1{{extension}} + }; +} + #if __cplusplus >= 201103L namespace dr1940 { // dr1940: yes static union { diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp index cc6c5af81708..d8d9307a5ebb 100644 --- a/test/CXX/drs/dr1xx.cpp +++ b/test/CXX/drs/dr1xx.cpp @@ -943,10 +943,10 @@ namespace dr188 { // dr188: yes namespace dr194 { // dr194: yes struct A { A(); - void A(); // expected-error {{has the same name as its class}} expected-error {{constructor cannot have a return type}} + void A(); // expected-error {{constructor cannot have a return type}} }; struct B { - void B(); // expected-error {{has the same name as its class}} expected-error {{constructor cannot have a return type}} + void B(); // expected-error {{constructor cannot have a return type}} B(); }; struct C { diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp index 5ac4f013b7fd..c438fccebd6b 100644 --- a/test/CXX/drs/dr3xx.cpp +++ b/test/CXX/drs/dr3xx.cpp @@ -110,18 +110,6 @@ namespace dr305 { // dr305: no x->~X<char>(); // expected-error {{no member named}} } - // FIXME: This appears to be valid (but allowing the nested types might be a - // defect). - template<typename> struct Nested { - template<typename> struct Nested {}; - }; - void testNested(Nested<int> n) { n.~Nested<int>(); } // expected-error {{no member named}} -#if __cplusplus < 201103L - // expected-error@-2 {{ambiguous}} - // expected-note@-6 {{here}} - // expected-note@-6 {{here}} -#endif - #if __cplusplus >= 201103L struct Y { template<typename T> using T1 = Y; diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index d027c7a388bb..2adefd928afb 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -157,7 +157,7 @@ namespace UndefinedBehavior { constexpr int shl_unsigned_negative = unsigned(-3) << 1; // ok constexpr int shl_unsigned_into_sign = 1u << 31; // ok constexpr int shl_unsigned_overflow = 1024u << 31; // ok - constexpr int shl_signed_negative = (-3) << 1; // expected-error {{constant expression}} expected-note {{left shift of negative value -3}} + constexpr int shl_signed_negative = (-3) << 1; // expected-warning {{shifting a negative signed value is undefined}} // expected-error {{constant expression}} expected-note {{left shift of negative value -3}} constexpr int shl_signed_ok = 1 << 30; // ok constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457) constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457) diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp index 5c1029f1a3ff..e299705a4c11 100644 --- a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp +++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++11 -include %S/ser.h %s -o - | FileCheck %s // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-pch -o %t-ser.pch -std=c++11 -x c++ %S/ser.h // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++11 -include-pch %t-ser.pch %s -o - | FileCheck %s diff --git a/test/CodeGen/align-systemz.c b/test/CodeGen/align-systemz.c index 68a21e39ab36..eaa1de64d344 100644 --- a/test/CodeGen/align-systemz.c +++ b/test/CodeGen/align-systemz.c @@ -25,3 +25,19 @@ void func (void) s = es; } + +// Alignment should be respected for coerced argument loads + +struct arg { long y __attribute__((packed, aligned(4))); }; + +extern struct arg x; +void f(struct arg); + +void test (void) +{ + f(x); +} + +// CHECK-LABEL: @test +// CHECK: load i64, i64* getelementptr inbounds (%struct.arg, %struct.arg* @x, i32 0, i32 0), align 4 + diff --git a/test/CodeGen/arm-long-calls.c b/test/CodeGen/arm-long-calls.c new file mode 100644 index 000000000000..fdd7babe9fe6 --- /dev/null +++ b/test/CodeGen/arm-long-calls.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -target-feature +long-calls -emit-llvm -o - %s | FileCheck -check-prefix=LONGCALL %s +// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -emit-llvm -o - %s | FileCheck -check-prefix=NOLONGCALL %s + +// LONGCALL: attributes #0 = { {{.*}} "target-features"="+long-calls" +// NOLONGCALL-NOT: attributes #0 = { {{.*}} "target-features"="+long-calls" + +int foo1(int a) { return a; } diff --git a/test/CodeGen/arm64-abi-vector.c b/test/CodeGen/arm64-abi-vector.c index 4566c417909b..ebf7f5112659 100644 --- a/test/CodeGen/arm64-abi-vector.c +++ b/test/CodeGen/arm64-abi-vector.c @@ -309,7 +309,7 @@ __attribute__((noinline)) double args_vec_5c(int fixed, __char5 c5) { // CHECK: args_vec_5c // CHECK: [[C5:%.*]] = alloca <5 x i8>, align 8 // CHECK: [[TMP:%.*]] = bitcast <5 x i8>* [[C5]] to <2 x i32>* -// CHECK: store <2 x i32> {{%.*}}, <2 x i32>* [[TMP]], align 1 +// CHECK: store <2 x i32> {{%.*}}, <2 x i32>* [[TMP]], align 8 double sum = fixed; sum = sum + c5.x + c5.y; return sum; @@ -325,7 +325,7 @@ __attribute__((noinline)) double args_vec_9c(int fixed, __char9 c9) { // CHECK: args_vec_9c // CHECK: [[C9:%.*]] = alloca <9 x i8>, align 16 // CHECK: [[TMP:%.*]] = bitcast <9 x i8>* [[C9]] to <4 x i32>* -// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 1 +// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 16 double sum = fixed; sum = sum + c9.x + c9.y; return sum; @@ -355,7 +355,7 @@ __attribute__((noinline)) double args_vec_3s(int fixed, __short3 c3) { // CHECK: args_vec_3s // CHECK: [[C3:%.*]] = alloca <3 x i16>, align 8 // CHECK: [[TMP:%.*]] = bitcast <3 x i16>* [[C3]] to <2 x i32>* -// CHECK: store <2 x i32> {{%.*}}, <2 x i32>* [[TMP]], align 1 +// CHECK: store <2 x i32> {{%.*}}, <2 x i32>* [[TMP]], align 8 double sum = fixed; sum = sum + c3.x + c3.y; return sum; @@ -371,7 +371,7 @@ __attribute__((noinline)) double args_vec_5s(int fixed, __short5 c5) { // CHECK: args_vec_5s // CHECK: [[C5:%.*]] = alloca <5 x i16>, align 16 // CHECK: [[TMP:%.*]] = bitcast <5 x i16>* [[C5]] to <4 x i32>* -// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 1 +// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 16 double sum = fixed; sum = sum + c5.x + c5.y; return sum; @@ -387,7 +387,7 @@ __attribute__((noinline)) double args_vec_3i(int fixed, __int3 c3) { // CHECK: args_vec_3i // CHECK: [[C3:%.*]] = alloca <3 x i32>, align 16 // CHECK: [[TMP:%.*]] = bitcast <3 x i32>* [[C3]] to <4 x i32>* -// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 1 +// CHECK: store <4 x i32> {{%.*}}, <4 x i32>* [[TMP]], align 16 double sum = fixed; sum = sum + c3.x + c3.y; return sum; diff --git a/test/CodeGen/arm64-arguments.c b/test/CodeGen/arm64-arguments.c index 4486bb4b18e2..8b551c4af470 100644 --- a/test/CodeGen/arm64-arguments.c +++ b/test/CodeGen/arm64-arguments.c @@ -219,8 +219,8 @@ int32x4_t f36(int i, s36_with_align s1, s36_with_align s2) { // CHECK: define <4 x i32> @f36(i32 %i, i128 %s1.coerce, i128 %s2.coerce) // CHECK: %s1 = alloca %struct.s36, align 16 // CHECK: %s2 = alloca %struct.s36, align 16 -// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 1 -// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 1 +// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 16 +// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 16 // CHECK: %[[a:.*]] = bitcast %struct.s36* %s1 to <4 x i32>* // CHECK: load <4 x i32>, <4 x i32>* %[[a]], align 16 // CHECK: %[[b:.*]] = bitcast %struct.s36* %s2 to <4 x i32>* @@ -275,8 +275,8 @@ int f38(int i, s38_no_align s1, s38_no_align s2) { // CHECK: define i32 @f38(i32 %i, i64 %s1.coerce, i64 %s2.coerce) // CHECK: %s1 = alloca %struct.s38, align 8 // CHECK: %s2 = alloca %struct.s38, align 8 -// CHECK: store i64 %s1.coerce, i64* %{{.*}}, align 1 -// CHECK: store i64 %s2.coerce, i64* %{{.*}}, align 1 +// CHECK: store i64 %s1.coerce, i64* %{{.*}}, align 8 +// CHECK: store i64 %s2.coerce, i64* %{{.*}}, align 8 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s1, i32 0, i32 1 @@ -287,8 +287,8 @@ s38_no_align g38; s38_no_align g38_2; int caller38() { // CHECK: define i32 @caller38() -// CHECK: %[[a:.*]] = load i64, i64* bitcast (%struct.s38* @g38 to i64*), align 1 -// CHECK: %[[b:.*]] = load i64, i64* bitcast (%struct.s38* @g38_2 to i64*), align 1 +// CHECK: %[[a:.*]] = load i64, i64* bitcast (%struct.s38* @g38 to i64*), align 4 +// CHECK: %[[b:.*]] = load i64, i64* bitcast (%struct.s38* @g38_2 to i64*), align 4 // CHECK: call i32 @f38(i32 3, i64 %[[a]], i64 %[[b]]) return f38(3, g38, g38_2); } @@ -299,8 +299,8 @@ int f38_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, // CHECK: define i32 @f38_stack(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i64 %s1.coerce, i64 %s2.coerce) // CHECK: %s1 = alloca %struct.s38, align 8 // CHECK: %s2 = alloca %struct.s38, align 8 -// CHECK: store i64 %s1.coerce, i64* %{{.*}}, align 1 -// CHECK: store i64 %s2.coerce, i64* %{{.*}}, align 1 +// CHECK: store i64 %s1.coerce, i64* %{{.*}}, align 8 +// CHECK: store i64 %s2.coerce, i64* %{{.*}}, align 8 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s38, %struct.s38* %s1, i32 0, i32 1 @@ -309,8 +309,8 @@ int f38_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, } int caller38_stack() { // CHECK: define i32 @caller38_stack() -// CHECK: %[[a:.*]] = load i64, i64* bitcast (%struct.s38* @g38 to i64*), align 1 -// CHECK: %[[b:.*]] = load i64, i64* bitcast (%struct.s38* @g38_2 to i64*), align 1 +// CHECK: %[[a:.*]] = load i64, i64* bitcast (%struct.s38* @g38 to i64*), align 4 +// CHECK: %[[b:.*]] = load i64, i64* bitcast (%struct.s38* @g38_2 to i64*), align 4 // CHECK: call i32 @f38_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i64 %[[a]], i64 %[[b]]) return f38_stack(1, 2, 3, 4, 5, 6, 7, 8, 9, g38, g38_2); } @@ -328,8 +328,8 @@ int f39(int i, s39_with_align s1, s39_with_align s2) { // CHECK: define i32 @f39(i32 %i, i128 %s1.coerce, i128 %s2.coerce) // CHECK: %s1 = alloca %struct.s39, align 16 // CHECK: %s2 = alloca %struct.s39, align 16 -// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 1 -// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 1 +// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 16 +// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 16 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s1, i32 0, i32 1 @@ -340,8 +340,8 @@ s39_with_align g39; s39_with_align g39_2; int caller39() { // CHECK: define i32 @caller39() -// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s39* @g39 to i128*), align 1 -// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s39* @g39_2 to i128*), align 1 +// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s39* @g39 to i128*), align 16 +// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s39* @g39_2 to i128*), align 16 // CHECK: call i32 @f39(i32 3, i128 %[[a]], i128 %[[b]]) return f39(3, g39, g39_2); } @@ -352,8 +352,8 @@ int f39_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, // CHECK: define i32 @f39_stack(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i128 %s1.coerce, i128 %s2.coerce) // CHECK: %s1 = alloca %struct.s39, align 16 // CHECK: %s2 = alloca %struct.s39, align 16 -// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 1 -// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 1 +// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 16 +// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 16 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s39, %struct.s39* %s1, i32 0, i32 1 @@ -362,8 +362,8 @@ int f39_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, } int caller39_stack() { // CHECK: define i32 @caller39_stack() -// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s39* @g39 to i128*), align 1 -// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s39* @g39_2 to i128*), align 1 +// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s39* @g39 to i128*), align 16 +// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s39* @g39_2 to i128*), align 16 // CHECK: call i32 @f39_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i128 %[[a]], i128 %[[b]]) return f39_stack(1, 2, 3, 4, 5, 6, 7, 8, 9, g39, g39_2); } @@ -383,8 +383,8 @@ int f40(int i, s40_no_align s1, s40_no_align s2) { // CHECK: define i32 @f40(i32 %i, [2 x i64] %s1.coerce, [2 x i64] %s2.coerce) // CHECK: %s1 = alloca %struct.s40, align 8 // CHECK: %s2 = alloca %struct.s40, align 8 -// CHECK: store [2 x i64] %s1.coerce, [2 x i64]* %{{.*}}, align 1 -// CHECK: store [2 x i64] %s2.coerce, [2 x i64]* %{{.*}}, align 1 +// CHECK: store [2 x i64] %s1.coerce, [2 x i64]* %{{.*}}, align 8 +// CHECK: store [2 x i64] %s2.coerce, [2 x i64]* %{{.*}}, align 8 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s1, i32 0, i32 1 @@ -395,8 +395,8 @@ s40_no_align g40; s40_no_align g40_2; int caller40() { // CHECK: define i32 @caller40() -// CHECK: %[[a:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40 to [2 x i64]*), align 1 -// CHECK: %[[b:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40_2 to [2 x i64]*), align 1 +// CHECK: %[[a:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40 to [2 x i64]*), align 4 +// CHECK: %[[b:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40_2 to [2 x i64]*), align 4 // CHECK: call i32 @f40(i32 3, [2 x i64] %[[a]], [2 x i64] %[[b]]) return f40(3, g40, g40_2); } @@ -407,8 +407,8 @@ int f40_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, // CHECK: define i32 @f40_stack(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, [2 x i64] %s1.coerce, [2 x i64] %s2.coerce) // CHECK: %s1 = alloca %struct.s40, align 8 // CHECK: %s2 = alloca %struct.s40, align 8 -// CHECK: store [2 x i64] %s1.coerce, [2 x i64]* %{{.*}}, align 1 -// CHECK: store [2 x i64] %s2.coerce, [2 x i64]* %{{.*}}, align 1 +// CHECK: store [2 x i64] %s1.coerce, [2 x i64]* %{{.*}}, align 8 +// CHECK: store [2 x i64] %s2.coerce, [2 x i64]* %{{.*}}, align 8 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s40, %struct.s40* %s1, i32 0, i32 1 @@ -417,8 +417,8 @@ int f40_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, } int caller40_stack() { // CHECK: define i32 @caller40_stack() -// CHECK: %[[a:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40 to [2 x i64]*), align 1 -// CHECK: %[[b:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40_2 to [2 x i64]*), align 1 +// CHECK: %[[a:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40 to [2 x i64]*), align 4 +// CHECK: %[[b:.*]] = load [2 x i64], [2 x i64]* bitcast (%struct.s40* @g40_2 to [2 x i64]*), align 4 // CHECK: call i32 @f40_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, [2 x i64] %[[a]], [2 x i64] %[[b]]) return f40_stack(1, 2, 3, 4, 5, 6, 7, 8, 9, g40, g40_2); } @@ -438,8 +438,8 @@ int f41(int i, s41_with_align s1, s41_with_align s2) { // CHECK: define i32 @f41(i32 %i, i128 %s1.coerce, i128 %s2.coerce) // CHECK: %s1 = alloca %struct.s41, align 16 // CHECK: %s2 = alloca %struct.s41, align 16 -// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 1 -// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 1 +// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 16 +// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 16 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s1, i32 0, i32 1 @@ -450,8 +450,8 @@ s41_with_align g41; s41_with_align g41_2; int caller41() { // CHECK: define i32 @caller41() -// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s41* @g41 to i128*), align 1 -// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s41* @g41_2 to i128*), align 1 +// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s41* @g41 to i128*), align 16 +// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s41* @g41_2 to i128*), align 16 // CHECK: call i32 @f41(i32 3, i128 %[[a]], i128 %[[b]]) return f41(3, g41, g41_2); } @@ -462,8 +462,8 @@ int f41_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, // CHECK: define i32 @f41_stack(i32 %i, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i128 %s1.coerce, i128 %s2.coerce) // CHECK: %s1 = alloca %struct.s41, align 16 // CHECK: %s2 = alloca %struct.s41, align 16 -// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 1 -// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 1 +// CHECK: store i128 %s1.coerce, i128* %{{.*}}, align 16 +// CHECK: store i128 %s2.coerce, i128* %{{.*}}, align 16 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s1, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s2, i32 0, i32 0 // CHECK: getelementptr inbounds %struct.s41, %struct.s41* %s1, i32 0, i32 1 @@ -472,8 +472,8 @@ int f41_stack(int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8, } int caller41_stack() { // CHECK: define i32 @caller41_stack() -// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s41* @g41 to i128*), align 1 -// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s41* @g41_2 to i128*), align 1 +// CHECK: %[[a:.*]] = load i128, i128* bitcast (%struct.s41* @g41 to i128*), align 16 +// CHECK: %[[b:.*]] = load i128, i128* bitcast (%struct.s41* @g41_2 to i128*), align 16 // CHECK: call i32 @f41_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i128 %[[a]], i128 %[[b]]) return f41_stack(1, 2, 3, 4, 5, 6, 7, 8, 9, g41, g41_2); } diff --git a/test/CodeGen/arm64-be-bitfield.c b/test/CodeGen/arm64-be-bitfield.c index b8d497c5580d..132239ab8313 100644 --- a/test/CodeGen/arm64-be-bitfield.c +++ b/test/CodeGen/arm64-be-bitfield.c @@ -7,7 +7,7 @@ struct bt3 { signed b2:10; signed b3:10; } b16; // Get the high 32-bits and then shift appropriately for big-endian. signed callee_b0f(struct bt3 bp11) { // IR: callee_b0f(i64 [[ARG:%.*]]) -// IR: store i64 [[ARG]], i64* [[PTR:%.*]] +// IR: store i64 [[ARG]], i64* [[PTR:%.*]], align 8 // IR: [[BITCAST:%.*]] = bitcast i64* [[PTR]] to i8* // IR: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* [[BITCAST]], i64 4 // ARM: asr x0, x0, #54 diff --git a/test/CodeGen/asm-attrs.c b/test/CodeGen/asm-attrs.c new file mode 100644 index 000000000000..ae7287953e0c --- /dev/null +++ b/test/CodeGen/asm-attrs.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple armv7-apple-darwin -emit-llvm %s -o - | FileCheck %s + +// CHECK: call i32 asm "foo0", {{.*}} [[READNONE:#[0-9]+]] +// CHECK: call i32 asm "foo1", {{.*}} [[READNONE]] +// CHECK: call i32 asm "foo2", {{.*}} [[NOATTRS:#[0-9]+]] +// CHECK: call i32 asm sideeffect "foo3", {{.*}} [[NOATTRS]] +// CHECK: call i32 asm "foo4", {{.*}} [[READONLY:#[0-9]+]] +// CHECK: call i32 asm "foo5", {{.*}} [[READONLY]] +// CHECK: call i32 asm "foo6", {{.*}} [[NOATTRS]] +// CHECK: call void asm sideeffect "foo7", {{.*}} [[NOATTRS]] +// CHECK: call void asm "foo8", {{.*}} [[NOATTRS]] + +// CHECK: attributes [[READNONE]] = { nounwind readnone } +// CHECK: attributes [[NOATTRS]] = { nounwind } +// CHECK: attributes [[READONLY]] = { nounwind readonly } + +int g0, g1; + +struct S { + int i; +} g2; + +void test_attrs(int a) { + __asm__ ("foo0" : "=r"(g1) : "r"(a)); + __asm__ ("foo1" : "=r"(g1) : "r"(a) : "cc"); + __asm__ ("foo2" : "=r"(g1) : "r"(a) : "memory"); + __asm__ volatile("foo3" : "=r"(g1) : "r"(a)); + __asm__ ("foo4" : "=r"(g1) : "r"(a), "m"(g0)); + __asm__ ("foo5" : "=r"(g1) : "r"(a), "Q"(g0)); + __asm__ ("foo6" : "=r"(g1), "=m"(g0) : "r"(a)); + __asm__ ("foo7" : : "r"(a)); + __asm__ ("foo8" : "=r"(g2) : "r"(a)); +} diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c index 13ab5f117f93..d8f7d28392a5 100644 --- a/test/CodeGen/atomic-ops.c +++ b/test/CodeGen/atomic-ops.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -triple=i686-apple-darwin9 | FileCheck %s +// REQUIRES: x86-registered-target // Also test serialization of atomic operations here, to avoid duplicating the // test. diff --git a/test/CodeGen/attr-target.c b/test/CodeGen/attr-target.c index 7ea5fe5a07a0..d805d133f365 100644 --- a/test/CodeGen/attr-target.c +++ b/test/CodeGen/attr-target.c @@ -13,6 +13,8 @@ int __attribute__((target("sse4"))) panda(int a) { return 4; } int bar(int a) { return baz(a) + foo(a); } +int __attribute__((target("avx, sse4.2, arch= ivybridge"))) qux(int a) { return 4; } + // Check that we emit the additional subtarget and cpu features for foo and not for baz or bar. // CHECK: baz{{.*}} #0 // CHECK: foo{{.*}} #1 @@ -22,6 +24,7 @@ int bar(int a) { return baz(a) + foo(a); } // CHECK: koala{{.*}} #0 // CHECK: echidna{{.*}} #2 // CHECK: bar{{.*}} #0 +// CHECK: qux{{.*}} #1 // CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,+sse2" // CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3" // CHECK: #2 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop" diff --git a/test/CodeGen/available-externally-hidden.cpp b/test/CodeGen/available-externally-hidden.cpp new file mode 100644 index 000000000000..dc13f26b7526 --- /dev/null +++ b/test/CodeGen/available-externally-hidden.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -O2 -fvisibility hidden -std=c++11 -emit-llvm -o - -triple x86_64-apple-darwin10 %s | FileCheck %s + +// Ensure that available_externally functions eliminated at -O2 are now +// declarations, and are not emitted as hidden with -fvisibility=hidden, +// but rather with default visibility. +struct Filter { + virtual void Foo(); + int a; +}; + +class Message{}; +class Sender { + public: + virtual bool Send(Message* msg) = 0; + + protected: + virtual ~Sender() {} +}; + +// CHECK: declare zeroext i1 @_ZThn16_N17SyncMessageFilter4SendEP7Message +class SyncMessageFilter : public Filter, public Sender { + public: + bool Send(Message* message) override; +}; + +class TestSyncMessageFilter : public SyncMessageFilter { +}; + +int main() { +TestSyncMessageFilter* f = new TestSyncMessageFilter; + f->Send(new Message); +} diff --git a/test/CodeGen/available-externally-suppress.c b/test/CodeGen/available-externally-suppress.c index 390d2017884a..a25a28271277 100644 --- a/test/CodeGen/available-externally-suppress.c +++ b/test/CodeGen/available-externally-suppress.c @@ -1,12 +1,18 @@ // RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-apple-darwin10 %s | FileCheck %s +// RUN: %clang_cc1 -O2 -fno-inline -emit-llvm -o - -triple x86_64-apple-darwin10 %s | FileCheck %s +// RUN: %clang_cc1 -flto -O2 -fno-inline -emit-llvm -o - -triple x86_64-apple-darwin10 %s | FileCheck %s -check-prefix=LTO // Ensure that we don't emit available_externally functions at -O0. +// Also should not emit them at -O2, unless -flto is present in which case +// we should preserve them for link-time inlining decisions. int x; inline void f0(int y) { x = y; } // CHECK-LABEL: define void @test() // CHECK: declare void @f0(i32) +// LTO-LABEL: define void @test() +// LTO: define available_externally void @f0 void test() { f0(17); } @@ -19,9 +25,13 @@ inline int __attribute__((always_inline)) f1(int x) { } // CHECK: @test1 +// LTO: @test1 int test1(int x) { // CHECK: br i1 // CHECK-NOT: call {{.*}} @f1 // CHECK: ret i32 + // LTO: br i1 + // LTO-NOT: call {{.*}} @f1 + // LTO: ret i32 return f1(x); } diff --git a/test/CodeGen/avx512vlbw-builtins.c b/test/CodeGen/avx512vlbw-builtins.c index a4a12440dc11..7aa8b873dc42 100644 --- a/test/CodeGen/avx512vlbw-builtins.c +++ b/test/CodeGen/avx512vlbw-builtins.c @@ -792,3 +792,588 @@ __m128i test_mm_maskz_mullo_epi16 (__mmask8 __U, __m128i __A, __m128i __B) { //CHECK: @llvm.x86.avx512.mask.pmull.w.128 return _mm_maskz_mullo_epi16(__U , __A, __B); } + + +__m128i test_mm_mask_blend_epi8(__mmask16 __U, __m128i __A, __m128i __W) { + // CHECK-LABEL: @test_mm_mask_blend_epi8 + // CHECK: @llvm.x86.avx512.mask.blend.b.128 + return _mm_mask_blend_epi8(__U,__A,__W); +} +__m256i test_mm256_mask_blend_epi8(__mmask32 __U, __m256i __A, __m256i __W) { + // CHECK-LABEL: @test_mm256_mask_blend_epi8 + // CHECK: @llvm.x86.avx512.mask.blend.b.256 + return _mm256_mask_blend_epi8(__U,__A,__W); +} + +__m128i test_mm_mask_blend_epi16(__mmask8 __U, __m128i __A, __m128i __W) { + // CHECK-LABEL: @test_mm_mask_blend_epi16 + // CHECK: @llvm.x86.avx512.mask.blend.w.128 + return _mm_mask_blend_epi16(__U,__A,__W); +} + +__m256i test_mm256_mask_blend_epi16(__mmask16 __U, __m256i __A, __m256i __W) { + // CHECK-LABEL: @test_mm256_mask_blend_epi16 + // CHECK: @llvm.x86.avx512.mask.blend.w.256 + return _mm256_mask_blend_epi16(__U,__A,__W); +} + +__m128i test_mm_mask_abs_epi8(__m128i __W, __mmask16 __U, __m128i __A) { + // CHECK-LABEL: @test_mm_mask_abs_epi8 + // CHECK: @llvm.x86.avx512.mask.pabs.b.128 + return _mm_mask_abs_epi8(__W,__U,__A); +} + +__m128i test_mm_maskz_abs_epi8(__mmask16 __U, __m128i __A) { + // CHECK-LABEL: @test_mm_maskz_abs_epi8 + // CHECK: @llvm.x86.avx512.mask.pabs.b.128 + return _mm_maskz_abs_epi8(__U,__A); +} + +__m256i test_mm256_mask_abs_epi8(__m256i __W, __mmask32 __U, __m256i __A) { + // CHECK-LABEL: @test_mm256_mask_abs_epi8 + // CHECK: @llvm.x86.avx512.mask.pabs.b.256 + return _mm256_mask_abs_epi8(__W,__U,__A); +} + +__m256i test_mm256_maskz_abs_epi8(__mmask32 __U, __m256i __A) { + // CHECK-LABEL: @test_mm256_maskz_abs_epi8 + // CHECK: @llvm.x86.avx512.mask.pabs.b.256 + return _mm256_maskz_abs_epi8(__U,__A); +} + +__m128i test_mm_mask_abs_epi16(__m128i __W, __mmask8 __U, __m128i __A) { + // CHECK-LABEL: @test_mm_mask_abs_epi16 + // CHECK: @llvm.x86.avx512.mask.pabs.w.128 + return _mm_mask_abs_epi16(__W,__U,__A); +} + +__m128i test_mm_maskz_abs_epi16(__mmask8 __U, __m128i __A) { + // CHECK-LABEL: @test_mm_maskz_abs_epi16 + // CHECK: @llvm.x86.avx512.mask.pabs.w.128 + return _mm_maskz_abs_epi16(__U,__A); +} + +__m256i test_mm256_mask_abs_epi16(__m256i __W, __mmask16 __U, __m256i __A) { + // CHECK-LABEL: @test_mm256_mask_abs_epi16 + // CHECK: @llvm.x86.avx512.mask.pabs.w.256 + return _mm256_mask_abs_epi16(__W,__U,__A); +} + +__m256i test_mm256_maskz_abs_epi16(__mmask16 __U, __m256i __A) { + // CHECK-LABEL: @test_mm256_maskz_abs_epi16 + // CHECK: @llvm.x86.avx512.mask.pabs.w.256 + return _mm256_maskz_abs_epi16(__U,__A); +} + +__m128i test_mm_maskz_packs_epi32(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_packs_epi32 + // CHECK: @llvm.x86.avx512.mask.packssdw.128 + return _mm_maskz_packs_epi32(__M,__A,__B); +} +__m128i test_mm_mask_packs_epi32(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_packs_epi32 + // CHECK: @llvm.x86.avx512.mask.packssdw.128 + return _mm_mask_packs_epi32(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_packs_epi32(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_packs_epi32 + // CHECK: @llvm.x86.avx512.mask.packssdw.256 + return _mm256_maskz_packs_epi32(__M,__A,__B); +} +__m256i test_mm256_mask_packs_epi32(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_packs_epi32 + // CHECK: @llvm.x86.avx512.mask.packssdw.256 + return _mm256_mask_packs_epi32(__W,__M,__A,__B); +} +__m128i test_mm_maskz_packs_epi16(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_packs_epi16 + // CHECK: @llvm.x86.avx512.mask.packsswb.128 + return _mm_maskz_packs_epi16(__M,__A,__B); +} +__m128i test_mm_mask_packs_epi16(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_packs_epi16 + // CHECK: @llvm.x86.avx512.mask.packsswb.128 + return _mm_mask_packs_epi16(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_packs_epi16(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_packs_epi16 + // CHECK: @llvm.x86.avx512.mask.packsswb.256 + return _mm256_maskz_packs_epi16(__M,__A,__B); +} +__m256i test_mm256_mask_packs_epi16(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_packs_epi16 + // CHECK: @llvm.x86.avx512.mask.packsswb.256 + return _mm256_mask_packs_epi16(__W,__M,__A,__B); +} + +__m128i test_mm_mask_packus_epi32(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_packus_epi32 + // CHECK: @llvm.x86.avx512.mask.packusdw.128 + return _mm_mask_packus_epi32(__W,__M,__A,__B); +} + +__m128i test_mm_maskz_packus_epi32(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_packus_epi32 + // CHECK: @llvm.x86.avx512.mask.packusdw.128 + return _mm_maskz_packus_epi32(__M,__A,__B); +} + +__m256i test_mm256_maskz_packus_epi32(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_packus_epi32 + // CHECK: @llvm.x86.avx512.mask.packusdw.256 + return _mm256_maskz_packus_epi32(__M,__A,__B); +} + +__m256i test_mm256_mask_packus_epi32(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_packus_epi32 + // CHECK: @llvm.x86.avx512.mask.packusdw.256 + return _mm256_mask_packus_epi32(__W,__M,__A,__B); +} + +__m128i test_mm_maskz_packus_epi16(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_packus_epi16 + // CHECK: @llvm.x86.avx512.mask.packuswb.128 + return _mm_maskz_packus_epi16(__M,__A,__B); +} + +__m128i test_mm_mask_packus_epi16(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_packus_epi16 + // CHECK: @llvm.x86.avx512.mask.packuswb.128 + return _mm_mask_packus_epi16(__W,__M,__A,__B); +} + +__m256i test_mm256_maskz_packus_epi16(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_packus_epi16 + // CHECK: @llvm.x86.avx512.mask.packuswb.256 + return _mm256_maskz_packus_epi16(__M,__A,__B); +} + +__m256i test_mm256_mask_packus_epi16(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_packus_epi16 + // CHECK: @llvm.x86.avx512.mask.packuswb.256 + return _mm256_mask_packus_epi16(__W,__M,__A,__B); +} + +__m128i test_mm_mask_adds_epi8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_adds_epi8 + // CHECK: @llvm.x86.avx512.mask.padds.b.128 + return _mm_mask_adds_epi8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_adds_epi8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_adds_epi8 + // CHECK: @llvm.x86.avx512.mask.padds.b.128 + return _mm_maskz_adds_epi8(__U,__A,__B); +} +__m256i test_mm256_mask_adds_epi8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_adds_epi8 + // CHECK: @llvm.x86.avx512.mask.padds.b.256 + return _mm256_mask_adds_epi8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_adds_epi8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_adds_epi8 + // CHECK: @llvm.x86.avx512.mask.padds.b.256 + return _mm256_maskz_adds_epi8(__U,__A,__B); +} +__m128i test_mm_mask_adds_epi16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_adds_epi16 + // CHECK: @llvm.x86.avx512.mask.padds.w.128 + return _mm_mask_adds_epi16(__W,__U,__A,__B); +} +__m128i test_mm_maskz_adds_epi16(__mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_adds_epi16 + // CHECK: @llvm.x86.avx512.mask.padds.w.128 + return _mm_maskz_adds_epi16(__U,__A,__B); +} +__m256i test_mm256_mask_adds_epi16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_adds_epi16 + // CHECK: @llvm.x86.avx512.mask.padds.w.256 + return _mm256_mask_adds_epi16(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_adds_epi16(__mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_adds_epi16 + // CHECK: @llvm.x86.avx512.mask.padds.w.256 + return _mm256_maskz_adds_epi16(__U,__A,__B); +} +__m128i test_mm_mask_adds_epu8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_adds_epu8 + // CHECK: @llvm.x86.avx512.mask.paddus.b.128 + return _mm_mask_adds_epu8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_adds_epu8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_adds_epu8 + // CHECK: @llvm.x86.avx512.mask.paddus.b.128 + return _mm_maskz_adds_epu8(__U,__A,__B); +} +__m256i test_mm256_mask_adds_epu8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_adds_epu8 + // CHECK: @llvm.x86.avx512.mask.paddus.b.256 + return _mm256_mask_adds_epu8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_adds_epu8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_adds_epu8 + // CHECK: @llvm.x86.avx512.mask.paddus.b.256 + return _mm256_maskz_adds_epu8(__U,__A,__B); +} +__m128i test_mm_mask_adds_epu16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_adds_epu16 + // CHECK: @llvm.x86.avx512.mask.paddus.w.128 + return _mm_mask_adds_epu16(__W,__U,__A,__B); +} +__m128i test_mm_maskz_adds_epu16(__mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_adds_epu16 + // CHECK: @llvm.x86.avx512.mask.paddus.w.128 + return _mm_maskz_adds_epu16(__U,__A,__B); +} +__m256i test_mm256_mask_adds_epu16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_adds_epu16 + // CHECK: @llvm.x86.avx512.mask.paddus.w.256 + return _mm256_mask_adds_epu16(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_adds_epu16(__mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_adds_epu16 + // CHECK: @llvm.x86.avx512.mask.paddus.w.256 + return _mm256_maskz_adds_epu16(__U,__A,__B); +} +__m128i test_mm_mask_avg_epu8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_avg_epu8 + // CHECK: @llvm.x86.avx512.mask.pavg.b.128 + return _mm_mask_avg_epu8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_avg_epu8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_avg_epu8 + // CHECK: @llvm.x86.avx512.mask.pavg.b.128 + return _mm_maskz_avg_epu8(__U,__A,__B); +} +__m256i test_mm256_mask_avg_epu8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_avg_epu8 + // CHECK: @llvm.x86.avx512.mask.pavg.b.256 + return _mm256_mask_avg_epu8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_avg_epu8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_avg_epu8 + // CHECK: @llvm.x86.avx512.mask.pavg.b.256 + return _mm256_maskz_avg_epu8(__U,__A,__B); +} +__m128i test_mm_mask_avg_epu16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_avg_epu16 + // CHECK: @llvm.x86.avx512.mask.pavg.w.128 + return _mm_mask_avg_epu16(__W,__U,__A,__B); +} +__m128i test_mm_maskz_avg_epu16(__mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_avg_epu16 + // CHECK: @llvm.x86.avx512.mask.pavg.w.128 + return _mm_maskz_avg_epu16(__U,__A,__B); +} +__m256i test_mm256_mask_avg_epu16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_avg_epu16 + // CHECK: @llvm.x86.avx512.mask.pavg.w.256 + return _mm256_mask_avg_epu16(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_avg_epu16(__mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_avg_epu16 + // CHECK: @llvm.x86.avx512.mask.pavg.w.256 + return _mm256_maskz_avg_epu16(__U,__A,__B); +} +__m128i test_mm_maskz_max_epi8(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_max_epi8 + // CHECK: @llvm.x86.avx512.mask.pmaxs.b.128 + return _mm_maskz_max_epi8(__M,__A,__B); +} +__m128i test_mm_mask_max_epi8(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_max_epi8 + // CHECK: @llvm.x86.avx512.mask.pmaxs.b.128 + return _mm_mask_max_epi8(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_max_epi8(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_max_epi8 + // CHECK: @llvm.x86.avx512.mask.pmaxs.b.256 + return _mm256_maskz_max_epi8(__M,__A,__B); +} +__m256i test_mm256_mask_max_epi8(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_max_epi8 + // CHECK: @llvm.x86.avx512.mask.pmaxs.b.256 + return _mm256_mask_max_epi8(__W,__M,__A,__B); +} +__m128i test_mm_maskz_max_epi16(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_max_epi16 + // CHECK: @llvm.x86.avx512.mask.pmaxs.w.128 + return _mm_maskz_max_epi16(__M,__A,__B); +} +__m128i test_mm_mask_max_epi16(__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_max_epi16 + // CHECK: @llvm.x86.avx512.mask.pmaxs.w.128 + return _mm_mask_max_epi16(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_max_epi16(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_max_epi16 + // CHECK: @llvm.x86.avx512.mask.pmaxs.w.256 + return _mm256_maskz_max_epi16(__M,__A,__B); +} +__m256i test_mm256_mask_max_epi16(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_max_epi16 + // CHECK: @llvm.x86.avx512.mask.pmaxs.w.256 + return _mm256_mask_max_epi16(__W,__M,__A,__B); +} +__m128i test_mm_maskz_max_epu8(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_max_epu8 + // CHECK: @llvm.x86.avx512.mask.pmaxu.b.128 + return _mm_maskz_max_epu8(__M,__A,__B); +} +__m128i test_mm_mask_max_epu8(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_max_epu8 + // CHECK: @llvm.x86.avx512.mask.pmaxu.b.128 + return _mm_mask_max_epu8(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_max_epu8(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_max_epu8 + // CHECK: @llvm.x86.avx512.mask.pmaxu.b.256 + return _mm256_maskz_max_epu8(__M,__A,__B); +} +__m256i test_mm256_mask_max_epu8(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_max_epu8 + // CHECK: @llvm.x86.avx512.mask.pmaxu.b.256 + return _mm256_mask_max_epu8(__W,__M,__A,__B); +} +__m128i test_mm_maskz_max_epu16(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_max_epu16 + // CHECK: @llvm.x86.avx512.mask.pmaxu.w.128 + return _mm_maskz_max_epu16(__M,__A,__B); +} +__m128i test_mm_mask_max_epu16(__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_max_epu16 + // CHECK: @llvm.x86.avx512.mask.pmaxu.w.128 + return _mm_mask_max_epu16(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_max_epu16(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_max_epu16 + // CHECK: @llvm.x86.avx512.mask.pmaxu.w.256 + return _mm256_maskz_max_epu16(__M,__A,__B); +} +__m256i test_mm256_mask_max_epu16(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_max_epu16 + // CHECK: @llvm.x86.avx512.mask.pmaxu.w.256 + return _mm256_mask_max_epu16(__W,__M,__A,__B); +} +__m128i test_mm_maskz_min_epi8(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_min_epi8 + // CHECK: @llvm.x86.avx512.mask.pmins.b.128 + return _mm_maskz_min_epi8(__M,__A,__B); +} +__m128i test_mm_mask_min_epi8(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_min_epi8 + // CHECK: @llvm.x86.avx512.mask.pmins.b.128 + return _mm_mask_min_epi8(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_min_epi8(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_min_epi8 + // CHECK: @llvm.x86.avx512.mask.pmins.b.256 + return _mm256_maskz_min_epi8(__M,__A,__B); +} +__m256i test_mm256_mask_min_epi8(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_min_epi8 + // CHECK: @llvm.x86.avx512.mask.pmins.b.256 + return _mm256_mask_min_epi8(__W,__M,__A,__B); +} +__m128i test_mm_maskz_min_epi16(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_min_epi16 + // CHECK: @llvm.x86.avx512.mask.pmins.w.128 + return _mm_maskz_min_epi16(__M,__A,__B); +} +__m128i test_mm_mask_min_epi16(__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_min_epi16 + // CHECK: @llvm.x86.avx512.mask.pmins.w.128 + return _mm_mask_min_epi16(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_min_epi16(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_min_epi16 + // CHECK: @llvm.x86.avx512.mask.pmins.w.256 + return _mm256_maskz_min_epi16(__M,__A,__B); +} +__m256i test_mm256_mask_min_epi16(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_min_epi16 + // CHECK: @llvm.x86.avx512.mask.pmins.w.256 + return _mm256_mask_min_epi16(__W,__M,__A,__B); +} +__m128i test_mm_maskz_min_epu8(__mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_min_epu8 + // CHECK: @llvm.x86.avx512.mask.pminu.b.128 + return _mm_maskz_min_epu8(__M,__A,__B); +} +__m128i test_mm_mask_min_epu8(__m128i __W, __mmask16 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_min_epu8 + // CHECK: @llvm.x86.avx512.mask.pminu.b.128 + return _mm_mask_min_epu8(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_min_epu8(__mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_min_epu8 + // CHECK: @llvm.x86.avx512.mask.pminu.b.256 + return _mm256_maskz_min_epu8(__M,__A,__B); +} +__m256i test_mm256_mask_min_epu8(__m256i __W, __mmask32 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_min_epu8 + // CHECK: @llvm.x86.avx512.mask.pminu.b.256 + return _mm256_mask_min_epu8(__W,__M,__A,__B); +} +__m128i test_mm_maskz_min_epu16(__mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_min_epu16 + // CHECK: @llvm.x86.avx512.mask.pminu.w.128 + return _mm_maskz_min_epu16(__M,__A,__B); +} +__m128i test_mm_mask_min_epu16(__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_min_epu16 + // CHECK: @llvm.x86.avx512.mask.pminu.w.128 + return _mm_mask_min_epu16(__W,__M,__A,__B); +} +__m256i test_mm256_maskz_min_epu16(__mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_min_epu16 + // CHECK: @llvm.x86.avx512.mask.pminu.w.256 + return _mm256_maskz_min_epu16(__M,__A,__B); +} +__m256i test_mm256_mask_min_epu16(__m256i __W, __mmask16 __M, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_min_epu16 + // CHECK: @llvm.x86.avx512.mask.pminu.w.256 + return _mm256_mask_min_epu16(__W,__M,__A,__B); +} +__m128i test_mm_mask_shuffle_epi8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_shuffle_epi8 + // CHECK: @llvm.x86.avx512.mask.pshuf.b.128 + return _mm_mask_shuffle_epi8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_shuffle_epi8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_shuffle_epi8 + // CHECK: @llvm.x86.avx512.mask.pshuf.b.128 + return _mm_maskz_shuffle_epi8(__U,__A,__B); +} +__m256i test_mm256_mask_shuffle_epi8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_shuffle_epi8 + // CHECK: @llvm.x86.avx512.mask.pshuf.b.256 + return _mm256_mask_shuffle_epi8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_shuffle_epi8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_shuffle_epi8 + // CHECK: @llvm.x86.avx512.mask.pshuf.b.256 + return _mm256_maskz_shuffle_epi8(__U,__A,__B); +} +__m128i test_mm_mask_subs_epi8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_subs_epi8 + // CHECK: @llvm.x86.avx512.mask.psubs.b.128 + return _mm_mask_subs_epi8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_subs_epi8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_subs_epi8 + // CHECK: @llvm.x86.avx512.mask.psubs.b.128 + return _mm_maskz_subs_epi8(__U,__A,__B); +} +__m256i test_mm256_mask_subs_epi8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_subs_epi8 + // CHECK: @llvm.x86.avx512.mask.psubs.b.256 + return _mm256_mask_subs_epi8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_subs_epi8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_subs_epi8 + // CHECK: @llvm.x86.avx512.mask.psubs.b.256 + return _mm256_maskz_subs_epi8(__U,__A,__B); +} +__m128i test_mm_mask_subs_epi16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_subs_epi16 + // CHECK: @llvm.x86.avx512.mask.psubs.w.128 + return _mm_mask_subs_epi16(__W,__U,__A,__B); +} +__m128i test_mm_maskz_subs_epi16(__mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_subs_epi16 + // CHECK: @llvm.x86.avx512.mask.psubs.w.128 + return _mm_maskz_subs_epi16(__U,__A,__B); +} +__m256i test_mm256_mask_subs_epi16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_subs_epi16 + // CHECK: @llvm.x86.avx512.mask.psubs.w.256 + return _mm256_mask_subs_epi16(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_subs_epi16(__mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_subs_epi16 + // CHECK: @llvm.x86.avx512.mask.psubs.w.256 + return _mm256_maskz_subs_epi16(__U,__A,__B); +} +__m128i test_mm_mask_subs_epu8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_subs_epu8 + // CHECK: @llvm.x86.avx512.mask.psubus.b.128 + return _mm_mask_subs_epu8(__W,__U,__A,__B); +} +__m128i test_mm_maskz_subs_epu8(__mmask16 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_subs_epu8 + // CHECK: @llvm.x86.avx512.mask.psubus.b.128 + return _mm_maskz_subs_epu8(__U,__A,__B); +} +__m256i test_mm256_mask_subs_epu8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_subs_epu8 + // CHECK: @llvm.x86.avx512.mask.psubus.b.256 + return _mm256_mask_subs_epu8(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_subs_epu8(__mmask32 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_subs_epu8 + // CHECK: @llvm.x86.avx512.mask.psubus.b.256 + return _mm256_maskz_subs_epu8(__U,__A,__B); +} +__m128i test_mm_mask_subs_epu16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_subs_epu16 + // CHECK: @llvm.x86.avx512.mask.psubus.w.128 + return _mm_mask_subs_epu16(__W,__U,__A,__B); +} +__m128i test_mm_maskz_subs_epu16(__mmask8 __U, __m128i __A, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_subs_epu16 + // CHECK: @llvm.x86.avx512.mask.psubus.w.128 + return _mm_maskz_subs_epu16(__U,__A,__B); +} +__m256i test_mm256_mask_subs_epu16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_subs_epu16 + // CHECK: @llvm.x86.avx512.mask.psubus.w.256 + return _mm256_mask_subs_epu16(__W,__U,__A,__B); +} +__m256i test_mm256_maskz_subs_epu16(__mmask16 __U, __m256i __A, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_subs_epu16 + // CHECK: @llvm.x86.avx512.mask.psubus.w.256 + return _mm256_maskz_subs_epu16(__U,__A,__B); +} + + +__m128i test_mm_mask2_permutex2var_epi16(__m128i __A, __m128i __I, __mmask8 __U, __m128i __B) { + // CHECK-LABEL: @test_mm_mask2_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermi2var.hi.128 + return _mm_mask2_permutex2var_epi16(__A,__I,__U,__B); +} +__m256i test_mm256_mask2_permutex2var_epi16(__m256i __A, __m256i __I, __mmask16 __U, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask2_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermi2var.hi.256 + return _mm256_mask2_permutex2var_epi16(__A,__I,__U,__B); +} +__m128i test_mm_permutex2var_epi16(__m128i __A, __m128i __I, __m128i __B) { + // CHECK-LABEL: @test_mm_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermt2var.hi.128 + return _mm_permutex2var_epi16(__A,__I,__B); +} +__m128i test_mm_mask_permutex2var_epi16(__m128i __A, __mmask8 __U, __m128i __I, __m128i __B) { + // CHECK-LABEL: @test_mm_mask_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermt2var.hi.128 + return _mm_mask_permutex2var_epi16(__A,__U,__I,__B); +} +__m128i test_mm_maskz_permutex2var_epi16(__mmask8 __U, __m128i __A, __m128i __I, __m128i __B) { + // CHECK-LABEL: @test_mm_maskz_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.maskz.vpermt2var.hi.128 + return _mm_maskz_permutex2var_epi16(__U,__A,__I,__B); +} + +__m256i test_mm256_permutex2var_epi16(__m256i __A, __m256i __I, __m256i __B) { + // CHECK-LABEL: @test_mm256_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermt2var.hi.256 + return _mm256_permutex2var_epi16(__A,__I,__B); +} +__m256i test_mm256_mask_permutex2var_epi16(__m256i __A, __mmask16 __U, __m256i __I, __m256i __B) { + // CHECK-LABEL: @test_mm256_mask_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.mask.vpermt2var.hi.256 + return _mm256_mask_permutex2var_epi16(__A,__U,__I,__B); +} +__m256i test_mm256_maskz_permutex2var_epi16(__mmask16 __U, __m256i __A, __m256i __I, __m256i __B) { + // CHECK-LABEL: @test_mm256_maskz_permutex2var_epi16 + // CHECK: @llvm.x86.avx512.maskz.vpermt2var.hi.256 + return _mm256_maskz_permutex2var_epi16(__U,__A,__I,__B); +} diff --git a/test/CodeGen/big-atomic-ops.c b/test/CodeGen/big-atomic-ops.c index 28b7b5d70822..6a7a7001f96d 100644 --- a/test/CodeGen/big-atomic-ops.c +++ b/test/CodeGen/big-atomic-ops.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-macosx10.9.0 | FileCheck %s - +// REQUIRES: x86-registered-target // Also test serialization of atomic operations here, to avoid duplicating the // test. // RUN: %clang_cc1 %s -emit-pch -o %t -triple=x86_64-apple-macosx10.9.0 diff --git a/test/CodeGen/bitfield-2.c b/test/CodeGen/bitfield-2.c index c5154fcb19e2..e4b1b0d9fd5c 100644 --- a/test/CodeGen/bitfield-2.c +++ b/test/CodeGen/bitfield-2.c @@ -14,7 +14,7 @@ // CHECK-RECORD: LLVMType:%struct.s0 = type { [3 x i8] } // CHECK-RECORD: IsZeroInitializable:1 // CHECK-RECORD: BitFields:[ -// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageAlignment:1> +// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageOffset:0> struct __attribute((packed)) s0 { int f0 : 24; }; @@ -54,8 +54,8 @@ unsigned long long test_0() { // CHECK-RECORD: LLVMType:%struct.s1 = type { [3 x i8] } // CHECK-RECORD: IsZeroInitializable:1 // CHECK-RECORD: BitFields:[ -// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1> -// CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1> +// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0> +// CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0> #pragma pack(push) #pragma pack(1) @@ -102,7 +102,7 @@ unsigned long long test_1() { // CHECK-RECORD: LLVMType:%union.u2 = type { i8 } // CHECK-RECORD: IsZeroInitializable:1 // CHECK-RECORD: BitFields:[ -// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageAlignment:1> +// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageOffset:0> union __attribute__((packed)) u2 { unsigned long long f0 : 3; @@ -274,8 +274,8 @@ _Bool test_6() { // CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, i32, [12 x i8] } // CHECK-RECORD: IsZeroInitializable:1 // CHECK-RECORD: BitFields:[ -// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageAlignment:4> -// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageAlignment:16> +// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageOffset:12> +// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageOffset:16> struct __attribute__((aligned(16))) s7 { int a, b, c; diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c index c6aa3c2faac2..8e8216b10111 100644 --- a/test/CodeGen/builtins-ppc-altivec.c +++ b/test/CodeGen/builtins-ppc-altivec.c @@ -1081,6 +1081,31 @@ void test6() { // CHECK: @llvm.ppc.altivec.vctuxs // CHECK-LE: @llvm.ppc.altivec.vctuxs + /* vec_div */ + res_vsc = vec_div(vsc, vsc); +// CHECK: sdiv <16 x i8> +// CHECK-LE: sdiv <16 x i8> + + res_vuc = vec_div(vuc, vuc); +// CHECK: udiv <16 x i8> +// CHECK-LE: udiv <16 x i8> + + res_vs = vec_div(vs, vs); +// CHECK: sdiv <8 x i16> +// CHECK-LE: sdiv <8 x i16> + + res_vus = vec_div(vus, vus); +// CHECK: udiv <8 x i16> +// CHECK-LE: udiv <8 x i16> + + res_vi = vec_div(vi, vi); +// CHECK: sdiv <4 x i32> +// CHECK-LE: sdiv <4 x i32> + + res_vui = vec_div(vui, vui); +// CHECK: udiv <4 x i32> +// CHECK-LE: udiv <4 x i32> + /* vec_dss */ vec_dss(0); // CHECK: @llvm.ppc.altivec.dss @@ -2127,6 +2152,31 @@ void test6() { // CHECK: @llvm.ppc.altivec.mtvscr // CHECK-LE: @llvm.ppc.altivec.mtvscr + /* vec_mul */ + res_vsc = vec_mul(vsc, vsc); +// CHECK: mul <16 x i8> +// CHECK-LE: mul <16 x i8> + + res_vuc = vec_mul(vuc, vuc); +// CHECK: mul <16 x i8> +// CHECK-LE: mul <16 x i8> + + res_vs = vec_mul(vs, vs); +// CHECK: mul <8 x i16> +// CHECK-LE: mul <8 x i16> + + res_vus = vec_mul(vus, vus); +// CHECK: mul <8 x i16> +// CHECK-LE: mul <8 x i16> + + res_vi = vec_mul(vi, vi); +// CHECK: mul <4 x i32> +// CHECK-LE: mul <4 x i32> + + res_vui = vec_mul(vui, vui); +// CHECK: mul <4 x i32> +// CHECK-LE: mul <4 x i32> + /* vec_mule */ res_vs = vec_mule(vsc, vsc); // CHECK: @llvm.ppc.altivec.vmulesb @@ -3272,6 +3322,15 @@ void test6() { // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm + res_vbs = vec_sld(vbs, vbs, 0); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + res_vp = vec_sld(vp, vp, 0); // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm @@ -3284,6 +3343,11 @@ void test6() { // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm + res_vbi = vec_sld(vbi, vbi, 0); +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> {{.+}}, <4 x i32> {{.+}}, <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> {{.+}}, <4 x i32> {{.+}}, <16 x i8> + res_vf = vec_sld(vf, vf, 0); // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm @@ -3802,28 +3866,28 @@ void test6() { /* vec_sr */ res_vsc = vec_sr(vsc, vuc); -// CHECK: shr <16 x i8> -// CHECK-LE: shr <16 x i8> +// CHECK: lshr <16 x i8> +// CHECK-LE: lshr <16 x i8> res_vuc = vec_sr(vuc, vuc); -// CHECK: shr <16 x i8> -// CHECK-LE: shr <16 x i8> +// CHECK: lshr <16 x i8> +// CHECK-LE: lshr <16 x i8> res_vs = vec_sr(vs, vus); -// CHECK: shr <8 x i16> -// CHECK-LE: shr <8 x i16> +// CHECK: lshr <8 x i16> +// CHECK-LE: lshr <8 x i16> res_vus = vec_sr(vus, vus); -// CHECK: shr <8 x i16> -// CHECK-LE: shr <8 x i16> +// CHECK: lshr <8 x i16> +// CHECK-LE: lshr <8 x i16> res_vi = vec_sr(vi, vui); -// CHECK: shr <4 x i32> -// CHECK-LE: shr <4 x i32> +// CHECK: lshr <4 x i32> +// CHECK-LE: lshr <4 x i32> res_vui = vec_sr(vui, vui); -// CHECK: shr <4 x i32> -// CHECK-LE: shr <4 x i32> +// CHECK: lshr <4 x i32> +// CHECK-LE: lshr <4 x i32> res_vsc = vec_vsrb(vsc, vuc); // CHECK: shr <16 x i8> diff --git a/test/CodeGen/builtins-ppc-p8vector.c b/test/CodeGen/builtins-ppc-p8vector.c index 61e14ba283d2..208dd4347f65 100644 --- a/test/CodeGen/builtins-ppc-p8vector.c +++ b/test/CodeGen/builtins-ppc-p8vector.c @@ -9,23 +9,41 @@ vector signed char vsc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; vector unsigned char vuc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; -vector int vi = { -1, 2, -3, 4 }; +vector bool char vbc = { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1 }; + +vector signed short vss = { 0, 1, 2, 3, 4, 5, 6, 7 }; +vector unsigned short vus = { 0, 1, 2, 3, 4, 5, 6, 7 }; +vector bool short vbs = { 1, 1, 0, 0, 0, 0, 1, 1 }; + +vector signed int vsi = { -1, 2, -3, 4 }; vector unsigned int vui = { 1, 2, 3, 4 }; vector bool int vbi = {0, -1, -1, 0}; -vector bool long long vbll = { 1, 0 }; + vector signed long long vsll = { 1, 2 }; vector unsigned long long vull = { 1, 2 }; +vector bool long long vbll = { 1, 0 }; + +vector float vfa = { 1.e-4f, -132.23f, -22.1, 32.00f }; vector double vda = { 1.e-11, -132.23e10 }; int res_i; vector signed char res_vsc; vector unsigned char res_vuc; -vector int res_vi; +vector bool char res_vbc; + +vector signed short res_vss; +vector unsigned short res_vus; +vector bool short res_vbs; + +vector signed int res_vsi; vector unsigned int res_vui; vector bool int res_vbi; -vector bool long long res_vbll; + vector signed long long res_vsll; vector unsigned long long res_vull; +vector bool long long res_vbll; + +vector double res_vf; vector double res_vd; // CHECK-LABEL: define void @test1 @@ -60,7 +78,7 @@ void test1() { // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm - res_vi = vec_mergee(vi, vi); + res_vsi = vec_mergee(vsi, vsi); // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm @@ -74,7 +92,7 @@ void test1() { // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm - res_vi = vec_mergeo(vi, vi); + res_vsi = vec_mergeo(vsi, vsi); // CHECK: @llvm.ppc.altivec.vperm // CHECK-LE: @llvm.ppc.altivec.vperm @@ -138,6 +156,325 @@ void test1() { // CHECK-LE: call <2 x i64> @llvm.ppc.altivec.vcmpgtud(<2 x i64> %{{[0-9]*}}, <2 x i64> %{{[0-9]*}}) // CHECK-PPC: error: call to 'vec_cmplt' is ambiguous + /* vec_eqv */ + res_vsc = vec_eqv(vsc, vsc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vsc = vec_eqv(vbc, vsc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vsc = vec_eqv(vsc, vbc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vuc = vec_eqv(vuc, vuc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vuc = vec_eqv(vbc, vuc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vuc = vec_eqv(vuc, vbc); +// CHECK: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <16 x i8> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <16 x i8> +// CHECK-PPC: error: assigning to + + res_vss = vec_eqv(vss, vss); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vss = vec_eqv(vbs, vss); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vss = vec_eqv(vss, vbs); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vus = vec_eqv(vus, vus); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vus = vec_eqv(vbs, vus); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vus = vec_eqv(vus, vbs); +// CHECK: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-LE: [[T1:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <8 x i16> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <8 x i16> +// CHECK-PPC: error: assigning to + + res_vsi = vec_eqv(vsi, vsi); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vsi = vec_eqv(vbi, vsi); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vsi = vec_eqv(vsi, vbi); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vui = vec_eqv(vui, vui); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vui = vec_eqv(vbi, vui); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vui = vec_eqv(vui, vbi); +// CHECK: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.*}}, <4 x i32> {{.+}}) +// CHECK-PPC: error: assigning to + + res_vsll = vec_eqv(vsll, vsll); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vsll = vec_eqv(vbll, vsll); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vsll = vec_eqv(vsll, vbll); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vull = vec_eqv(vull, vull); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vull = vec_eqv(vbll, vull); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vull = vec_eqv(vull, vbll); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x i64> +// CHECK-PPC: error: assigning to + + res_vf = vec_eqv(vfa, vfa); +// CHECK: [[T1:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <4 x float> +// CHECK-LE: [[T1:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <4 x float> +// CHECK-PPC: error: assigning to + + res_vf = vec_eqv(vbi, vfa); +// CHECK: [[T2:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.+}}, <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <4 x float> +// CHECK-LE: [[T2:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.+}}, <4 x i32> [[T2]]) +// CHECK-PPC: error: assigning to + + res_vf = vec_eqv(vfa, vbi); +// CHECK: [[T1:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> +// CHECK: bitcast <4 x i32> [[T3]] to <4 x float> +// CHECK-LE: [[T1:%.+]] = bitcast <4 x float> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> +// CHECK-LE: bitcast <4 x i32> [[T3]] to <4 x float> +// CHECK-PPC: error: assigning to + + res_vd = vec_eqv(vda, vda); +// CHECK: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-PPC: error: assigning to + + res_vd = vec_eqv(vbll, vda); +// CHECK: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.+}}, <4 x i32> [[T2]]) +// CHECK: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> {{.+}}, <4 x i32> [[T2]]) +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-PPC: error: assigning to + + res_vd = vec_eqv(vda, vbll); +// CHECK: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> +// CHECK: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: [[T3:%.+]] = call <4 x i32> @llvm.ppc.vsx.xxleqv(<4 x i32> [[T1]], <4 x i32> +// CHECK-LE: bitcast <4 x i32> [[T3]] to <2 x double> +// CHECK-PPC: error: assigning to + + res_vsc = vec_cntlz(vsc); +// CHECK: call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %{{.+}}, i1 false) +// CHECK-LE: call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %{{.+}}, i1 false) +// CHECK-PPC: warning: implicit declaration of function 'vec_cntlz' is invalid in C99 + + res_vuc = vec_cntlz(vuc); +// CHECK: call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %{{.+}}, i1 false) +// CHECK-LE: call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %{{.+}}, i1 false) + + res_vss = vec_cntlz(vss); +// CHECK: call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %{{.+}}, i1 false) +// CHECK-LE: call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %{{.+}}, i1 false) + + res_vus = vec_cntlz(vus); +// CHECK: call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %{{.+}}, i1 false) +// CHECK-LE: call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %{{.+}}, i1 false) + + res_vsi = vec_cntlz(vsi); +// CHECK: call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %{{.+}}, i1 false) +// CHECK-LE: call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %{{.+}}, i1 false) + + res_vui = vec_cntlz(vui); +// CHECK: call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %{{.+}}, i1 false) +// CHECK-LE: call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %{{.+}}, i1 false) + + res_vsll = vec_cntlz(vsll); +// CHECK: call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %{{.+}}, i1 false) +// CHECK-LE: call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %{{.+}}, i1 false) + + res_vull = vec_cntlz(vull); +// CHECK: call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %{{.+}}, i1 false) +// CHECK-LE: call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %{{.+}}, i1 false) + /* ----------------------- predicates --------------------------- */ /* vec_all_eq */ res_i = vec_all_eq(vsll, vsll); @@ -634,7 +971,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_min' is ambiguous /* vec_mule */ - res_vsll = vec_mule(vi, vi); + res_vsll = vec_mule(vsi, vsi); // CHECK: @llvm.ppc.altivec.vmulesw // CHECK-LE: @llvm.ppc.altivec.vmulosw // CHECK-PPC: error: call to 'vec_mule' is ambiguous @@ -645,7 +982,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_mule' is ambiguous /* vec_mulo */ - res_vsll = vec_mulo(vi, vi); + res_vsll = vec_mulo(vsi, vsi); // CHECK: @llvm.ppc.altivec.vmulosw // CHECK-LE: @llvm.ppc.altivec.vmulesw // CHECK-PPC: error: call to 'vec_mulo' is ambiguous @@ -656,7 +993,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_mulo' is ambiguous /* vec_packs */ - res_vi = vec_packs(vsll, vsll); + res_vsi = vec_packs(vsll, vsll); // CHECK: @llvm.ppc.altivec.vpksdss // CHECK-LE: @llvm.ppc.altivec.vpksdss // CHECK-PPC: error: call to 'vec_packs' is ambiguous @@ -701,8 +1038,8 @@ void test1() { /* vec_sr */ res_vsll = vec_sr(vsll, vull); -// CHECK: ashr <2 x i64> -// CHECK-LE: ashr <2 x i64> +// CHECK: lshr <2 x i64> +// CHECK-LE: lshr <2 x i64> // CHECK-PPC: error: call to 'vec_sr' is ambiguous res_vull = vec_sr(vull, vull); @@ -722,7 +1059,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_sra' is ambiguous /* vec_unpackh */ - res_vsll = vec_unpackh(vi); + res_vsll = vec_unpackh(vsi); // CHECK: llvm.ppc.altivec.vupkhsw // CHECK-LE: llvm.ppc.altivec.vupklsw // CHECK-PPC: error: call to 'vec_unpackh' is ambiguous @@ -733,7 +1070,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_unpackh' is ambiguous /* vec_unpackl */ - res_vsll = vec_unpackl(vi); + res_vsll = vec_unpackl(vsi); // CHECK: llvm.ppc.altivec.vupklsw // CHECK-LE: llvm.ppc.altivec.vupkhsw // CHECK-PPC: error: call to 'vec_unpackl' is ambiguous @@ -744,7 +1081,7 @@ void test1() { // CHECK-PPC: error: call to 'vec_unpackl' is ambiguous /* vec_vpksdss */ - res_vi = vec_vpksdss(vsll, vsll); + res_vsi = vec_vpksdss(vsll, vsll); // CHECK: llvm.ppc.altivec.vpksdss // CHECK-LE: llvm.ppc.altivec.vpksdss // CHECK-PPC: warning: implicit declaration of function 'vec_vpksdss' @@ -756,7 +1093,7 @@ void test1() { // CHECK-PPC: warning: implicit declaration of function 'vec_vpksdus' /* vec_vpkudum */ - res_vi = vec_vpkudum(vsll, vsll); + res_vsi = vec_vpkudum(vsll, vsll); // CHECK: vperm // CHECK-LE: vperm // CHECK-PPC: warning: implicit declaration of function 'vec_vpkudum' @@ -771,7 +1108,7 @@ void test1() { // CHECK-PPC: warning: implicit declaration of function 'vec_vpkudus' /* vec_vupkhsw */ - res_vsll = vec_vupkhsw(vi); + res_vsll = vec_vupkhsw(vsi); // CHECK: llvm.ppc.altivec.vupkhsw // CHECK-LE: llvm.ppc.altivec.vupklsw // CHECK-PPC: warning: implicit declaration of function 'vec_vupkhsw' @@ -781,7 +1118,7 @@ void test1() { // CHECK-LE: llvm.ppc.altivec.vupklsw /* vec_vupklsw */ - res_vsll = vec_vupklsw(vi); + res_vsll = vec_vupklsw(vsi); // CHECK: llvm.ppc.altivec.vupklsw // CHECK-LE: llvm.ppc.altivec.vupkhsw // CHECK-PPC: warning: implicit declaration of function 'vec_vupklsw' @@ -832,6 +1169,298 @@ void test1() { // CHECK: @llvm.ppc.altivec.vminud // CHECK-LE: @llvm.ppc.altivec.vminud + /* vec_nand */ + res_vsc = vec_nand(vsc, vsc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-PPC: warning: implicit declaration of function 'vec_nand' is invalid in C99 + + res_vsc = vec_nand(vsc, vbc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> + + res_vsc = vec_nand(vbc, vsc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> + + res_vuc = vec_nand(vuc, vuc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> + + res_vuc = vec_nand(vuc, vbc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> + + res_vuc = vec_nand(vbc, vuc); +// CHECK: [[T1:%.+]] = and <16 x i8> +// CHECK: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: [[T1:%.+]] = and <16 x i8> +// CHECK-LE: xor <16 x i8> [[T1]], <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> + + res_vss = vec_nand(vss, vss); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vss = vec_nand(vss, vbs); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vss = vec_nand(vbs, vss); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vus = vec_nand(vus, vus); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vus = vec_nand(vus, vbs); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vus = vec_nand(vbs, vus); +// CHECK: [[T1:%.+]] = and <8 x i16> +// CHECK: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: [[T1:%.+]] = and <8 x i16> +// CHECK-LE: xor <8 x i16> [[T1]], <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> + + res_vsi = vec_nand(vsi, vsi); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vsi = vec_nand(vsi, vbi); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vsi = vec_nand(vbi, vsi); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vui = vec_nand(vui, vui); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vui = vec_nand(vui, vbi); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vui = vec_nand(vbi, vui); +// CHECK: [[T1:%.+]] = and <4 x i32> +// CHECK: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: [[T1:%.+]] = and <4 x i32> +// CHECK-LE: xor <4 x i32> [[T1]], <i32 -1, i32 -1, i32 -1, i32 -1> + + res_vsll = vec_nand(vsll, vsll); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + res_vsll = vec_nand(vsll, vbll); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + res_vsll = vec_nand(vbll, vsll); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + res_vull = vec_nand(vull, vull); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + res_vull = vec_nand(vull, vbll); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + res_vull = vec_nand(vbll, vull); +// CHECK: [[T1:%.+]] = and <2 x i64> +// CHECK: xor <2 x i64> [[T1]], <i64 -1, i64 -1> +// CHECK-LE: [[T1:%.+]] = and <2 x i64> +// CHECK-LE: xor <2 x i64> [[T1]], <i64 -1, i64 -1> + + /* vec_orc */ + res_vsc = vec_orc(vsc, vsc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-PPC: warning: implicit declaration of function 'vec_orc' is invalid in C99 + + res_vsc = vec_orc(vsc, vbc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] + + res_vsc = vec_orc(vbc, vsc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] + + res_vuc = vec_orc(vuc, vuc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] + + res_vuc = vec_orc(vuc, vbc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] + + res_vuc = vec_orc(vbc, vuc); +// CHECK: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK: or <16 x i8> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <16 x i8> {{%.+}}, <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1> +// CHECK-LE: or <16 x i8> {{%.+}}, [[T1]] + + res_vss = vec_orc(vss, vss); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vss = vec_orc(vss, vbs); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vss = vec_orc(vbs, vss); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vus = vec_orc(vus, vus); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vus = vec_orc(vus, vbs); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vus = vec_orc(vbs, vus); +// CHECK: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK: or <8 x i16> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <8 x i16> {{%.+}}, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> +// CHECK-LE: or <8 x i16> {{%.+}}, [[T1]] + + res_vsi = vec_orc(vsi, vsi); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vsi = vec_orc(vsi, vbi); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vsi = vec_orc(vbi, vsi); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vui = vec_orc(vui, vui); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vui = vec_orc(vui, vbi); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vui = vec_orc(vbi, vui); +// CHECK: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK: or <4 x i32> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <4 x i32> {{%.+}}, <i32 -1, i32 -1, i32 -1, i32 -1> +// CHECK-LE: or <4 x i32> {{%.+}}, [[T1]] + + res_vsll = vec_orc(vsll, vsll); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + + res_vsll = vec_orc(vsll, vbll); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + + res_vsll = vec_orc(vbll, vsll); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + + res_vull = vec_orc(vull, vull); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + + res_vull = vec_orc(vull, vbll); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + + res_vull = vec_orc(vbll, vull); +// CHECK: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK: or <2 x i64> {{%.+}}, [[T1]] +// CHECK-LE: [[T1:%.+]] = xor <2 x i64> {{%.+}}, <i64 -1, i64 -1> +// CHECK-LE: or <2 x i64> {{%.+}}, [[T1]] + /* vec_vbpermq */ res_vsll = vec_vbpermq(vsc, vsc); // CHECK: llvm.ppc.altivec.vbpermq diff --git a/test/CodeGen/builtins-ppc-vsx.c b/test/CodeGen/builtins-ppc-vsx.c index 99362133dd9a..9a40d3041db1 100644 --- a/test/CodeGen/builtins-ppc-vsx.c +++ b/test/CodeGen/builtins-ppc-vsx.c @@ -1,6 +1,6 @@ // REQUIRES: powerpc-registered-target // RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -faltivec -target-feature +vsx -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LE vector unsigned char vuc = { 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7}; @@ -27,39 +27,57 @@ void dummy() { } void test1() { // CHECK-LABEL: define void @test1 +// CHECK-LE-LABEL: define void @test1 res_vd = vec_add(vd, vd); // CHECK: fadd <2 x double> +// CHECK-LE: fadd <2 x double> res_vd = vec_and(vbll, vd); // CHECK: and <2 x i64> // CHECK: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> +// CHECK-LE: and <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> res_vd = vec_and(vd, vbll); // CHECK: and <2 x i64> // CHECK: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> +// CHECK-LE: and <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> res_vd = vec_and(vd, vd); // CHECK: and <2 x i64> // CHECK: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> +// CHECK-LE: and <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> dummy(); // CHECK: call void @dummy() +// CHECK-LE: call void @dummy() res_vd = vec_andc(vbll, vd); // CHECK: bitcast <2 x double> %{{[0-9]*}} to <2 x i64> // CHECK: xor <2 x i64> %{{[0-9]*}}, <i64 -1, i64 -1> // CHECK: and <2 x i64> // CHECK: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> +// CHECK-LE: bitcast <2 x double> %{{[0-9]*}} to <2 x i64> +// CHECK-LE: xor <2 x i64> %{{[0-9]*}}, <i64 -1, i64 -1> +// CHECK-LE: and <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> dummy(); // CHECK: call void @dummy() +// CHECK-LE: call void @dummy() res_vd = vec_andc(vd, vbll); // CHECK: bitcast <2 x double> %{{[0-9]*}} to <2 x i64> // CHECK: xor <2 x i64> %{{[0-9]*}}, <i64 -1, i64 -1> // CHECK: and <2 x i64> // CHECK: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> +// CHECK-LE: bitcast <2 x double> %{{[0-9]*}} to <2 x i64> +// CHECK-LE: xor <2 x i64> %{{[0-9]*}}, <i64 -1, i64 -1> +// CHECK-LE: and <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]*}} to <2 x double> dummy(); // CHECK: call void @dummy() @@ -72,307 +90,759 @@ void test1() { dummy(); // CHECK: call void @dummy() +// CHECK-LE: call void @dummy() res_vd = vec_ceil(vd); // CHECK: call <2 x double> @llvm.ceil.v2f64(<2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x double> @llvm.ceil.v2f64(<2 x double> %{{[0-9]*}}) res_vf = vec_ceil(vf); // CHECK: call <4 x float> @llvm.ceil.v4f32(<4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x float> @llvm.ceil.v4f32(<4 x float> %{{[0-9]*}}) res_vbll = vec_cmpeq(vd, vd); // CHECK: call <2 x i64> @llvm.ppc.vsx.xvcmpeqdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x i64> @llvm.ppc.vsx.xvcmpeqdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) res_vbi = vec_cmpeq(vf, vf); // CHECK: call <4 x i32> @llvm.ppc.vsx.xvcmpeqsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xvcmpeqsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) res_vbll = vec_cmpge(vd, vd); // CHECK: call <2 x i64> @llvm.ppc.vsx.xvcmpgedp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x i64> @llvm.ppc.vsx.xvcmpgedp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) res_vbi = vec_cmpge(vf, vf); // CHECK: call <4 x i32> @llvm.ppc.vsx.xvcmpgesp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xvcmpgesp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) res_vbll = vec_cmpgt(vd, vd); // CHECK: call <2 x i64> @llvm.ppc.vsx.xvcmpgtdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x i64> @llvm.ppc.vsx.xvcmpgtdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) res_vbi = vec_cmpgt(vf, vf); // CHECK: call <4 x i32> @llvm.ppc.vsx.xvcmpgtsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xvcmpgtsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) res_vbll = vec_cmple(vd, vd); // CHECK: call <2 x i64> @llvm.ppc.vsx.xvcmpgedp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x i64> @llvm.ppc.vsx.xvcmpgedp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) res_vbi = vec_cmple(vf, vf); // CHECK: call <4 x i32> @llvm.ppc.vsx.xvcmpgesp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xvcmpgesp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) res_vbll = vec_cmplt(vd, vd); // CHECK: call <2 x i64> @llvm.ppc.vsx.xvcmpgtdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) +// CHECK-LE: call <2 x i64> @llvm.ppc.vsx.xvcmpgtdp(<2 x double> %{{[0-9]*}}, <2 x double> %{{[0-9]*}}) res_vbi = vec_cmplt(vf, vf); // CHECK: call <4 x i32> @llvm.ppc.vsx.xvcmpgtsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) +// CHECK-LE: call <4 x i32> @llvm.ppc.vsx.xvcmpgtsp(<4 x float> %{{[0-9]*}}, <4 x float> %{{[0-9]*}}) + + /* vec_cpsgn */ + res_vf = vec_cpsgn(vf, vf); +// CHECK: call <4 x float> @llvm.copysign.v4f32(<4 x float> %{{.+}}, <4 x float> %{{.+}}) +// CHECK-LE: call <4 x float> @llvm.copysign.v4f32(<4 x float> %{{.+}}, <4 x float> %{{.+}}) + + res_vd = vec_cpsgn(vd, vd); +// CHECK: call <2 x double> @llvm.copysign.v2f64(<2 x double> %{{.+}}, <2 x double> %{{.+}}) +// CHECK-LE: call <2 x double> @llvm.copysign.v2f64(<2 x double> %{{.+}}, <2 x double> %{{.+}}) /* vec_div */ + res_vsll = vec_div(vsll, vsll); +// CHECK: sdiv <2 x i64> +// CHECK-LE: sdiv <2 x i64> + + res_vull = vec_div(vull, vull); +// CHECK: udiv <2 x i64> +// CHECK-LE: udiv <2 x i64> + res_vf = vec_div(vf, vf); -// CHECK: @llvm.ppc.vsx.xvdivsp +// CHECK: fdiv <4 x float> +// CHECK-LE: fdiv <4 x float> res_vd = vec_div(vd, vd); -// CHECK: @llvm.ppc.vsx.xvdivdp +// CHECK: fdiv <2 x double> +// CHECK-LE: fdiv <2 x double> /* vec_max */ res_vf = vec_max(vf, vf); // CHECK: @llvm.ppc.vsx.xvmaxsp +// CHECK-LE: @llvm.ppc.vsx.xvmaxsp res_vd = vec_max(vd, vd); // CHECK: @llvm.ppc.vsx.xvmaxdp +// CHECK-LE: @llvm.ppc.vsx.xvmaxdp res_vf = vec_vmaxfp(vf, vf); // CHECK: @llvm.ppc.vsx.xvmaxsp +// CHECK-LE: @llvm.ppc.vsx.xvmaxsp /* vec_min */ res_vf = vec_min(vf, vf); // CHECK: @llvm.ppc.vsx.xvminsp +// CHECK-LE: @llvm.ppc.vsx.xvminsp res_vd = vec_min(vd, vd); // CHECK: @llvm.ppc.vsx.xvmindp +// CHECK-LE: @llvm.ppc.vsx.xvmindp res_vf = vec_vminfp(vf, vf); // CHECK: @llvm.ppc.vsx.xvminsp +// CHECK-LE: @llvm.ppc.vsx.xvminsp res_d = __builtin_vsx_xsmaxdp(d, d); // CHECK: @llvm.ppc.vsx.xsmaxdp +// CHECK-LE: @llvm.ppc.vsx.xsmaxdp res_d = __builtin_vsx_xsmindp(d, d); // CHECK: @llvm.ppc.vsx.xsmindp +// CHECK-LE: @llvm.ppc.vsx.xsmindp /* vec_perm */ res_vsll = vec_perm(vsll, vsll, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm res_vull = vec_perm(vull, vull, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vbll = vec_perm(vbll, vbll, vuc); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + + res_vf = vec_round(vf); +// CHECK: call <4 x float> @llvm.round.v4f32(<4 x float> +// CHECK-LE: call <4 x float> @llvm.round.v4f32(<4 x float> + + res_vd = vec_round(vd); +// CHECK: call <2 x double> @llvm.round.v2f64(<2 x double> +// CHECK-LE: call <2 x double> @llvm.round.v2f64(<2 x double> res_vd = vec_perm(vd, vd, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vd = vec_splat(vd, 1); +// CHECK: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x double> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + + res_vbll = vec_splat(vbll, 1); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + + res_vsll = vec_splat(vsll, 1); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + + res_vull = vec_splat(vull, 1); +// CHECK: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> +// CHECK-LE: xor <16 x i8> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: [[T2:%.+]] = bitcast <2 x i64> {{.+}} to <4 x i32> +// CHECK-LE: call <4 x i32> @llvm.ppc.altivec.vperm(<4 x i32> [[T1]], <4 x i32> [[T2]], <16 x i8> + + res_vsi = vec_pack(vsll, vsll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vui = vec_pack(vull, vull); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vbi = vec_pack(vbll, vbll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm res_vsll = vec_vperm(vsll, vsll, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm res_vull = vec_vperm(vull, vull, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm res_vd = vec_vperm(vd, vd, vuc); // CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm /* vec_vsx_ld */ res_vsi = vec_vsx_ld(0, &vsi); // CHECK: @llvm.ppc.vsx.lxvw4x +// CHECK-LE: @llvm.ppc.vsx.lxvw4x res_vui = vec_vsx_ld(0, &vui); // CHECK: @llvm.ppc.vsx.lxvw4x +// CHECK-LE: @llvm.ppc.vsx.lxvw4x res_vf = vec_vsx_ld (0, &vf); // CHECK: @llvm.ppc.vsx.lxvw4x +// CHECK-LE: @llvm.ppc.vsx.lxvw4x res_vsll = vec_vsx_ld(0, &vsll); // CHECK: @llvm.ppc.vsx.lxvd2x +// CHECK-LE: @llvm.ppc.vsx.lxvd2x res_vull = vec_vsx_ld(0, &vull); // CHECK: @llvm.ppc.vsx.lxvd2x +// CHECK-LE: @llvm.ppc.vsx.lxvd2x res_vd = vec_vsx_ld(0, &vd); // CHECK: @llvm.ppc.vsx.lxvd2x +// CHECK-LE: @llvm.ppc.vsx.lxvd2x /* vec_vsx_st */ vec_vsx_st(vsi, 0, &res_vsi); // CHECK: @llvm.ppc.vsx.stxvw4x +// CHECK-LE: @llvm.ppc.vsx.stxvw4x vec_vsx_st(vui, 0, &res_vui); // CHECK: @llvm.ppc.vsx.stxvw4x +// CHECK-LE: @llvm.ppc.vsx.stxvw4x vec_vsx_st(vf, 0, &res_vf); // CHECK: @llvm.ppc.vsx.stxvw4x +// CHECK-LE: @llvm.ppc.vsx.stxvw4x vec_vsx_st(vsll, 0, &res_vsll); // CHECK: @llvm.ppc.vsx.stxvd2x +// CHECK-LE: @llvm.ppc.vsx.stxvd2x vec_vsx_st(vull, 0, &res_vull); // CHECK: @llvm.ppc.vsx.stxvd2x +// CHECK-LE: @llvm.ppc.vsx.stxvd2x vec_vsx_st(vd, 0, &res_vd); // CHECK: @llvm.ppc.vsx.stxvd2x +// CHECK-LE: @llvm.ppc.vsx.stxvd2x /* vec_and */ res_vsll = vec_and(vsll, vsll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_and(vbll, vsll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_and(vsll, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_and(vull, vull); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_and(vbll, vull); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_and(vull, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vbll = vec_and(vbll, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> /* vec_vand */ res_vsll = vec_vand(vsll, vsll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_vand(vbll, vsll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_vand(vsll, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_vand(vull, vull); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_vand(vbll, vull); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_vand(vull, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> res_vbll = vec_vand(vbll, vbll); // CHECK: and <2 x i64> +// CHECK-LE: and <2 x i64> /* vec_andc */ res_vsll = vec_andc(vsll, vsll); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_andc(vbll, vsll); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vsll = vec_andc(vsll, vbll); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_andc(vull, vull); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_andc(vbll, vull); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vull = vec_andc(vull, vbll); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> res_vbll = vec_andc(vbll, vbll); // CHECK: xor <2 x i64> // CHECK: and <2 x i64> +// CHECK-LE: xor <2 x i64> +// CHECK-LE: and <2 x i64> + + res_vf = vec_floor(vf); +// CHECK: call <4 x float> @llvm.floor.v4f32(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.floor.v4f32(<4 x float> %{{[0-9]+}}) + + res_vd = vec_floor(vd); +// CHECK: call <2 x double> @llvm.floor.v2f64(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.floor.v2f64(<2 x double> %{{[0-9]+}}) + + res_vf = vec_madd(vf, vf, vf); +// CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}) + + res_vd = vec_madd(vd, vd, vd); +// CHECK: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}) + + /* vec_mergeh */ + res_vsll = vec_mergeh(vsll, vsll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vsll = vec_mergeh(vsll, vbll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vsll = vec_mergeh(vbll, vsll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergeh(vull, vull); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergeh(vull, vbll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergeh(vbll, vull); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + /* vec_mergel */ + res_vsll = vec_mergel(vsll, vsll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vsll = vec_mergel(vsll, vbll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vsll = vec_mergel(vbll, vsll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergel(vull, vull); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergel(vull, vbll); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + res_vull = vec_mergel(vbll, vull); +// CHECK: @llvm.ppc.altivec.vperm +// CHECK-LE: @llvm.ppc.altivec.vperm + + /* vec_msub */ + res_vf = vec_msub(vf, vf, vf); +// CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} +// CHECK-NEXT: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> +// CHECK-LE: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} +// CHECK-LE-NEXT: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> + + res_vd = vec_msub(vd, vd, vd); +// CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{[0-9]+}} +// CHECK-NEXT: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> +// CHECK-LE: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{[0-9]+}} +// CHECK-LE-NEXT: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> + + res_vsll = vec_mul(vsll, vsll); +// CHECK: mul <2 x i64> +// CHECK-LE: mul <2 x i64> + + res_vull = vec_mul(vull, vull); +// CHECK: mul <2 x i64> +// CHECK-LE: mul <2 x i64> + + res_vf = vec_mul(vf, vf); +// CHECK: fmul <4 x float> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: fmul <4 x float> %{{[0-9]+}}, %{{[0-9]+}} + + res_vd = vec_mul(vd, vd); +// CHECK: fmul <2 x double> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: fmul <2 x double> %{{[0-9]+}}, %{{[0-9]+}} + + res_vf = vec_nearbyint(vf); +// CHECK: call <4 x float> @llvm.round.v4f32(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.round.v4f32(<4 x float> %{{[0-9]+}}) + + res_vd = vec_nearbyint(vd); +// CHECK: call <2 x double> @llvm.round.v2f64(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.round.v2f64(<2 x double> %{{[0-9]+}}) + + res_vf = vec_nmadd(vf, vf, vf); +// CHECK: [[FM:[0-9]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}) +// CHECK-NEXT: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %[[FM]] +// CHECK-LE: [[FM:[0-9]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}) +// CHECK-LE-NEXT: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %[[FM]] + + res_vd = vec_nmadd(vd, vd, vd); +// CHECK: [[FM:[0-9]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}) +// CHECK-NEXT: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %[[FM]] +// CHECK-LE: [[FM:[0-9]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}) +// CHECK-LE-NEXT: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %[[FM]] + + res_vf = vec_nmsub(vf, vf, vf); +// CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} +// CHECK-NEXT: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> +// CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} +// CHECK-LE: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} +// CHECK-LE-NEXT: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{[0-9]+}}, <4 x float> %{{[0-9]+}}, <4 x float> +// CHECK-LE: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{[0-9]+}} + + res_vd = vec_nmsub(vd, vd, vd); +// CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{[0-9]+}} +// CHECK-NEXT: [[FM:[0-9]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> +// CHECK-NEXT: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %[[FM]] +// CHECK-LE: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{[0-9]+}} +// CHECK-LE-NEXT: [[FM:[0-9]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{[0-9]+}}, <2 x double> %{{[0-9]+}}, <2 x double> +// CHECK-LE-NEXT: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %[[FM]] /* vec_nor */ res_vsll = vec_nor(vsll, vsll); // CHECK: or <2 x i64> // CHECK: xor <2 x i64> +// CHECK-LE: or <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_nor(vull, vull); // CHECK: or <2 x i64> // CHECK: xor <2 x i64> +// CHECK-LE: or <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_nor(vbll, vbll); // CHECK: or <2 x i64> // CHECK: xor <2 x i64> +// CHECK-LE: or <2 x i64> +// CHECK-LE: xor <2 x i64> + + res_vd = vec_nor(vd, vd); +// CHECK: bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK: [[OR:%.+]] = or <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-NEXT: xor <2 x i64> [[OR]], <i64 -1, i64 -1> +// CHECK-LE: bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK-LE: [[OR:%.+]] = or <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE-NEXT: xor <2 x i64> [[OR]], <i64 -1, i64 -1> /* vec_or */ res_vsll = vec_or(vsll, vsll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vsll = vec_or(vbll, vsll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vsll = vec_or(vsll, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_or(vull, vull); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_or(vbll, vull); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_or(vull, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vbll = vec_or(vbll, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> + + res_vd = vec_or(vd, vd); +// CHECK: bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK: or <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK-LE: or <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} + + res_vd = vec_or(vbll, vd); +// CHECK: [[T1:%.+]] = bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK: [[T2:%.+]] = or <2 x i64> %{{[0-9]+}}, [[T1]] +// CHECK: bitcast <2 x i64> [[T2]] to <2 x double> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK-LE: [[T2:%.+]] = or <2 x i64> %{{[0-9]+}}, [[T1]] +// CHECK-LE: bitcast <2 x i64> [[T2]] to <2 x double> + + res_vd = vec_or(vd, vbll); +// CHECK: [[T1:%.+]] = bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK: [[T2:%.+]] = or <2 x i64> [[T1]], %{{[0-9]+}} +// CHECK: bitcast <2 x i64> [[T2]] to <2 x double> +// CHECK-LE: [[T1:%.+]] = bitcast <2 x double> %{{[0-9]+}} to <2 x i64> +// CHECK-LE: [[T2:%.+]] = or <2 x i64> [[T1]], %{{[0-9]+}} +// CHECK-LE: bitcast <2 x i64> [[T2]] to <2 x double> + + res_vf = vec_re(vf); +// CHECK: call <4 x float> @llvm.ppc.vsx.xvresp(<4 x float> +// CHECK-LE: call <4 x float> @llvm.ppc.vsx.xvresp(<4 x float> + + res_vd = vec_re(vd); +// CHECK: call <2 x double> @llvm.ppc.vsx.xvredp(<2 x double> +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.xvredp(<2 x double> + + res_vf = vec_rint(vf); +// CHECK: call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %{{[0-9]+}}) + + res_vd = vec_rint(vd); +// CHECK: call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %{{[0-9]+}}) + + res_vf = vec_rsqrte(vf); +// CHECK: call <4 x float> @llvm.ppc.vsx.xvrsqrtesp(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.ppc.vsx.xvrsqrtesp(<4 x float> %{{[0-9]+}}) + + res_vd = vec_rsqrte(vd); +// CHECK: call <2 x double> @llvm.ppc.vsx.xvrsqrtedp(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.ppc.vsx.xvrsqrtedp(<2 x double> %{{[0-9]+}}) + + dummy(); +// CHECK: call void @dummy() +// CHECK-LE: call void @dummy() + + res_vf = vec_sel(vd, vd, vbll); +// CHECK: xor <2 x i64> %{{[0-9]+}}, <i64 -1, i64 -1> +// CHECK: and <2 x i64> %{{[0-9]+}}, +// CHECK: and <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK: or <2 x i64> +// CHECK: bitcast <2 x i64> %{{[0-9]+}} to <2 x double> +// CHECK-LE: xor <2 x i64> %{{[0-9]+}}, <i64 -1, i64 -1> +// CHECK-LE: and <2 x i64> %{{[0-9]+}}, +// CHECK-LE: and <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: or <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]+}} to <2 x double> + + dummy(); +// CHECK: call void @dummy() +// CHECK-LE: call void @dummy() + + res_vd = vec_sel(vd, vd, vull); +// CHECK: xor <2 x i64> %{{[0-9]+}}, <i64 -1, i64 -1> +// CHECK: and <2 x i64> %{{[0-9]+}}, +// CHECK: and <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK: or <2 x i64> +// CHECK: bitcast <2 x i64> %{{[0-9]+}} to <2 x double> +// CHECK-LE: xor <2 x i64> %{{[0-9]+}}, <i64 -1, i64 -1> +// CHECK-LE: and <2 x i64> %{{[0-9]+}}, +// CHECK-LE: and <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: or <2 x i64> +// CHECK-LE: bitcast <2 x i64> %{{[0-9]+}} to <2 x double> + + res_vf = vec_sqrt(vf); +// CHECK: call <4 x float> @llvm.sqrt.v4f32(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.sqrt.v4f32(<4 x float> %{{[0-9]+}}) + + res_vd = vec_sqrt(vd); +// CHECK: call <2 x double> @llvm.sqrt.v2f64(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.sqrt.v2f64(<2 x double> %{{[0-9]+}}) + + res_vd = vec_sub(vd, vd); +// CHECK: fsub <2 x double> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: fsub <2 x double> %{{[0-9]+}}, %{{[0-9]+}} + + res_vf = vec_trunc(vf); +// CHECK: call <4 x float> @llvm.trunc.v4f32(<4 x float> %{{[0-9]+}}) +// CHECK-LE: call <4 x float> @llvm.trunc.v4f32(<4 x float> %{{[0-9]+}}) + + res_vd = vec_trunc(vd); +// CHECK: call <2 x double> @llvm.trunc.v2f64(<2 x double> %{{[0-9]+}}) +// CHECK-LE: call <2 x double> @llvm.trunc.v2f64(<2 x double> %{{[0-9]+}}) /* vec_vor */ res_vsll = vec_vor(vsll, vsll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vsll = vec_vor(vbll, vsll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vsll = vec_vor(vsll, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_vor(vull, vull); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_vor(vbll, vull); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vull = vec_vor(vull, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> res_vbll = vec_vor(vbll, vbll); // CHECK: or <2 x i64> +// CHECK-LE: or <2 x i64> /* vec_xor */ res_vsll = vec_xor(vsll, vsll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vsll = vec_xor(vbll, vsll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vsll = vec_xor(vsll, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_xor(vull, vull); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_xor(vbll, vull); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_xor(vull, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vbll = vec_xor(vbll, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> + + dummy(); +// CHECK: call void @dummy() +// CHECK-LE: call void @dummy() + + res_vd = vec_xor(vd, vd); +// CHECK: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK: bitcast <2 x i64> [[X1]] to <2 x double> +// CHECK-LE: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: bitcast <2 x i64> [[X1]] to <2 x double> + + dummy(); +// CHECK: call void @dummy() +// CHECK-LE: call void @dummy() + + res_vd = vec_xor(vd, vbll); +// CHECK: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK: bitcast <2 x i64> [[X1]] to <2 x double> +// CHECK-LE: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: bitcast <2 x i64> [[X1]] to <2 x double> + + dummy(); +// CHECK: call void @dummy() +// CHECK-LE: call void @dummy() + + res_vd = vec_xor(vbll, vd); +// CHECK: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK: bitcast <2 x i64> [[X1]] to <2 x double> +// CHECK-LE: [[X1:%.+]] = xor <2 x i64> %{{[0-9]+}}, %{{[0-9]+}} +// CHECK-LE: bitcast <2 x i64> [[X1]] to <2 x double> /* vec_vxor */ res_vsll = vec_vxor(vsll, vsll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vsll = vec_vxor(vbll, vsll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vsll = vec_vxor(vsll, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_vxor(vull, vull); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_vxor(vbll, vull); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vull = vec_vxor(vull, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> res_vbll = vec_vxor(vbll, vbll); // CHECK: xor <2 x i64> +// CHECK-LE: xor <2 x i64> } diff --git a/test/CodeGen/debug-info-block.c b/test/CodeGen/debug-info-block.c index c4930bfc3c86..48a9f66877e1 100644 --- a/test/CodeGen/debug-info-block.c +++ b/test/CodeGen/debug-info-block.c @@ -1,10 +1,29 @@ // RUN: %clang_cc1 -fblocks -g -emit-llvm -o - %s | FileCheck %s // Verify that the desired debugging type is generated for a structure -// member that is a pointer to a block. +// member that is a pointer to a block. -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "__block_literal_generic" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, scope +// CHECK-NOT: line +// CHECK-SAME: elements: ![[ELEMS1:.*]]) +// CHECK: ![[ELEMS1]] = {{.*, .*, .*,}} ![[FPEL1:.*]], {{.*}} +// CHECK: ![[INT:.*]] = !DIBasicType(name: "int" +// CHECK: ![[FPEL1]] = {{.*}}"__FuncPtr", {{.*}}, baseType: ![[FPTY1:[0-9]+]] +// CHECK: ![[FPTY1]] = {{.*}}baseType: ![[FNTY1:[0-9]+]] +// CHECK: ![[FNTY1]] = !DISubroutineType(types: ![[VOIDVOID:[0-9]+]]) +// CHECK: ![[VOIDVOID]] = !{null, null} // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "__block_descriptor" +// CHECK-NOT: line +// CHECK-SAME: ) + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, scope +// CHECK-NOT: line +// CHECK-SAME: elements: ![[ELEMS2:.*]]) +// CHECK: ![[ELEMS2]] = {{.*,.*,.*}}, ![[FPEL2:.*]], {{.*}} +// CHECK: ![[FPEL2]] = {{.*}}"__FuncPtr", {{.*}}, baseType: ![[FPTY2:[0-9]+]] +// CHECK: ![[FPTY2]] = {{.*}}baseType: ![[FNTY2:[0-9]+]] +// CHECK: ![[FNTY2]] = !DISubroutineType(types: ![[INTINT:[0-9]+]]) +// CHECK: ![[INTINT]] = !{![[INT]], ![[INT]]} struct inStruct { - void (^genericBlockPtr)(); + void (^voidBlockPtr)(); + int (^intBlockPtr)(int); } is; - diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index 345d514611e3..772e28306b58 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s void abort(void) __attribute__((noreturn)); void might_crash(void); @@ -17,18 +18,18 @@ void basic_finally(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) // CHECK-NEXT: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}}) // CHECK: call void @cleanup() // Mostly check that we don't double emit 'r' which would crash. @@ -57,11 +58,11 @@ l: // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@label_in_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) // CHECK: ret void -// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"({{.*}}) // CHECK: br label %[[l:[^ ]*]] // // CHECK: [[l]] @@ -84,19 +85,19 @@ void use_abnormal_termination(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) // CHECK: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %abnormal_termination to i32 +// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer) +// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32 // CHECK: store i32 %[[abnormal_zext]], i32* @crashed // CHECK-NEXT: ret void @@ -109,11 +110,10 @@ void noreturn_noop_finally() { } // CHECK-LABEL: define void @noreturn_noop_finally() -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 0, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}}) // CHECK: ret void -// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}}) // CHECK: call void @abort() // CHECK: unreachable @@ -130,18 +130,16 @@ void noreturn_finally() { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 0, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) // CHECK: ret void // // CHECK: [[lpad]] // CHECK: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 1, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"({{.*}}) // CHECK: call void @abort() // CHECK: unreachable @@ -152,11 +150,10 @@ int finally_with_return() { } } // CHECK-LABEL: define i32 @finally_with_return() -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i8 0, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@finally_with_return@@"({{.*}}) // CHECK-NEXT: ret i32 42 -// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"({{.*}}) // CHECK-NOT: br i1 // CHECK-NOT: br label // CHECK: ret void @@ -174,25 +171,22 @@ int nested___finally___finally() { } // CHECK-LABEL: define i32 @nested___finally___finally -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"({{.*}}) // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[outercont]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) // CHECK-NEXT: ret i32 0 // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"({{.*}}) // CHECK: ret void -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"({{.*}}) // CHECK: unreachable int nested___finally___finally_with_eh_edge() { @@ -212,31 +206,27 @@ int nested___finally___finally_with_eh_edge() { // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]] // // [[invokecont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]]) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] // // CHECK: [[outercont]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK-NEXT: ret i32 912 // // CHECK: [[lpad1]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]]) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]] // // CHECK: [[lpad2]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]]) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: resume -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: ret void -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) // CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c index 36b896d06240..e56da17d0a80 100644 --- a/test/CodeGen/exceptions-seh-leave.c +++ b/test/CodeGen/exceptions-seh-leave.c @@ -74,7 +74,7 @@ int __leave_with___finally_simple() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i8 0, i8* %[[fp]]) // __finally block doesn't return, __finally.cont doesn't exist. @@ -94,7 +94,7 @@ int __leave_with___finally_noreturn() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i8 0, i8* %[[fp]]) // The "normal" case. @@ -118,7 +118,7 @@ int __leave_with___finally() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i8 0, i8* %[[fp]]) @@ -148,7 +148,7 @@ int nested___except___finally() { // CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont1]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] @@ -159,7 +159,7 @@ int nested___except___finally() { // CHECK: [[g1_lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: catch i8* null -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]]) // CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] @@ -205,7 +205,7 @@ int nested___except___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void @g() +// CHECK: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] @@ -216,7 +216,7 @@ int nested___except___except() { // CHECK: br label %[[outerexcept:[^ ]*]] // CHECK: [[outerexcept]] -// CHECK-NEXT: br label %[[trycont4:[^ ]*]] +// CHECK: br label %[[trycont4:[^ ]*]] // CHECK: [[trycont4]] // CHECK-NEXT: ret i32 1 @@ -258,15 +258,15 @@ int nested___finally___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void @g() +// CHECK: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK: br label %[[tryleave:[^ ]*]] // CHECK-NOT: 23 // CHECK: [[g2_lpad]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) // CHECK-NEXT: br label %[[ehresume:[^ ]*]] @@ -275,7 +275,7 @@ int nested___finally___except() { // CHECK-NEXT: br label %[[tryleave]] // CHECK: [[tryleave]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 1 @@ -311,20 +311,20 @@ int nested___finally___finally() { // CHECK: [[g1_cont]] // CHECK: store i32 16, i32* %[[myres:[^ ]*]], -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[finally_cont]] // CHECK: store i32 51, i32* %[[myres]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) // CHECK-NEXT: ret i32 1 // CHECK: [[g1_lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) // CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] @@ -337,7 +337,7 @@ int nested___finally___finally() { // CHECK: br label %[[ehcleanup]] // CHECK: [[ehcleanup]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) // CHECK: resume diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c index 1b77ad616278..9707a9a31beb 100644 --- a/test/CodeGen/exceptions-seh.c +++ b/test/CodeGen/exceptions-seh.c @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 void try_body(int numerator, int denominator, int *myres) { *myres = numerator / denominator; @@ -19,20 +22,46 @@ int safe_div(int numerator, int denominator, int *res) { *res = myres; return success; } -// CHECK-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] -// CHECK: to label %{{.*}} unwind label %[[lpad:[^ ]*]] -// -// CHECK: [[lpad]] -// CHECK: landingpad { i8*, i32 } -// CHECK-NEXT: catch i8* null -// CHECK-NOT: br i1 -// CHECK: br label %[[except:[^ ]*]] -// CHECK: [[except]] -// CHECK-NEXT: store i32 -42, i32* %[[success:[^ ]*]] -// -// CHECK: %[[res:[^ ]*]] = load i32, i32* %[[success]] -// CHECK: ret i32 %[[res]] + +// X64-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// X64: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] +// X64: to label %{{.*}} unwind label %[[lpad:[^ ]*]] +// +// X64: [[lpad]] +// X64: landingpad { i8*, i32 } +// X64-NEXT: catch i8* null +// X64-NOT: br i1 +// X64: br label %[[except:[^ ]*]] +// X64: [[except]] +// X64: store i32 -42, i32* %[[success:[^ ]*]] +// +// X64: %[[res:[^ ]*]] = load i32, i32* %[[success]] +// X64: ret i32 %[[res]] + +// X86-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res) {{.*}} personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// X86: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]] +// X86: to label %{{.*}} unwind label %[[lpad:[^ ]*]] +// +// X86: [[lpad]] +// X86: landingpad { i8*, i32 } +// X86-NEXT: catch i8* bitcast (i32 ()* @"\01?filt$0@0@safe_div@@" to i8*) +// X86-NOT: br i1 +// X86: br label %[[except:[^ ]*]] +// X86: [[except]] +// X86: store i32 -42, i32* %[[success:[^ ]*]] +// +// X86: %[[res:[^ ]*]] = load i32, i32* %[[success]] +// X86: ret i32 %[[res]] + +// X86-LABEL: define internal i32 @"\01?filt$0@0@safe_div@@"() +// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) +// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[ebp]]) +// X86: call i8* @llvm.localrecover(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[fp]], i32 0) +// X86: load i8*, i8** +// X86: load i32*, i32** +// X86: load i32, i32* +// X86: store i32 %{{.*}}, i32* +// X86: ret i32 1 void j(void); @@ -46,20 +75,29 @@ int filter_expr_capture(void) { return r; } -// CHECK-LABEL: define i32 @filter_expr_capture() {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// CHECK: call void (...) @llvm.frameescape(i32* %[[r:[^ ,]*]]) +// CHECK-LABEL: define i32 @filter_expr_capture() +// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// X64: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]]) +// X86: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]], i32* %[[code:[^ ,]*]]) // CHECK: store i32 42, i32* %[[r]] // CHECK: invoke void @j() #[[NOINLINE]] // // CHECK: landingpad -// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@filter_expr_capture@@" to i8*) +// CHECK-NEXT: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@filter_expr_capture@@" to i8*) // CHECK: store i32 13, i32* %[[r]] // // CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]] // CHECK: ret i32 %[[rv]] -// CHECK-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: call i8* @llvm.framerecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer, i32 0) +// X64-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer) +// X64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer, i32 0) +// +// X86-LABEL: define internal i32 @"\01?filt$0@0@filter_expr_capture@@"() +// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1) +// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[ebp]]) +// X86: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0) +// // CHECK: store i32 -1, i32* %{{.*}} // CHECK: ret i32 -1 @@ -77,7 +115,9 @@ int nested_try(void) { } return r; } -// CHECK-LABEL: define i32 @nested_try() {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// CHECK-LABEL: define i32 @nested_try() +// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) // CHECK: store i32 42, i32* %[[r:[^ ,]*]] // CHECK: invoke void @j() #[[NOINLINE]] // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] @@ -88,18 +128,18 @@ int nested_try(void) { // // CHECK: [[lpad]] // CHECK: landingpad { i8*, i32 } -// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*) -// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*) +// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*) +// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*) // CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]] // CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]] // // CHECK: load i32, i32* %[[sel_slot]] -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)) +// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})* @"\01?filt$1@0@nested_try@@" to i8*)) // CHECK: icmp eq i32 // CHECK: br i1 // // CHECK: load i32, i32* %[[sel_slot]] -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*)) +// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})* @"\01?filt$0@0@nested_try@@" to i8*)) // CHECK: icmp eq i32 // CHECK: br i1 // @@ -115,40 +155,55 @@ int nested_try(void) { // // CHECK: [[inner_try_cont]] // CHECK: br label %[[outer_try_cont]] +// +// CHECK-LABEL: define internal i32 @"\01?filt$0@0@nested_try@@"({{.*}}) +// X86: call i8* @llvm.x86.seh.recoverfp({{.*}}) +// CHECK: load i32*, i32** +// CHECK: load i32, i32* +// CHECK: icmp eq i32 %{{.*}}, 456 +// +// CHECK-LABEL: define internal i32 @"\01?filt$1@0@nested_try@@"({{.*}}) +// X86: call i8* @llvm.x86.seh.recoverfp({{.*}}) +// CHECK: load i32*, i32** +// CHECK: load i32, i32* +// CHECK: icmp eq i32 %{{.*}}, 123 -static unsigned g = 0; -void basic_finally(void) { - ++g; +int basic_finally(int g) { __try { j(); } __finally { - --g; + ++g; } + return g; } -// CHECK-LABEL: define void @basic_finally() {{.*}} personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -// CHECK: load i32, i32* @g -// CHECK: add i32 %{{.*}}, 1 -// CHECK: store i32 %{{.*}}, i32* @g +// CHECK-LABEL: define i32 @basic_finally(i32 %g) +// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) +// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +// CHECK: %[[g_addr:[^ ]*]] = alloca i32, align 4 +// CHECK: call void (...) @llvm.localescape(i32* %[[g_addr]]) +// CHECK: store i32 %g, i32* %[[g_addr]] // // CHECK: invoke void @j() // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]]) -// CHECK: ret void +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) +// CHECK: load i32, i32* %[[g_addr]], align 4 +// CHECK: ret i32 // // CHECK: [[lpad]] // CHECK: landingpad { i8*, i32 } // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]]) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) // CHECK: resume -// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i8 %abnormal_termination, i8* %frame_pointer) -// CHECK: load i32, i32* @g, align 4 -// CHECK: add i32 %{{.*}}, -1 -// CHECK: store i32 %{{.*}}, i32* @g, align 4 +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} %abnormal_termination, i8* %frame_pointer) +// CHECK: call i8* @llvm.localrecover(i8* bitcast (i32 (i32)* @basic_finally to i8*), i8* %frame_pointer, i32 0) +// CHECK: load i32, i32* %{{.*}}, align 4 +// CHECK: add nsw i32 %{{.*}}, 1 +// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 4 // CHECK: ret void int returns_int(void); diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c index a45bccc51328..16e95c03c875 100644 --- a/test/CodeGen/inline.c +++ b/test/CodeGen/inline.c @@ -54,6 +54,7 @@ // RUN: echo "MS C Mode tests:" // RUN: %clang_cc1 %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=c99 -fms-compatibility | FileCheck %s --check-prefix=CHECK4 +// CHECK4-NOT: define weak_odr void @_Exit( // CHECK4-LABEL: define weak_odr i32 @ei() // CHECK4-LABEL: define i32 @bar() // CHECK4-NOT: unreferenced1 @@ -62,6 +63,9 @@ // CHECK4-LABEL: define linkonce_odr i32 @foo() // CHECK4-LABEL: define available_externally void @gnu_ei_inline() +__attribute__((noreturn)) void __cdecl _exit(int _Code); +__inline void __cdecl _Exit(int status) { _exit(status); } + extern __inline int ei() { return 123; } __inline int foo() { diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c index 1dcd2ec468d7..e2bbd41a9daf 100644 --- a/test/CodeGen/packed-nest-unpacked.c +++ b/test/CodeGen/packed-nest-unpacked.c @@ -60,6 +60,35 @@ struct YBitfield gbitfield; unsigned test7() { // CHECK: @test7 - // CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 4 + // CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1 return gbitfield.y.b2; } + +void test8(unsigned x) { + // CHECK: @test8 + // CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1 + // CHECK: store i32 {{.*}}, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1 + gbitfield.y.b2 = x; +} + +struct TBitfield +{ + long a; + char b; + unsigned c:15; +}; +struct TBitfield tbitfield; + +unsigned test9() { + // CHECK: @test9 + // CHECK: load i16, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1 + return tbitfield.c; +} + +void test10(unsigned x) { + // CHECK: @test10 + // CHECK: load i16, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1 + // CHECK: store i16 {{.*}}, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1 + tbitfield.c = x; +} + diff --git a/test/CodeGen/ppc64-struct-onefloat.c b/test/CodeGen/ppc64-struct-onefloat.c index d0ccfbe34a44..534e5116f9b0 100644 --- a/test/CodeGen/ppc64-struct-onefloat.c +++ b/test/CodeGen/ppc64-struct-onefloat.c @@ -14,15 +14,15 @@ void bar(Sf a, Sd b, SSf d, SSd e) {} // CHECK: %d = alloca %struct.s4, align 4 // CHECK: %e = alloca %struct.s5, align 8 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1, %struct.s1* %a, i32 0, i32 0 -// CHECK: store float %a.coerce, float* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: store float %a.coerce, float* %{{[a-zA-Z0-9.]+}}, align 4 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2, %struct.s2* %b, i32 0, i32 0 -// CHECK: store double %b.coerce, double* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: store double %b.coerce, double* %{{[a-zA-Z0-9.]+}}, align 8 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s4, %struct.s4* %d, i32 0, i32 0 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1, %struct.s1* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0 -// CHECK: store float %d.coerce, float* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: store float %d.coerce, float* %{{[a-zA-Z0-9.]+}}, align 4 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s5, %struct.s5* %e, i32 0, i32 0 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2, %struct.s2* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0 -// CHECK: store double %e.coerce, double* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: store double %e.coerce, double* %{{[a-zA-Z0-9.]+}}, align 8 // CHECK: ret void void foo(void) @@ -36,14 +36,14 @@ void foo(void) // CHECK-LABEL: define void @foo // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1, %struct.s1* %p1, i32 0, i32 0 -// CHECK: %{{[0-9]+}} = load float, float* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: %{{[0-9]+}} = load float, float* %{{[a-zA-Z0-9.]+}}, align 4 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2, %struct.s2* %p2, i32 0, i32 0 -// CHECK: %{{[0-9]+}} = load double, double* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: %{{[0-9]+}} = load double, double* %{{[a-zA-Z0-9.]+}}, align 8 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s4, %struct.s4* %p4, i32 0, i32 0 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1, %struct.s1* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0 -// CHECK: %{{[0-9]+}} = load float, float* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: %{{[0-9]+}} = load float, float* %{{[a-zA-Z0-9.]+}}, align 4 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s5, %struct.s5* %p5, i32 0, i32 0 // CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2, %struct.s2* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0 -// CHECK: %{{[0-9]+}} = load double, double* %{{[a-zA-Z0-9.]+}}, align 1 +// CHECK: %{{[0-9]+}} = load double, double* %{{[a-zA-Z0-9.]+}}, align 8 // CHECK: call void @bar(float inreg %{{[0-9]+}}, double inreg %{{[0-9]+}}, float inreg %{{[0-9]+}}, double inreg %{{[0-9]+}}) // CHECK: ret void diff --git a/test/CodeGen/ppc64le-aggregates.c b/test/CodeGen/ppc64le-aggregates.c index 76798c132734..3ad4b06c688a 100644 --- a/test/CodeGen/ppc64le-aggregates.c +++ b/test/CodeGen/ppc64le-aggregates.c @@ -54,49 +54,49 @@ struct fabc func_fabc(struct fabc x) { return x; } struct f2a2b func_f2a2b(struct f2a2b x) { return x; } // CHECK-LABEL: @call_f1 -// CHECK: %[[TMP:[^ ]+]] = load float, float* getelementptr inbounds (%struct.f1, %struct.f1* @global_f1, i32 0, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load float, float* getelementptr inbounds (%struct.f1, %struct.f1* @global_f1, i32 0, i32 0, i32 0), align 4 // CHECK: call [1 x float] @func_f1(float inreg %[[TMP]]) struct f1 global_f1; void call_f1(void) { global_f1 = func_f1(global_f1); } // CHECK-LABEL: @call_f2 -// CHECK: %[[TMP:[^ ]+]] = load [2 x float], [2 x float]* getelementptr inbounds (%struct.f2, %struct.f2* @global_f2, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [2 x float], [2 x float]* getelementptr inbounds (%struct.f2, %struct.f2* @global_f2, i32 0, i32 0), align 4 // CHECK: call [2 x float] @func_f2([2 x float] %[[TMP]]) struct f2 global_f2; void call_f2(void) { global_f2 = func_f2(global_f2); } // CHECK-LABEL: @call_f3 -// CHECK: %[[TMP:[^ ]+]] = load [3 x float], [3 x float]* getelementptr inbounds (%struct.f3, %struct.f3* @global_f3, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [3 x float], [3 x float]* getelementptr inbounds (%struct.f3, %struct.f3* @global_f3, i32 0, i32 0), align 4 // CHECK: call [3 x float] @func_f3([3 x float] %[[TMP]]) struct f3 global_f3; void call_f3(void) { global_f3 = func_f3(global_f3); } // CHECK-LABEL: @call_f4 -// CHECK: %[[TMP:[^ ]+]] = load [4 x float], [4 x float]* getelementptr inbounds (%struct.f4, %struct.f4* @global_f4, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [4 x float], [4 x float]* getelementptr inbounds (%struct.f4, %struct.f4* @global_f4, i32 0, i32 0), align 4 // CHECK: call [4 x float] @func_f4([4 x float] %[[TMP]]) struct f4 global_f4; void call_f4(void) { global_f4 = func_f4(global_f4); } // CHECK-LABEL: @call_f5 -// CHECK: %[[TMP:[^ ]+]] = load [5 x float], [5 x float]* getelementptr inbounds (%struct.f5, %struct.f5* @global_f5, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [5 x float], [5 x float]* getelementptr inbounds (%struct.f5, %struct.f5* @global_f5, i32 0, i32 0), align 4 // CHECK: call [5 x float] @func_f5([5 x float] %[[TMP]]) struct f5 global_f5; void call_f5(void) { global_f5 = func_f5(global_f5); } // CHECK-LABEL: @call_f6 -// CHECK: %[[TMP:[^ ]+]] = load [6 x float], [6 x float]* getelementptr inbounds (%struct.f6, %struct.f6* @global_f6, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [6 x float], [6 x float]* getelementptr inbounds (%struct.f6, %struct.f6* @global_f6, i32 0, i32 0), align 4 // CHECK: call [6 x float] @func_f6([6 x float] %[[TMP]]) struct f6 global_f6; void call_f6(void) { global_f6 = func_f6(global_f6); } // CHECK-LABEL: @call_f7 -// CHECK: %[[TMP:[^ ]+]] = load [7 x float], [7 x float]* getelementptr inbounds (%struct.f7, %struct.f7* @global_f7, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [7 x float], [7 x float]* getelementptr inbounds (%struct.f7, %struct.f7* @global_f7, i32 0, i32 0), align 4 // CHECK: call [7 x float] @func_f7([7 x float] %[[TMP]]) struct f7 global_f7; void call_f7(void) { global_f7 = func_f7(global_f7); } // CHECK-LABEL: @call_f8 -// CHECK: %[[TMP:[^ ]+]] = load [8 x float], [8 x float]* getelementptr inbounds (%struct.f8, %struct.f8* @global_f8, i32 0, i32 0), align 1 +// CHECK: %[[TMP:[^ ]+]] = load [8 x float], [8 x float]* getelementptr inbounds (%struct.f8, %struct.f8* @global_f8, i32 0, i32 0), align 4 // CHECK: call [8 x float] @func_f8([8 x float] %[[TMP]]) struct f8 global_f8; void call_f8(void) { global_f8 = func_f8(global_f8); } @@ -104,7 +104,7 @@ void call_f8(void) { global_f8 = func_f8(global_f8); } // CHECK-LABEL: @call_f9 // CHECK: %[[TMP1:[^ ]+]] = alloca [5 x i64] // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[TMP2]], i8* bitcast (%struct.f9* @global_f9 to i8*), i64 36, i32 1, i1 false) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[TMP2]], i8* bitcast (%struct.f9* @global_f9 to i8*), i64 36, i32 4, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] // CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) struct f9 global_f9; diff --git a/test/CodeGenCXX/2012-03-16-StoreAlign.cpp b/test/CodeGenCXX/2012-03-16-StoreAlign.cpp index 7e82ca544dc0..5f6189e2451b 100644 --- a/test/CodeGenCXX/2012-03-16-StoreAlign.cpp +++ b/test/CodeGenCXX/2012-03-16-StoreAlign.cpp @@ -28,7 +28,7 @@ struct Foo { }; // CHECK: @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth = linkonce_odr global %struct.Length zeroinitializer, align 4 -// CHECK: store float %{{.*}}, float* getelementptr inbounds (%struct.Length, %struct.Length* @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth, i32 0, i32 0), align 1 +// CHECK: store float %{{.*}}, float* getelementptr inbounds (%struct.Length, %struct.Length* @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth, i32 0, i32 0), align 4 bool bar(Length &b) { Foo f; diff --git a/test/CodeGenCXX/cfi-ms-rtti.cpp b/test/CodeGenCXX/cfi-ms-rtti.cpp new file mode 100644 index 000000000000..5203a6bb0c8b --- /dev/null +++ b/test/CodeGenCXX/cfi-ms-rtti.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s +// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s + +struct A { + A(); + virtual void f() {} +}; + +A::A() {} + +// RTTI: !{!"A@@", [2 x i8*]* {{.*}}, i64 8} +// NO-RTTI: !{!"A@@", [1 x i8*]* {{.*}}, i64 0} diff --git a/test/CodeGenCXX/cfi-vcall.cpp b/test/CodeGenCXX/cfi-vcall.cpp index 333c7bd1f160..5cb5e02cf585 100644 --- a/test/CodeGenCXX/cfi-vcall.cpp +++ b/test/CodeGenCXX/cfi-vcall.cpp @@ -134,6 +134,29 @@ void foo() { af(&fa); } +namespace test2 { + +struct A { + virtual void m_fn1(); +}; +struct B { + virtual void m_fn2(); +}; +struct C : B, A {}; +struct D : C { + void m_fn1(); +}; + +// ITANIUM: define void @_ZN5test21fEPNS_1DE +// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z" +void f(D *d) { + // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"N5test21DE") + // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"A@test2@@") + d->m_fn1(); +} + +} + // Check for the expected number of elements (9 or 15 respectively). // MS: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){8}]]} // ITANIUM: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]} diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp index 35b371ec9c9d..8a00d9b4a5eb 100644 --- a/test/CodeGenCXX/debug-info-namespace.cpp +++ b/test/CodeGenCXX/debug-info-namespace.cpp @@ -104,8 +104,7 @@ void B::func_fwd() {} // CHECK-GMLT: [[CU:![0-9]+]] = distinct !DICompileUnit( // CHECK-GMLT-SAME: emissionKind: 2, -// CHECK-GMLT-SAME: imports: [[MODULES:![0-9]+]] -// CHECK-GMLT: [[MODULES]] = !{} +// CHECK-GMLT-NOT: imports: // CHECK-NOLIMIT: !DICompositeType(tag: DW_TAG_structure_type, name: "bar",{{.*}} line: 6, // CHECK-NOLIMIT-NOT: DIFlagFwdDecl diff --git a/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp b/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp new file mode 100644 index 000000000000..29fb5567fb1d --- /dev/null +++ b/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp @@ -0,0 +1,37 @@ +// Check that in case of copying an array of memcpy-able objects, their +// destructors will be called if an exception is thrown. +// +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s + +struct ImplicitCopy { + int x; + ImplicitCopy() { x = 10; } + ~ImplicitCopy() { x = 20; } +}; + +struct ThrowCopy { + ThrowCopy() {} + ThrowCopy(const ThrowCopy &) { throw 1; } +}; + +struct Container { + ImplicitCopy b[2]; + ThrowCopy c; +}; + +int main () { + try { + Container c1; + // CHECK_LABEL: main + // CHECK-NOT: call void @_ZN9ThrowCopyC1ERKS_ + // CHECK: invoke void @_ZN9ThrowCopyC1ERKS_ + // CHECK: invoke void @_ZN12ImplicitCopyD1Ev + Container c2(c1); + } + catch (...) { + return 1; + } + + return 0; +} + diff --git a/test/CodeGenCXX/eh-aggregated-inits-unwind.cpp b/test/CodeGenCXX/eh-aggregated-inits-unwind.cpp new file mode 100644 index 000000000000..9772564b051c --- /dev/null +++ b/test/CodeGenCXX/eh-aggregated-inits-unwind.cpp @@ -0,0 +1,47 @@ +// Check that destructors of memcpy-able struct members are called properly +// during stack unwinding after an exception. +// +// Check that destructor's argument (address of member to be destroyed) is +// obtained by taking offset from struct, not by bitcasting pointers. +// +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s + +struct ImplicitCopy { + int id; + ImplicitCopy() { id = 10; } + ~ImplicitCopy() { id = 20; } +}; + +struct ThrowCopy { + int id; + ThrowCopy() { id = 15; } + ThrowCopy(const ThrowCopy &x) { + id = 25; + throw 1; + } + ~ThrowCopy() { id = 35; } +}; + +struct Container { + int id; + ImplicitCopy o1; + ThrowCopy o2; + + Container() { id = 1000; } + ~Container() { id = 2000; } +}; + +int main() { + try { + Container c1; + // CHECK-LABEL: main + // CHECK: %{{.+}} = getelementptr inbounds %struct.Container, %struct.Container* %{{.+}}, i32 0, i32 1 + // CHECK-NOT: %{{.+}} = bitcast %struct.Container* %{{.+}} to %struct.ImplicitCopy* + Container c2(c1); + + return 2; + } catch (...) { + return 1; + } + return 0; +} diff --git a/test/CodeGenCXX/eh-aggregated-inits.cpp b/test/CodeGenCXX/eh-aggregated-inits.cpp new file mode 100644 index 000000000000..cb34b65dfe8e --- /dev/null +++ b/test/CodeGenCXX/eh-aggregated-inits.cpp @@ -0,0 +1,46 @@ +// Check that initialization of the only one memcpy-able struct member will not +// be performed twice after successful non-trivial initializtion of the second +// member. +// +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s + +int globId = 0; + +struct ImplicitCopy { + int id; + + ImplicitCopy() { id = 10; } + ~ImplicitCopy() { id = 20; } +}; + +struct ExplicitCopy { + int id; + + ExplicitCopy() { id = 15; } + ExplicitCopy(const ExplicitCopy &x) { id = 25; } + ~ExplicitCopy() { id = 35; } +}; + +struct Container { + ImplicitCopy o1; // memcpy-able member. + ExplicitCopy o2; // non-trivial initialization. + + Container() { globId = 1000; } + ~Container() { globId = 2000; } +}; + +int main() { + try { + Container c1; + // CHECK-DAG: call void @llvm.memcpy + // CHECK-DAG: declare void @llvm.memcpy + // CHECK-NOT: @llvm.memcpy + Container c2(c1); + + return 2; + } + catch (...) { + return 1; + } + return 0; +} diff --git a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp index 5df418a13ad8..26ef90f5a6f3 100644 --- a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp +++ b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp @@ -15,15 +15,15 @@ extern "C" void test_freefunc(int p1) { } // CHECK-LABEL: define void @test_freefunc(i32 %p1) -// CHECK: @llvm.frameescape(i32* %[[p1_ptr:[^, ]*]], i32* %[[l1_ptr:[^, ]*]]) +// CHECK: @llvm.localescape(i32* %[[p1_ptr:[^, ]*]], i32* %[[l1_ptr:[^, ]*]]) // CHECK: store i32 %p1, i32* %[[p1_ptr]], align 4 // CHECK: store i32 13, i32* %[[l1_ptr]], align 4 // CHECK: invoke void @might_crash() // CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_freefunc@@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 0) +// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 0) // CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32* -// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 1) +// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 1) // CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32* // CHECK: %[[s1:[^ ]*]] = load i32, i32* @"\01?s1@?1??test_freefunc@@9@4HA", align 4 // CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]] @@ -45,12 +45,12 @@ void S::test_method() { } // CHECK-LABEL: define void @"\01?test_method@S@@QEAAXXZ"(%struct.S* %this) -// CHECK: @llvm.frameescape(i32* %[[l1_addr:[^, ]*]]) +// CHECK: @llvm.localescape(i32* %[[l1_addr:[^, ]*]]) // CHECK: store i32 13, i32* %[[l1_addr]], align 4 // CHECK: invoke void @might_crash() // CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_method@S@@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer, i32 0) +// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer, i32 0) // CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32* // CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]] // CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]]) @@ -69,12 +69,12 @@ void test_lambda() { } // CHECK-LABEL: define internal void @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this) -// CHECK: @llvm.frameescape(i32* %[[l2_addr:[^, ]*]]) +// CHECK: @llvm.localescape(i32* %[[l2_addr:[^, ]*]]) // CHECK: store i32 42, i32* %[[l2_addr]], align 4 // CHECK: invoke void @might_crash() // CHECK-LABEL: define internal i32 @"\01?filt$0@0@?R<lambda_0>@?test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer) -// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ" to i8*), i8* %frame_pointer, i32 0) +// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ" to i8*), i8* %frame_pointer, i32 0) // CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32* // CHECK: %[[l2:[^ ]*]] = load i32, i32* %[[l2_ptr]] // CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l2]]) diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp index 2cee4f77e5d4..187ad4bc710e 100644 --- a/test/CodeGenCXX/exceptions-seh.cpp +++ b/test/CodeGenCXX/exceptions-seh.cpp @@ -127,13 +127,13 @@ void use_inline() { // // CHECK: invoke void @might_throw() // -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 0, i8* %[[fp]]) // CHECK: ret void // // CHECK: landingpad { i8*, i32 } // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() // CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]]) // CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func) diff --git a/test/CodeGenCXX/pr24097.cpp b/test/CodeGenCXX/pr24097.cpp new file mode 100644 index 000000000000..122bf88506d3 --- /dev/null +++ b/test/CodeGenCXX/pr24097.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple=x86_64-pc-linux -fvisibility hidden -emit-llvm -O1 -disable-llvm-optzns -o - | FileCheck %s + +struct Filter { + virtual void Foo(); +}; +struct Sender { + virtual bool Send(); +}; +struct SyncMessageFilter : public Filter, public Sender { + bool Send(); +}; +struct TestSyncMessageFilter : public SyncMessageFilter { +}; +void bar() { + TestSyncMessageFilter f; + f.Send(); +} + +// Test that it is not hidden +// CHECK: define available_externally zeroext i1 @_ZThn8_N17SyncMessageFilter4SendEv diff --git a/test/CodeGenCXX/sanitize-dtor-callback.cpp b/test/CodeGenCXX/sanitize-dtor-callback.cpp new file mode 100644 index 000000000000..4912a27229f9 --- /dev/null +++ b/test/CodeGenCXX/sanitize-dtor-callback.cpp @@ -0,0 +1,17 @@ +// Test -fsanitize-memory-use-after-dtor +// RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fsanitize=memory -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s -check-prefix=NO_DTOR_CHECK + +struct Simple { + ~Simple() {} +}; +Simple s; +// Simple internal member is poisoned by compiler-generated dtor +// CHECK-LABEL: @_ZN6SimpleD2Ev +// CHECK: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// Compiling without the flag does not generate member-poisoning dtor +// NO_DTOR_CHECK-LABEL: @_ZN6SimpleD2Ev +// NO_DTOR_CHECK-NOT: call void @sanitizer_dtor_callback +// NO_DTOR_CHECK: ret void diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp index 1ea072e2eb5a..e0165994d013 100644 --- a/test/CodeGenCXX/varargs.cpp +++ b/test/CodeGenCXX/varargs.cpp @@ -37,7 +37,7 @@ namespace test1 { // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[X]] to i8* // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 8, i32 4, i1 false) // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i64* - // CHECK-NEXT: [[T1:%.*]] = load i64, i64* [[T0]], align 1 + // CHECK-NEXT: [[T1:%.*]] = load i64, i64* [[T0]], align 4 // CHECK-NEXT: call void (...) @_ZN5test13fooEz(i64 [[T1]]) // CHECK-NEXT: ret void } diff --git a/test/CodeGenCXX/x86_64-arguments-avx.cpp b/test/CodeGenCXX/x86_64-arguments-avx.cpp index 29e693451d12..2933d9445b76 100644 --- a/test/CodeGenCXX/x86_64-arguments-avx.cpp +++ b/test/CodeGenCXX/x86_64-arguments-avx.cpp @@ -50,3 +50,12 @@ UU2 PR23082(UU2 x) { return x; } } + +namespace test3 { +union U { + __attribute__((__vector_size__(32))) float f1; + int f2; +}; +// CHECK: define i32 @_ZN5test31fENS_1UE({{.*}}* byval align 32 +int f(U u) { return u.f2; } +} diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp index 815ef6111a9a..64202b4d02c6 100644 --- a/test/CodeGenCXX/x86_64-arguments.cpp +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -196,3 +196,19 @@ namespace test9 { return sret; } } + +namespace test10 { +#pragma pack(1) +struct BasePacked { + char one; + short two; +}; +#pragma pack() +struct DerivedPacked : public BasePacked { + int three; +}; +// CHECK-LABEL: define i32 @_ZN6test1020FuncForDerivedPackedENS_13DerivedPackedE({{.*}}* byval align 8 +int FuncForDerivedPacked(DerivedPacked d) { + return d.three; +} +} diff --git a/test/CodeGenObjC/parameterized_classes.m b/test/CodeGenObjC/parameterized_classes.m new file mode 100644 index 000000000000..1d8e9a259934 --- /dev/null +++ b/test/CodeGenObjC/parameterized_classes.m @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-arc -emit-llvm -o - %s | FileCheck %s + +// Parameterized classes have no effect on code generation; this test +// mainly verifies that CodeGen doesn't assert when substituted types +// in uses of methods don't line up exactly with the parameterized +// types in the method declarations due to type erasure. "Not crash" +// is the only interesting criteria here. + +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableArray<T> : NSObject <NSCopying> +@property (copy,nonatomic) T firstObject; +- (void)addObject:(T)object; +- (void)sortWithFunction:(int (*)(T, T))function; +- (void)getObjects:(T __strong *)objects length:(unsigned*)length; +@end + +NSString *getFirstObjectProp(NSMutableArray<NSString *> *array) { + return array.firstObject; +} + +NSString *getFirstObjectMethod(NSMutableArray<NSString *> *array) { + return [array firstObject]; +} + +void addObject(NSMutableArray<NSString *> *array, NSString *obj) { + [array addObject: obj]; +} + +int compareStrings(NSString *x, NSString *y) { return 0; } +int compareBlocks(NSString * (^x)(NSString *), + NSString * (^y)(NSString *)) { return 0; } + +void sortTest(NSMutableArray<NSString *> *array, + NSMutableArray<NSString * (^)(NSString *)> *array2) { + [array sortWithFunction: &compareStrings]; + [array2 sortWithFunction: &compareBlocks]; +} + +void getObjectsTest(NSMutableArray<NSString *> *array) { + NSString * __strong *objects; + unsigned length; + [array getObjects: objects length: &length]; +} + +void printMe(NSString *name) { } + +// CHECK-LABEL: define void @blockTest +void blockTest(NSMutableArray<void (^)(void)> *array, NSString *name) { + // CHECK: call i8* @objc_retainBlock + [array addObject: ^ { printMe(name); }]; +} diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm index 5b944caf1f41..bcb920ba1e91 100644 --- a/test/CodeGenObjCXX/mangle.mm +++ b/test/CodeGenObjCXX/mangle.mm @@ -98,3 +98,18 @@ template<> void X<A*>::f() {} // CHECK-LABEL: define void @_ZN1XIP1AE1fEv template<> void X<A<P>*>::f() {} // CHECK-LABEL: define void @_ZN1XIPU11objcproto1P1AE1fEv + +// CHECK-LABEL: define void @_Z12kindof_test2PU8__kindof5Test2 +void kindof_test2(__kindof Test2 *t2) { } + +@interface Parameterized<T, U> : A +@end + +// CHECK-LABEL: define void @_Z19parameterized_test1P13ParameterizedIP1AP4TestE +void parameterized_test1(Parameterized<A *, Test *> *p) {} + +// CHECK-LABEL: define void @_Z19parameterized_test2PU8__kindof13ParameterizedIP1AP4TestE +void parameterized_test2(__kindof Parameterized<A *, Test *> *p) {} + +// CHECK-LABEL: define void @_Z19parameterized_test3P13Parameterized +void parameterized_test3(Parameterized *p) {} diff --git a/test/Driver/apple-kext-mkernel.c b/test/Driver/apple-kext-mkernel.c index 8282c05dd8f1..5f4f52246155 100644 --- a/test/Driver/apple-kext-mkernel.c +++ b/test/Driver/apple-kext-mkernel.c @@ -11,7 +11,7 @@ // RUN: -arch armv7 -mkernel -mstrict-align -### -fsyntax-only %s 2> %t // RUN: FileCheck --check-prefix=CHECK-ARM < %t %s -// CHECK-ARM: "-backend-option" "-arm-long-calls" +// CHECK-ARM: "-target-feature" "+long-calls" // CHECK-ARM: "-backend-option" "-arm-strict-align" // CHECK-ARM-NOT: "-backend-option" "-arm-strict-align" // CHECK-ARM: "-fno-builtin" diff --git a/test/Driver/arm-long-calls.c b/test/Driver/arm-long-calls.c index 62294a09c22a..375b0f81c24f 100644 --- a/test/Driver/arm-long-calls.c +++ b/test/Driver/arm-long-calls.c @@ -7,9 +7,9 @@ // RUN: %clang -target armv7-eabi -### -mlong-calls -mno-long-calls %s 2>&1 \ // RUN: | FileCheck %s -check-prefix CHECK-NO-LONG-CALLS -// CHECK-DEFAULT-NOT: "-backend-option" "-arm-long-calls" +// CHECK-DEFAULT-NOT: "-target-feature" "+long-calls" -// CHECK-LONG-CALLS: "-backend-option" "-arm-long-calls" +// CHECK-LONG-CALLS: "-target-feature" "+long-calls" -// CHECK-NO-LONG-CALLS-NOT: "-backend-option" "-arm-long-calls" +// CHECK-NO-LONG-CALLS-NOT: "-target-feature" "+long-calls" diff --git a/test/Driver/cl-eh.cpp b/test/Driver/cl-eh.cpp index a71491edeaf3..b43f31f83fc7 100644 --- a/test/Driver/cl-eh.cpp +++ b/test/Driver/cl-eh.cpp @@ -4,9 +4,11 @@ // Note: %s must be preceded by --, otherwise it may be interpreted as a // command-line option, e.g. on Mac where %s is commonly under /Users. +// FIXME: When C++ EH works, we can make this flag turn things back on. + // RUN: %clang_cl /c /EHsc -### -- %s 2>&1 | FileCheck -check-prefix=EHsc %s -// EHsc: "-fcxx-exceptions" -// EHsc: "-fexceptions" +// EHsc-NOT: "-fcxx-exceptions" +// EHsc-NOT: "-fexceptions" // RUN: %clang_cl /c /EHs-c- -### -- %s 2>&1 | FileCheck -check-prefix=EHs_c_ %s // EHs_c_-NOT: "-fcxx-exceptions" @@ -17,12 +19,12 @@ // EHs_EHc_-NOT: "-fexceptions" // RUN: %clang_cl /c /EHs- /EHs -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHs %s -// EHs_EHs: "-fcxx-exceptions" -// EHs_EHs: "-fexceptions" +// EHs_EHs-NOT: "-fcxx-exceptions" +// EHs_EHs-NOT: "-fexceptions" // RUN: %clang_cl /c /EHs- /EHsa -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHa %s -// EHs_EHa: "-fcxx-exceptions" -// EHs_EHa: "-fexceptions" +// EHs_EHa-NOT: "-fcxx-exceptions" +// EHs_EHa-NOT: "-fexceptions" // RUN: %clang_cl /c /EHinvalid -### -- %s 2>&1 | FileCheck -check-prefix=EHinvalid %s // EHinvalid: error: invalid value 'invalid' in '/EH' diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index 68890a70bc52..003430174b61 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -66,6 +66,40 @@ // CHECK-PROFILE-ARCS: "-femit-coverage-data" // CHECK-NO-PROFILE-ARCS-NOT: "-femit-coverage-data" +// RUN: %clang -### -S -fprofile-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s +// RUN: %clang -### -S -fprofile-instr-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s +// RUN: %clang -### -S -fprofile-generate=/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-DIR %s +// RUN: %clang -### -S -fprofile-instr-generate=/tmp/somefile.profraw %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-FILE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// CHECK-PROFILE-GENERATE: "-fprofile-instr-generate" +// CHECK-PROFILE-GENERATE-DIR: "-fprofile-instr-generate=/some/dir{{/|\\\\}}default.profraw" +// CHECK-PROFILE-GENERATE-FILE: "-fprofile-instr-generate=/tmp/somefile.profraw" +// CHECK-NO-MIX-GEN-USE: '{{[a-z=-]*}}' not allowed with '{{[a-z=-]*}}' + +// RUN: %clang -### -S -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s +// RUN: %clang -### -S -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s +// RUN: mkdir -p %t.d/some/dir +// RUN: %clang -### -S -fprofile-use=%t.d/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-DIR %s +// RUN: %clang -### -S -fprofile-instr-use=/tmp/somefile.prof %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// CHECK-PROFILE-USE: "-fprofile-instr-use=default.profdata" +// CHECK-PROFILE-USE-DIR: "-fprofile-instr-use={{.*}}.d/some/dir{{/|\\\\}}default.profdata" +// CHECK-PROFILE-USE-FILE: "-fprofile-instr-use=/tmp/somefile.prof" + // RUN: %clang -### -S -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s // RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s // RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s @@ -162,7 +196,6 @@ // RUN: -fprefetch-loop-arrays -fno-prefetch-loop-arrays \ // RUN: -fprofile-correction -fno-profile-correction \ // RUN: -fprofile-dir=bar \ -// RUN: -fprofile-use -fprofile-use=zed -fno-profile-use \ // RUN: -fprofile-values -fno-profile-values \ // RUN: -frounding-math -fno-rounding-math \ // RUN: -fsee -fno-see \ @@ -242,8 +275,6 @@ // RUN: -fno-keep-inline-functions \ // RUN: -freorder-blocks \ // RUN: -fprofile-dir=/rand/dir \ -// RUN: -fprofile-use \ -// RUN: -fprofile-use=/rand/dir \ // RUN: -falign-functions \ // RUN: -falign-functions=1 \ // RUN: -ffloat-store \ @@ -312,8 +343,6 @@ // CHECK-WARNING-DAG: optimization flag '-fno-keep-inline-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported // CHECK-WARNING-DAG: optimization flag '-fprofile-dir=/rand/dir' is not supported -// CHECK-WARNING-DAG: optimization flag '-fprofile-use' is not supported -// CHECK-WARNING-DAG: optimization flag '-fprofile-use=/rand/dir' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions=1' is not supported // CHECK-WARNING-DAG: optimization flag '-ffloat-store' is not supported diff --git a/test/Driver/crash-report-modules.m b/test/Driver/crash-report-modules.m index 66ebaa750ddc..0e1d81a1f340 100644 --- a/test/Driver/crash-report-modules.m +++ b/test/Driver/crash-report-modules.m @@ -26,6 +26,8 @@ const int x = MODULE_MACRO; // CHECKSRC: const int x = 10; // CHECKSH: # Crash reproducer +// CHECKSH-NEXT: # Driver args: "-fsyntax-only" +// CHECKSH-SAME: "-D" "FOO=BAR" // CHECKSH-NEXT: # Original command: {{.*$}} // CHECKSH-NEXT: "-cc1" // CHECKSH: "-isysroot" "/tmp/" diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c index 5caad79f192b..2ff5b44f5e52 100644 --- a/test/Driver/crash-report.c +++ b/test/Driver/crash-report.c @@ -5,7 +5,7 @@ // RUN: -iprefix /the/prefix -iwithprefix /tmp -iwithprefixbefore /tmp/ \ // RUN: -Xclang -internal-isystem -Xclang /tmp/ \ // RUN: -Xclang -internal-externc-isystem -Xclang /tmp/ \ -// RUN: -DFOO=BAR 2>&1 | FileCheck %s +// RUN: -DFOO=BAR -DBAR="BAZ QUX" 2>&1 | FileCheck %s // RUN: cat %t/crash-report-*.c | FileCheck --check-prefix=CHECKSRC %s // RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s // REQUIRES: crash-recovery @@ -19,10 +19,14 @@ FOO // CHECKSRC: FOO // CHECKSH: # Crash reproducer +// CHECKSH-NEXT: # Driver args: "-fsyntax-only" +// CHECKSH-SAME: "-D" "FOO=BAR" +// CHECKSH-SAME: "-D" "BAR=BAZ QUX" // CHECKSH-NEXT: # Original command: {{.*$}} // CHECKSH-NEXT: "-cc1" // CHECKSH: "-main-file-name" "crash-report.c" // CHECKSH: "-D" "FOO=BAR" +// CHECKSH: "-D" "BAR=BAZ QUX" // CHECKSH-NOT: "-F/tmp/" // CHECKSH-NOT: "-I" "/tmp/" // CHECKSH-NOT: "-idirafter" "/tmp/" diff --git a/test/Driver/cuda-options.cu b/test/Driver/cuda-options.cu new file mode 100644 index 000000000000..90bdea4499c8 --- /dev/null +++ b/test/Driver/cuda-options.cu @@ -0,0 +1,111 @@ +// Tests CUDA compilation pipeline construction in Driver. +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: nvptx-registered-target + +// Simple compilation case: +// RUN: %clang -### -target=x86_64-linux-gnu -c %s 2>&1 \ +// Compile device-side to PTX assembly and make sure we use it on the host side. +// RUN: | FileCheck -check-prefix CUDA-D1 \ +// Then compile host side and incorporate device code. +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \ +// Make sure we don't link anything. +// RUN: -check-prefix CUDA-NL %s + +// Typical compilation + link case: +// RUN: %clang -### -target=x86_64-linux-gnu %s 2>&1 \ +// Compile device-side to PTX assembly and make sure we use it on the host side +// RUN: | FileCheck -check-prefix CUDA-D1 \ +// Then compile host side and incorporate device code. +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \ +// Then link things. +// RUN: -check-prefix CUDA-L %s + +// Verify that -cuda-no-device disables device-side compilation and linking +// RUN: %clang -### -target=x86_64-linux-gnu --cuda-host-only %s 2>&1 \ +// Make sure we didn't run device-side compilation. +// RUN: | FileCheck -check-prefix CUDA-ND \ +// Then compile host side and make sure we don't attempt to incorporate GPU code. +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-NI \ +// Make sure we don't link anything. +// RUN: -check-prefix CUDA-NL %s + +// Verify that -cuda-no-host disables host-side compilation and linking +// RUN: %clang -### -target=x86_64-linux-gnu --cuda-device-only %s 2>&1 \ +// Compile device-side to PTX assembly +// RUN: | FileCheck -check-prefix CUDA-D1 \ +// Make sure there are no host cmpilation or linking. +// RUN: -check-prefix CUDA-NH -check-prefix CUDA-NL %s + +// Verify that with -S we compile host and device sides to assembly +// and incorporate device code on the host side. +// RUN: %clang -### -target=x86_64-linux-gnu -S -c %s 2>&1 \ +// Compile device-side to PTX assembly +// RUN: | FileCheck -check-prefix CUDA-D1 \ +// Then compile host side and incorporate GPU code. +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \ +// Make sure we don't link anything. +// RUN: -check-prefix CUDA-NL %s + +// Verify that --cuda-gpu-arch option passes correct GPU +// archtecture info to device compilation. +// RUN: %clang -### -target=x86_64-linux-gnu --cuda-gpu-arch=sm_35 -c %s 2>&1 \ +// Compile device-side to PTX assembly. +// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1-SM35 \ +// Then compile host side and incorporate GPU code. +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \ +// Make sure we don't link anything. +// RUN: -check-prefix CUDA-NL %s + +// Verify that there is device-side compilation per --cuda-gpu-arch args +// and that all results are included on the host side. +// RUN: %clang -### -target=x86_64-linux-gnu --cuda-gpu-arch=sm_35 --cuda-gpu-arch=sm_30 -c %s 2>&1 \ +// Compile both device-sides to PTX assembly +// RUN: | FileCheck \ +// RUN: -check-prefix CUDA-D1 -check-prefix CUDA-D1-SM35 \ +// RUN: -check-prefix CUDA-D2 -check-prefix CUDA-D2-SM30 \ +// Then compile host side and incorporate both device-side outputs +// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 -check-prefix CUDA-H-I2 \ +// Make sure we don't link anything. +// RUN: -check-prefix CUDA-NL %s + +// Match device-side compilation +// CUDA-D1: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda" +// CUDA-D1-SAME: "-fcuda-is-device" +// CUDA-D1-SM35-SAME: "-target-cpu" "sm_35" +// CUDA-D1-SAME: "-o" "[[GPUBINARY1:[^"]*]]" +// CUDA-D1-SAME: "-x" "cuda" + +// Match anothe device-side compilation +// CUDA-D2: "-cc1" "-triple" "nvptx{{(64)?}}-nvidia-cuda" +// CUDA-D2-SAME: "-fcuda-is-device" +// CUDA-D2-SM30-SAME: "-target-cpu" "sm_30" +// CUDA-D2-SAME: "-o" "[[GPUBINARY2:[^"]*]]" +// CUDA-D2-SAME: "-x" "cuda" + +// Match no device-side compilation +// CUDA-ND-NOT: "-cc1" "-triple" "nvptx{{64?}}-nvidia-cuda" +// CUDA-ND-SAME-NOT: "-fcuda-is-device" + +// Match host-side compilation +// CUDA-H: "-cc1" "-triple" +// CUDA-H-SAME-NOT: "nvptx{{64?}}-nvidia-cuda" +// CUDA-H-SAME-NOT: "-fcuda-is-device" +// CUDA-H-SAME: "-o" "[[HOSTOBJ:[^"]*]]" +// CUDA-H-SAME: "-x" "cuda" +// CUDA-H-I1-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY1]]" +// CUDA-H-I2-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY2]]" + +// Match no GPU code inclusion. +// CUDA-H-NI-NOT: "-fcuda-include-gpubinary" + +// Match no CUDA compilation +// CUDA-NH-NOT: "-cc1" "-triple" +// CUDA-NH-SAME-NOT: "-x" "cuda" + +// Match linker +// CUDA-L: "{{.*}}{{ld|link}}{{(.exe)?}}" +// CUDA-L-SAME: "[[HOSTOBJ]]" + +// Match no linker +// CUDA-NL-NOT: "{{.*}}{{ld|link}}{{(.exe)?}}" diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c index 96d078101695..15b438332730 100644 --- a/test/Driver/fsanitize.c +++ b/test/Driver/fsanitize.c @@ -122,6 +122,9 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=3 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-3 // CHECK-TRACK-ORIGINS-3: error: invalid value '3' in '-fsanitize-memory-track-origins=3' +// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-use-after-dtor -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-USE-AFTER-DTOR +// CHECK-MSAN-USE-AFTER-DTOR: -cc1{{.*}}-fsanitize-memory-use-after-dtor + // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-0 // CHECK-ASAN-FIELD-PADDING-0-NOT: -fsanitize-address-field-padding // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-1 @@ -246,6 +249,10 @@ // RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.7 -flto -fsanitize=cfi-vcall -fno-sanitize-trap=cfi -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOTRAP-OLD-MACOS // CHECK-CFI-NOTRAP-OLD-MACOS: error: unsupported option '-fno-sanitize-trap=cfi-vcall' for target 'x86_64-apple-darwin10' +// RUN: %clang -target x86_64-pc-win32 -flto -fsanitize=cfi-vcall -fno-sanitize-trap=cfi -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOTRAP-WIN +// CHECK-CFI-NOTRAP-WIN: -emit-llvm-bc +// CHECK-CFI-NOTRAP-WIN-NOT: -fsanitize-trap=cfi + // RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL // RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL // RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL diff --git a/test/Driver/nacl-direct.c b/test/Driver/nacl-direct.c index 9768eab24dce..5fe857622320 100644 --- a/test/Driver/nacl-direct.c +++ b/test/Driver/nacl-direct.c @@ -63,6 +63,29 @@ // CHECK-ARM: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}usr{{/|\\\\}}lib" // CHECK-ARM: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}arm-nacl" // CHECK-ARM-NOT: -lpthread +// +// RUN: %clang -no-canonical-prefixes -### -o %t.o %s \ +// RUN: -target mipsel-unknown-nacl -resource-dir foo 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-MIPS %s +// CHECK-MIPS: {{.*}}clang{{.*}}" "-cc1" +// CHECK-MIPS: "-fuse-init-array" +// CHECK-MIPS: "-target-cpu" "mips32r2" +// CHECK-MIPS: "-target-abi" "o32" +// CHECK-MIPS: "-mfloat-abi" "hard" +// CHECK-MIPS: "-resource-dir" "foo" +// CHECK-MIPS: "-internal-isystem" "foo{{/|\\\\}}include" +// CHECK-MIPS: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}usr{{/|\\\\}}include" +// CHECK-MIPS: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}include" +// CHECK-MIPS-NOT: as{{(.exe)?}}" +// CHECK-MIPS: ld{{(.exe)?}}" +// CHECK-MIPS: "--build-id" +// CHECK-MIPS: "-m" "mipselelf_nacl" +// CHECK-MIPS: "-static" +// CHECK-MIPS: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}lib" +// CHECK-MIPS: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}usr{{/|\\\\}}lib" +// CHECK-MIPS: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}mipsel-nacl" +// CHECK-MIPS: "-lpnacl_legacy" +// CHECK-MIPS-NOT: "-lpthread" // Check that even when the target arch is just "arm" (as will be the case when // it is inferred from the binary name) that we get the right ABI flags @@ -109,3 +132,15 @@ // CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}include" // CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include" // CHECK-x86_64-CXX: "-lpthread" + +// RUN: %clangxx -no-canonical-prefixes -### -o %t.o %s \ +// RUN: -target mipsel-unknown-nacl -resource-dir foo 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-MIPS-CXX %s +// CHECK-MIPS-CXX: {{.*}}clang{{.*}}" "-cc1" +// CHECK-MIPS-CXX: "-resource-dir" "foo" +// CHECK-MIPS-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" +// CHECK-MIPS-CXX: "-internal-isystem" "foo{{/|\\\\}}include" +// CHECK-MIPS-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}usr{{/|\\\\}}include" +// CHECK-MIPS-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}mipsel-nacl{{/|\\\\}}include" +// CHECK-MIPS-CXX: "-lnacl" +// CHECK-MIPS-CXX: "-lpthread" diff --git a/test/Driver/ppc-abi.c b/test/Driver/ppc-abi.c index 3c7d7f136de7..958fd7741669 100644 --- a/test/Driver/ppc-abi.c +++ b/test/Driver/ppc-abi.c @@ -21,6 +21,8 @@ // RUN: -mabi=elfv1 | FileCheck -check-prefix=CHECK-ELFv1 %s // RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \ // RUN: -mabi=elfv2 | FileCheck -check-prefix=CHECK-ELFv2 %s +// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \ +// RUN: -mabi=altivec | FileCheck -check-prefix=CHECK-ELFv2 %s // CHECK-ELFv1: "-target-abi" "elfv1" // CHECK-ELFv1-QPX: "-target-abi" "elfv1-qpx" diff --git a/test/Driver/ppc-dependent-options.cpp b/test/Driver/ppc-dependent-options.cpp new file mode 100644 index 000000000000..b4dcaf6d9bf0 --- /dev/null +++ b/test/Driver/ppc-dependent-options.cpp @@ -0,0 +1,62 @@ +// REQUIRES: powerpc-registered-target +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-DEFAULT + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mno-vsx -mpower8-vector %s 2>&1 | \ +// RUN: FileCheck %s -check-prefix=CHECK-NVSX-P8V + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mno-vsx -mdirect-move %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-NVSX-DMV + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mno-vsx -mpower8-vector -mvsx %s 2>&1 | \ +// RUN: FileCheck %s -check-prefix=CHECK-DEFAULT + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mno-vsx -mdirect-move -mvsx %s 2>&1 | \ +// RUN: FileCheck %s -check-prefix=CHECK-DEFAULT + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mpower8-vector -mno-vsx %s 2>&1 | \ +// RUN: FileCheck %s -check-prefix=CHECK-NVSX-P8V + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mdirect-move -mno-vsx %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-NVSX-DMV + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power8 -std=c++11 -mno-vsx %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-NVSX + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power6 -std=c++11 %s 2>&1 | FileCheck %s -check-prefix=CHECK-NVSX + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power6 -std=c++11 -mpower8-vector %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-DEFAULT + +// RUN: not %clang -target powerpc64le-unknown-unknown -fsyntax-only \ +// RUN: -mcpu=power6 -std=c++11 -mdirect-move %s 2>&1 | FileCheck %s \ +// RUN: -check-prefix=CHECK-VSX + +#ifdef __VSX__ +static_assert(false, "VSX enabled"); +#endif + +#ifdef __POWER8_VECTOR__ +static_assert(false, "P8V enabled"); +#endif + +#if !defined(__VSX__) && !defined(__POWER8_VECTOR__) +static_assert(false, "Neither enabled"); +#endif + +// CHECK-DEFAULT: VSX enabled +// CHECK-DEFAULT: P8V enabled +// CHECK-NVSX-P8V: error: option '-mpower8-vector' cannot be specified with '-mno-vsx' +// CHECK-NVSX-DMV: error: option '-mdirect-move' cannot be specified with '-mno-vsx' +// CHECK-NVSX: Neither enabled +// CHECK-VSX: VSX enabled diff --git a/test/Driver/ppc-endian.c b/test/Driver/ppc-endian.c new file mode 100644 index 000000000000..4d8db38943b2 --- /dev/null +++ b/test/Driver/ppc-endian.c @@ -0,0 +1,9 @@ +// RUN: %clang -target powerpc64le -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-LE %s +// RUN: %clang -target powerpc64le -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-LE %s +// RUN: %clang -target powerpc64 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-LE %s +// CHECK-LE: "-cc1"{{.*}} "-triple" "powerpc64le{{.*}}" + +// RUN: %clang -target powerpc64 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE %s +// RUN: %clang -target powerpc64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE %s +// RUN: %clang -target powerpc64le -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE %s +// CHECK-BE: "-cc1"{{.*}} "-triple" "powerpc64{{.*}}" diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp index 8ef83184693b..947183c61f70 100644 --- a/test/Driver/ppc-features.cpp +++ b/test/Driver/ppc-features.cpp @@ -142,4 +142,8 @@ // RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_LE_LD_ARGS %s // CHECK_LE_LD_ARGS: "elf64lppc" - +// OpenMP features +// RUN: %clang -target powerpc-unknown-linux-gnu %s -### -fopenmp=libomp -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_OPENMP_TLS %s +// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -fopenmp=libomp -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_OPENMP_TLS %s +// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -fopenmp=libomp -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_OPENMP_TLS %s +// CHECK_OPENMP_TLS-NOT: "-fnoopenmp-use-tls" diff --git a/test/Frontend/ast-codegen.c b/test/Frontend/ast-codegen.c index b85c5dcf5085..4a3f8a3b79fd 100644 --- a/test/Frontend/ast-codegen.c +++ b/test/Frontend/ast-codegen.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: %clang -target i386-unknown-unknown -emit-ast -o %t.ast %s // RUN: %clang -target i386-unknown-unknown -emit-llvm -S -o - %t.ast | FileCheck %s diff --git a/test/Headers/xmmintrin.c b/test/Headers/xmmintrin.c index 5bf5d4a56683..39743c96b783 100644 --- a/test/Headers/xmmintrin.c +++ b/test/Headers/xmmintrin.c @@ -4,7 +4,7 @@ // RUN: %clang_cc1 %s -ffreestanding -triple x86_64-apple-macosx10.9.0 -emit-llvm -o - \ // RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -isystem %S/Inputs/include \ // RUN: | FileCheck %s - +// REQUIRES: x86-registered-target #include <xmmintrin.h> // Make sure the last step of _mm_cvtps_pi16 converts <4 x i32> to <4 x i16> by diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m index 9696a280661d..284406f6446f 100644 --- a/test/Index/TestClassForwardDecl.m +++ b/test/Index/TestClassForwardDecl.m @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -o %t.ast // RUN: c-index-test -test-file-scan %t.ast %s | FileCheck -check-prefix=CHECK-scan %s // RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=CHECK-load %s - +// REQUIRES: x86-registered-target // This test checks how the @class resolves as a cursor when the @interface is implicitly defined. // See TestClassDecl.m for the corresponding test case. (<rdar://problem/7383421>) diff --git a/test/Index/annotate-parameterized-classes.m b/test/Index/annotate-parameterized-classes.m new file mode 100644 index 000000000000..762ae2aece13 --- /dev/null +++ b/test/Index/annotate-parameterized-classes.m @@ -0,0 +1,38 @@ +@protocol NSObject +@end + +@interface NSObject +@end + +@interface A<T : id, U : NSObject *> : NSObject +@end + +@interface A<T : id, U : NSObject *> (Cat1) +@end + +typedef A<id<NSObject>, NSObject *> ASpecialization1; + +@interface B<T : id, U : NSObject *> : A<T, U> +@end + +// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s +// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14 +// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TypeRef=id:0:0 +// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22 +// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] ObjCClassRef=NSObject:4:12 + +// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s +// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14 +// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TypeRef=id:0:0 +// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22 +// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] ObjCClassRef=NSObject:4:12 + +// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s +// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0 +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:14 - 13:22] ObjCProtocolRef=NSObject:1:11 +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:25 - 13:33] ObjCClassRef=NSObject:4:12 + +// RUN: c-index-test -test-annotate-tokens=%s:15:1:16:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SUPER %s +// CHECK-SUPER: Identifier: "A" [15:40 - 15:41] ObjCSuperClassRef=A:7:12 +// CHECK-SUPER: Identifier: "T" [15:42 - 15:43] TypeRef=T:15:14 +// CHECK-SUPER: Identifier: "U" [15:45 - 15:46] TypeRef=U:15:22 diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m index 9a7e28a666bf..0a76105a94d5 100644 --- a/test/Index/annotate-tokens.m +++ b/test/Index/annotate-tokens.m @@ -152,6 +152,7 @@ static Rdar8595462_A * Rdar8595462_staticVar; @property int extensionProperty; @end +typedef id<Proto> *proto_ptr; // RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s // CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12 @@ -596,3 +597,9 @@ static Rdar8595462_A * Rdar8595462_staticVar; // CHECK-PROP: Keyword: "property" [152:4 - 152:12] ObjCPropertyDecl=extensionProperty:152:17 // CHECK-PROP: Keyword: "int" [152:13 - 152:16] ObjCPropertyDecl=extensionProperty:152:17 // CHECK-PROP: Identifier: "extensionProperty" [152:17 - 152:34] ObjCPropertyDecl=extensionProperty:152:17 + +// RUN: c-index-test -test-annotate-tokens=%s:155:1:156:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-ID-PROTO %s +// CHECK-ID-PROTO: Identifier: "id" [155:9 - 155:11] TypeRef=id:0:0 +// CHECK-ID-PROTO: Punctuation: "<" [155:11 - 155:12] TypedefDecl=proto_ptr:155:20 (Definition) +// CHECK-ID-PROTO: Identifier: "Proto" [155:12 - 155:17] ObjCProtocolRef=Proto +// CHECK-ID-PROTO: Punctuation: ">" [155:17 - 155:18] TypedefDecl=proto_ptr:155:20 (Definition) diff --git a/test/Index/attributes-cuda.cu b/test/Index/attributes-cuda.cu index 824bdb4c883f..51f4aedd198d 100644 --- a/test/Index/attributes-cuda.cu +++ b/test/Index/attributes-cuda.cu @@ -1,4 +1,6 @@ // RUN: c-index-test -test-load-source all -x cuda %s | FileCheck %s +// RUN: c-index-test -test-load-source all -x cuda --cuda-host-only %s | FileCheck %s +// RUN: c-index-test -test-load-source all -x cuda --cuda-device-only %s | FileCheck %s __attribute__((device)) void f_device(); __attribute__((global)) void f_global(); @@ -6,13 +8,13 @@ __attribute__((constant)) int* g_constant; __attribute__((shared)) float *g_shared; __attribute__((host)) void f_host(); -// CHECK: attributes-cuda.cu:3:30: FunctionDecl=f_device:3:30 -// CHECK-NEXT: attributes-cuda.cu:3:16: attribute(device) -// CHECK: attributes-cuda.cu:4:30: FunctionDecl=f_global:4:30 -// CHECK-NEXT: attributes-cuda.cu:4:16: attribute(global) -// CHECK: attributes-cuda.cu:5:32: VarDecl=g_constant:5:32 (Definition) -// CHECK-NEXT: attributes-cuda.cu:5:16: attribute(constant) -// CHECK: attributes-cuda.cu:6:32: VarDecl=g_shared:6:32 (Definition) -// CHECK-NEXT: attributes-cuda.cu:6:16: attribute(shared) -// CHECK: attributes-cuda.cu:7:28: FunctionDecl=f_host:7:28 -// CHECK-NEXT: attributes-cuda.cu:7:16: attribute(host) +// CHECK: attributes-cuda.cu:5:30: FunctionDecl=f_device:5:30 +// CHECK-NEXT: attributes-cuda.cu:5:16: attribute(device) +// CHECK: attributes-cuda.cu:6:30: FunctionDecl=f_global:6:30 +// CHECK-NEXT: attributes-cuda.cu:6:16: attribute(global) +// CHECK: attributes-cuda.cu:7:32: VarDecl=g_constant:7:32 (Definition) +// CHECK-NEXT: attributes-cuda.cu:7:16: attribute(constant) +// CHECK: attributes-cuda.cu:8:32: VarDecl=g_shared:8:32 (Definition) +// CHECK-NEXT: attributes-cuda.cu:8:16: attribute(shared) +// CHECK: attributes-cuda.cu:9:28: FunctionDecl=f_host:9:28 +// CHECK-NEXT: attributes-cuda.cu:9:16: attribute(host) diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index c75d5ac6814e..cbd742b240b5 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -o %t.ast // RUN: c-index-test -test-load-tu %t.ast all > %t 2>&1 && FileCheck --input-file=%t %s - +// REQUIRES: x86-registered-target @interface Foo { __attribute__((iboutlet)) id myoutlet; diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m index c1799026cec9..f368f1f07433 100644 --- a/test/Index/c-index-getCursor-test.m +++ b/test/Index/c-index-getCursor-test.m @@ -166,3 +166,4 @@ void f() { // CHECK: [57:1 - 57:10] FunctionDecl=f:57:6 (Definition) // CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition) // CHECK: [58:8 - 58:15] macro expansion=CONCAT:55:9 +// REQUIRES: x86-registered-target diff --git a/test/Index/comment-objc-parameterized-classes.m b/test/Index/comment-objc-parameterized-classes.m new file mode 100644 index 000000000000..5a928509dfe6 --- /dev/null +++ b/test/Index/comment-objc-parameterized-classes.m @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s > %t/out +// RUN: FileCheck %s < %t/out + +// Ensure that XML we generate is not invalid. +// RUN: FileCheck %s -check-prefix=WRONG < %t/out +// WRONG-NOT: CommentXMLInvalid + +@protocol NSObject +@end + +@interface NSObject +@end + +// CHECK: <Declaration>@interface A <__covariant T : id, U : NSObject *> : NSObject +/// A +@interface A<__covariant T : id, U : NSObject *> : NSObject +@end diff --git a/test/Index/complete-blocks.m b/test/Index/complete-blocks.m index cb507e2be34e..046a08695d08 100644 --- a/test/Index/complete-blocks.m +++ b/test/Index/complete-blocks.m @@ -42,6 +42,14 @@ void test_D(D *d) { [d method6:0]; } +@interface I1 +- method7:(int (^_Nullable)(int x, int y))b; +@end +void f2(int (^_Nullable block)(int x, int y)); +void test_f2(I1 *o) { + [o method7:0]; +} + // RUN: c-index-test -code-completion-at=%s:8:1 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder ^int(int x, int y)block}{RightParen )} (50) // CHECK-CC1: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{Placeholder ^(float f, double d)b}{RightParen )} (50) @@ -62,3 +70,7 @@ void test_D(D *d) { // RUN: c-index-test -code-completion-at=%s:42:6 %s | FileCheck -check-prefix=CHECK-CC6 %s // CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText method6:}{Placeholder ^(block_t block)arg} (35) +// RUN: c-index-test -code-completion-at=%s:50:1 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: FunctionDecl:{ResultType void}{TypedText f2}{LeftParen (}{Placeholder ^int(int x, int y)block}{RightParen )} (50) +// RUN: c-index-test -code-completion-at=%s:50:6 %s | FileCheck -check-prefix=CHECK-CC8 %s +// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType id}{TypedText method7:}{Placeholder ^int(int x, int y)b} (35) diff --git a/test/Index/complete-ctor-inits.cpp b/test/Index/complete-ctor-inits.cpp index f50621466f1e..96f36b65e3d0 100644 --- a/test/Index/complete-ctor-inits.cpp +++ b/test/Index/complete-ctor-inits.cpp @@ -17,6 +17,18 @@ struct Z : public X<int>, public Y { Z::Z() : ::X<int>(0), Virt(), b(), c() { } +struct PR23948 { + template<class size> PR23948() + : + {} + + template<class size> void invalid() + : + {} + + int a; +}; + // RUN: c-index-test -code-completion-at=%s:18:10 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: MemberRef:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (35) // CHECK-CC1: MemberRef:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (35) @@ -38,3 +50,7 @@ Z::Z() : ::X<int>(0), Virt(), b(), c() { } // CHECK-CC3: MemberRef:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (7) // CHECK-CC3-NOT: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} // CHECK-CC3: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (35) + +// RUN: c-index-test -code-completion-at=%s:22:10 -target i386-apple-darwin %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: MemberRef:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (7) +// RUN: c-index-test -code-completion-at=%s:26:10 %s diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m index 0e3780ba3d5f..e45d68f97087 100644 --- a/test/Index/complete-method-decls.m +++ b/test/Index/complete-method-decls.m @@ -90,7 +90,18 @@ typedef A *MyObjectRef; @end @implementation I2 -- +-(void)foo {} +@end + +#pragma clang assume_nonnull begin +@interface I3 +-(I3 *)produceI3:(I3 *)i3; +-(instancetype)getI3; +@end +#pragma clang assume_nonnull end + +@implementation I3 +-(void)foo {} @end // RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s @@ -208,9 +219,12 @@ typedef A *MyObjectRef; // RUN: c-index-test -code-completion-at=%s:85:2 %s | FileCheck -check-prefix=CHECK-CLASSTY %s // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text Class<P1>}{RightParen )}{TypedText meth} -// FIXME: It should be "MyObject <P1> *"" -// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text A<P1> *}{RightParen )}{TypedText meth2} +// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObject<P1> *}{RightParen )}{TypedText meth2} // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObjectRef}{RightParen )}{TypedText meth3} // RUN: c-index-test -code-completion-at=%s:93:2 %s | FileCheck -check-prefix=CHECK-NULLABILITY %s // CHECK-NULLABILITY: ObjCInstanceMethodDecl:{LeftParen (}{Text nonnull }{Text I2 *}{RightParen )}{TypedText produceI2}{TypedText :}{LeftParen (}{Text nullable }{Text I2 *}{RightParen )}{Text i2} (40) + +// RUN: c-index-test -code-completion-at=%s:104:2 %s | FileCheck -check-prefix=CHECK-NULLABILITY2 %s +// CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text nonnull }{Text instancetype}{RightParen )}{TypedText getI3} (40) +// CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text nonnull }{Text I3 *}{RightParen )}{TypedText produceI3}{TypedText :}{LeftParen (}{Text nonnull }{Text I3 *}{RightParen )}{Text i3} (40) diff --git a/test/Index/complete-parameterized-classes.m b/test/Index/complete-parameterized-classes.m new file mode 100644 index 000000000000..70d85885e3b7 --- /dev/null +++ b/test/Index/complete-parameterized-classes.m @@ -0,0 +1,79 @@ +@protocol NSObject +@end + +@interface NSObject +@end + +@interface Test<T : id, U : NSObject *> : NSObject +{ +@public + U myVar; +} +-(U)getit:(T)val; +-(void)apply:(void(^)(T, U))block; +-(void)apply2:(void(^_Nonnull)(T, U))block; + +@property (strong) T prop; +@end + +@interface MyClsA : NSObject +@end +@interface MyClsB : NSObject +@end + +void test1(Test<MyClsA*, MyClsB*> *obj) { + [obj ]; + obj.; + obj->; +} + +void test2(Test *obj) { + [obj ]; + obj.; + obj->; +} + +@implementation Test +-(id)getit:(id)val {} +@end + +void test3() { + Test<> t; + NSObject<> n; +} + +// RUN: c-index-test -code-completion-at=%s:25:8 %s | FileCheck -check-prefix=CHECK-CC0 %s +// CHECK-CC0: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply2:}{Placeholder ^(MyClsA *, MyClsB *)block} (35) +// CHECK-CC0: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply:}{Placeholder ^(MyClsA *, MyClsB *)block} (35) +// CHECK-CC0: ObjCInstanceMethodDecl:{ResultType MyClsB *}{TypedText getit:}{Placeholder (MyClsA *)} (35) + +// RUN: c-index-test -code-completion-at=%s:26:7 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: ObjCPropertyDecl:{ResultType MyClsA *}{TypedText prop} (35) + +// RUN: c-index-test -code-completion-at=%s:27:8 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: ObjCIvarDecl:{ResultType MyClsB *}{TypedText myVar} (35) + +// RUN: c-index-test -code-completion-at=%s:31:8 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply2:}{Placeholder ^(id, NSObject *)block} (35) +// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply:}{Placeholder ^(id, NSObject *)block} (35) +// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType __kindof NSObject *}{TypedText getit:}{Placeholder (id)} (35) + +// RUN: c-index-test -code-completion-at=%s:32:7 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: ObjCPropertyDecl:{ResultType id}{TypedText prop} (35) + +// RUN: c-index-test -code-completion-at=%s:33:8 %s | FileCheck -check-prefix=CHECK-CC5 %s +// CHECK-CC5: ObjCIvarDecl:{ResultType __kindof NSObject *}{TypedText myVar} (35) + +// RUN: c-index-test -code-completion-at=%s:37:2 %s | FileCheck -check-prefix=CHECK-CC6 %s +// CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText apply2}{TypedText :}{LeftParen (}{Text void (^ _Nonnull)(id, NSObject *)}{RightParen )}{Text block} (40) +// CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText apply}{TypedText :}{LeftParen (}{Text void (^)(id, NSObject *)}{RightParen )}{Text block} (40) +// CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text NSObject *}{RightParen )}{TypedText getit}{TypedText :}{LeftParen (}{Text id}{RightParen )}{Text val} (40) +// CHECK-CC6: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText prop} (40) + +// RUN: c-index-test -code-completion-at=%s:41:8 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: ObjCInterfaceDecl:{TypedText MyClsA} +// RUN: c-index-test -code-completion-at=%s:42:12 %s > %t.out +// RUN: FileCheck -input-file=%t.out -check-prefix=CHECK-CC8 %s +// RUN: FileCheck -input-file=%t.out -check-prefix=CHECK-CC9 %s +// CHECK-CC8: ObjCProtocolDecl:{TypedText NSObject} +// CHECK-CC9-NOT: ObjCInterfaceDecl:{TypedText MyClsA} diff --git a/test/Index/index-file.cu b/test/Index/index-file.cu new file mode 100644 index 000000000000..26b93f069457 --- /dev/null +++ b/test/Index/index-file.cu @@ -0,0 +1,9 @@ +// Make sure we can process CUDA file even if driver creates multiple jobs +// RUN: c-index-test -test-load-source all %s | FileCheck %s -check-prefix=CHECK-ANY +// Make sure we process correct side of cuda compilation +// RUN: c-index-test -test-load-source all --cuda-host-only %s | FileCheck %s -check-prefix=CHECK-HOST +// RUN: c-index-test -test-load-source all --cuda-device-only %s | FileCheck %s -check-prefix=CHECK-DEVICE + +// CHECK-ANY: macro definition=__cplusplus +// CHECK-HOST-NOT: macro definition=__CUDA_ARCH__ +// CHECK-DEVICE: macro definition=__CUDA_ARCH__ diff --git a/test/Index/pch-with-module.m b/test/Index/pch-with-module.m index e839c811dab6..77262d5eb6d1 100644 --- a/test/Index/pch-with-module.m +++ b/test/Index/pch-with-module.m @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: rm -rf %t.cache // RUN: c-index-test -write-pch %t.h.pch %s -target x86_64-apple-macosx10.7 -fobjc-arc -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs -Xclang -fdisable-module-hash // RUN: %clang -fsyntax-only %s -target x86_64-apple-macosx10.7 -include %t.h -fobjc-arc -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \ diff --git a/test/Index/print-mangled-name.cpp b/test/Index/print-mangled-name.cpp index b7e79c3f6d65..d4edc5ff3921 100644 --- a/test/Index/print-mangled-name.cpp +++ b/test/Index/print-mangled-name.cpp @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-pch %s -o %t_linux.ast // RUN: c-index-test -test-print-mangle %t_linux.ast | FileCheck %s --check-prefix=ITANIUM diff --git a/test/Modules/Inputs/diagnostics-aux-2.modulemap b/test/Modules/Inputs/diagnostics-aux-2.modulemap new file mode 100644 index 000000000000..8ceeb8ebdfc9 --- /dev/null +++ b/test/Modules/Inputs/diagnostics-aux-2.modulemap @@ -0,0 +1,3 @@ +module external { + blahblah +} diff --git a/test/Modules/Inputs/diagnostics-aux.modulemap b/test/Modules/Inputs/diagnostics-aux.modulemap index d067d04d3d6a..2c6ecb93aa96 100644 --- a/test/Modules/Inputs/diagnostics-aux.modulemap +++ b/test/Modules/Inputs/diagnostics-aux.modulemap @@ -1 +1,3 @@ module foo {} + +extern module external "diagnostics-aux-2.modulemap" diff --git a/test/Modules/Inputs/explicit-build-prefer-self/map b/test/Modules/Inputs/explicit-build-prefer-self/map index 26be8e690736..042b2ae5b507 100644 --- a/test/Modules/Inputs/explicit-build-prefer-self/map +++ b/test/Modules/Inputs/explicit-build-prefer-self/map @@ -1,2 +1,2 @@ -module a { header "a.h" header "x.h" } -module b { header "b.h" header "x.h" } +module a { module h { header "a.h" } module x { header "x.h" } } +module b { module h { header "b.h" } module x { header "x.h" } } diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/a.h b/test/Modules/Inputs/merge-template-pattern-visibility/a.h new file mode 100644 index 000000000000..7f9b6497e725 --- /dev/null +++ b/test/Modules/Inputs/merge-template-pattern-visibility/a.h @@ -0,0 +1,5 @@ +template<typename, typename = int> struct A; +template<typename T> struct B; + +template<typename, typename> struct A {}; +template<typename T> struct B : A<T> {}; diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/b.h b/test/Modules/Inputs/merge-template-pattern-visibility/b.h new file mode 100644 index 000000000000..5ed18e7e7c5d --- /dev/null +++ b/test/Modules/Inputs/merge-template-pattern-visibility/b.h @@ -0,0 +1,9 @@ +template<typename, typename = int> struct A; +template<typename T> struct B; + +template<typename, typename> struct A {}; +template<typename T> struct B : A<T> {}; + +inline void f() { + B<int> bi; +} diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap b/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap new file mode 100644 index 000000000000..ba97abbaa8ec --- /dev/null +++ b/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap @@ -0,0 +1,4 @@ +module X { + module A { header "a.h" } + module B { header "b.h" } +} diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index ffaa53e18e28..904c65c2dbf4 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -336,3 +336,14 @@ module ImportNameInDir { header "ImportNameInDir.h" export * } + +module RequiresWithMissingHeader { + module HeaderBefore { + header "RequiresWithMissingHeader-Missing1.h" + requires missing + } + module HeaderAfter { + requires missing + header "RequiresWithMissingHeader-Missing2.h" + } +} diff --git a/test/Modules/Inputs/multiple-include/a.h b/test/Modules/Inputs/multiple-include/a.h new file mode 100644 index 000000000000..826619085888 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/a.h @@ -0,0 +1 @@ +#include "x.h" diff --git a/test/Modules/Inputs/multiple-include/b.h b/test/Modules/Inputs/multiple-include/b.h new file mode 100644 index 000000000000..f56ab64da6b1 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/b.h @@ -0,0 +1,3 @@ +#pragma clang __debug macro C_H +#include "c.h" +inline int get() { return c; } diff --git a/test/Modules/Inputs/multiple-include/c.h b/test/Modules/Inputs/multiple-include/c.h new file mode 100644 index 000000000000..4e7d4b742dc3 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/c.h @@ -0,0 +1,4 @@ +#ifndef C_H +#define C_H +extern int c; +#endif diff --git a/test/Modules/Inputs/multiple-include/module.modulemap b/test/Modules/Inputs/multiple-include/module.modulemap new file mode 100644 index 000000000000..1228ae6cbb73 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/module.modulemap @@ -0,0 +1,2 @@ +module A { module a { header "a.h" } module b { header "b.h" } module c { header "c.h" } } +module X { module x { header "x.h" } module c { header "c.h" } } diff --git a/test/Modules/Inputs/multiple-include/x.h b/test/Modules/Inputs/multiple-include/x.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/x.h diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h index 787fe753fba9..5badf62764b6 100644 --- a/test/Modules/Inputs/namespaces-left.h +++ b/test/Modules/Inputs/namespaces-left.h @@ -71,3 +71,5 @@ namespace N12 { } Foo *getFoo(); } + +namespace Empty {} diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h index 77f54ead65ab..dd2ac33f9108 100644 --- a/test/Modules/Inputs/namespaces-right.h +++ b/test/Modules/Inputs/namespaces-right.h @@ -66,3 +66,5 @@ namespace N12 { } void consumeFoo(Foo*); } + +namespace Empty {} diff --git a/test/Modules/Inputs/namespaces-top.h b/test/Modules/Inputs/namespaces-top.h index 7bf5394f55be..006b53c8fd28 100644 --- a/test/Modules/Inputs/namespaces-top.h +++ b/test/Modules/Inputs/namespaces-top.h @@ -21,3 +21,5 @@ namespace N13 { namespace AddAndReexportBeforeImport { int S; } + +namespace Empty {} diff --git a/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h index bda0567c93a3..07dfac7ee657 100644 --- a/test/Modules/Inputs/submodules-merge-defs/defs.h +++ b/test/Modules/Inputs/submodules-merge-defs/defs.h @@ -94,3 +94,6 @@ namespace MergeFunctionTemplateSpecializations { }; using xiq = X<int>::Q<int>; } + +enum ScopedEnum : int; +enum ScopedEnum : int { a, b, c }; diff --git a/test/Modules/compiler_builtins_arm.m b/test/Modules/compiler_builtins_arm.m index ccfceaa93f88..23efa4608aa0 100644 --- a/test/Modules/compiler_builtins_arm.m +++ b/test/Modules/compiler_builtins_arm.m @@ -1,5 +1,5 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fsyntax-only -triple thumbv7-none-linux-gnueabihf -target-abi aapcs -target-cpu cortex-a8 -mfloat-abi hard -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -D__need_wint_t %s -verify // expected-no-diagnostics - +// REQUIRES: arm-registered-target @import _Builtin_intrinsics.arm.neon; diff --git a/test/Modules/dependency-gen-inferred-map.m b/test/Modules/dependency-gen-inferred-map.m index cebfeea4f40b..053a653d1748 100644 --- a/test/Modules/dependency-gen-inferred-map.m +++ b/test/Modules/dependency-gen-inferred-map.m @@ -1,5 +1,6 @@ // Test that the virtual file "__inferred_module.map" doesn't show up as dependency. +// REQUIRES: x86-registered-target // RUN: rm -rf %t-mcp // RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -dependency-file %t.d -MT %s.o -F %S/Inputs -fsyntax-only -fmodules -fimplicit-module-maps -fmodules-cache-path=%t-mcp %s // RUN: FileCheck %s < %t.d diff --git a/test/Modules/dependency-gen-pch.m b/test/Modules/dependency-gen-pch.m index 697b42947afa..4da054ff7dc8 100644 --- a/test/Modules/dependency-gen-pch.m +++ b/test/Modules/dependency-gen-pch.m @@ -1,5 +1,6 @@ // RUN: rm -rf %t-mcp // RUN: mkdir -p %t-mcp +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -module-file-deps -dependency-file %t.d -MT %s.o -I %S/Inputs -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t-mcp -emit-pch -o %t.pch %s // RUN: FileCheck %s < %t.d diff --git a/test/Modules/diagnostics.modulemap b/test/Modules/diagnostics.modulemap index aef094d3bf64..3b5b6a5c0396 100644 --- a/test/Modules/diagnostics.modulemap +++ b/test/Modules/diagnostics.modulemap @@ -1,5 +1,8 @@ // RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/diagnostics-aux.modulemap -fmodule-map-file=%s -fsyntax-only -x c++ /dev/null 2>&1 | FileCheck %s +// CHECK: In file included from {{.*}}diagnostics-aux.modulemap:3: +// CHECK: diagnostics-aux-2.modulemap:2:3: error: expected + // PR22299: Ensure we can produce diagnostics for duplicate modules from -fmodule-map-file=. // // CHECK: diagnostics.modulemap:[[@LINE+2]]:8: error: redefinition of module 'foo' diff --git a/test/Modules/irgen.c b/test/Modules/irgen.c index f09cc7b5388f..b2eb8b5ce09a 100644 --- a/test/Modules/irgen.c +++ b/test/Modules/irgen.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: rm -rf %t // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=irgen -triple x86_64-apple-darwin10 %S/Inputs/module.map // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s diff --git a/test/Modules/linkage-merge.m b/test/Modules/linkage-merge.m index 955eb1aa95ea..e7b9e5cec136 100644 --- a/test/Modules/linkage-merge.m +++ b/test/Modules/linkage-merge.m @@ -16,8 +16,8 @@ static int f2(float); // okay: considered distinct extern int f3(float); // okay: considered distinct extern float v0; -// expected-error@-1{{redefinition of 'v0' with a different type: 'float' vs 'int'}} -// expected-note@Inputs/linkage-merge-sub.h:6{{previous definition is here}} +// expected-error@-1{{redeclaration of 'v0' with a different type: 'float' vs 'int'}} +// expected-note@Inputs/linkage-merge-sub.h:6{{previous declaration is here}} static float v1; static float v2; diff --git a/test/Modules/merge-target-features.cpp b/test/Modules/merge-target-features.cpp index 8b82c8a9789b..938715dd6b11 100644 --- a/test/Modules/merge-target-features.cpp +++ b/test/Modules/merge-target-features.cpp @@ -1,6 +1,6 @@ // RUN: rm -rf %t // RUN: cd %S -// +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -fmodules -x c++ -fmodules-cache-path=%t \ // RUN: -iquote Inputs/merge-target-features \ // RUN: -fno-implicit-modules \ diff --git a/test/Modules/merge-template-pattern-visibility.cpp b/test/Modules/merge-template-pattern-visibility.cpp new file mode 100644 index 000000000000..db759b5a46a1 --- /dev/null +++ b/test/Modules/merge-template-pattern-visibility.cpp @@ -0,0 +1,4 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fno-modules-error-recovery \ +// RUN: -fmodule-name=X -emit-module %S/Inputs/merge-template-pattern-visibility/module.modulemap -x c++ \ +// RUN: -fmodules-local-submodule-visibility diff --git a/test/Modules/multiple-include.cpp b/test/Modules/multiple-include.cpp new file mode 100644 index 000000000000..7cbeefc81782 --- /dev/null +++ b/test/Modules/multiple-include.cpp @@ -0,0 +1,5 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -I%S/Inputs/multiple-include -fmodules-cache-path=%t -fimplicit-module-maps -verify %s -fmodules-local-submodule-visibility +// expected-no-diagnostics +#include "b.h" +int c = get(); diff --git a/test/Modules/pch_container.m b/test/Modules/pch_container.m new file mode 100644 index 000000000000..095245bdc3a4 --- /dev/null +++ b/test/Modules/pch_container.m @@ -0,0 +1,17 @@ +@import DependsOnModule; +// REQUIRES: x86-registered-target +// RUN: rm -rf %t-MachO %t-ELF %t-ELF_SPLIT %t-COFF +// RUN: %clang_cc1 -triple=x86_64-apple-darwin -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t-MachO -F %S/Inputs %s +// RUN: %clang_cc1 -triple=x86_64-linux-elf -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t-ELF -F %S/Inputs %s +// RUN: %clang_cc1 -triple=x86_64-windows-coff -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t-COFF -F %S/Inputs %s + +// RUN: llvm-objdump -section-headers %t-MachO/DependsOnModule.pcm %t-ELF/DependsOnModule.pcm %t-COFF/DependsOnModule.pcm | FileCheck %s +// CHECK: file format Mach-O 64-bit x86-64 +// CHECK: __clangast {{[0-9a-f]+}} {{[0-9a-f]+}} DATA +// CHECK: file format ELF64-x86-64 +// CHECK: __clangast {{[0-9a-f]+}} {{[0-9a-f]+}} DATA +// CHECK: file format COFF-x86-64 +// CHECK: clangast {{[0-9a-f]+}} {{[0-9a-f]+}} + + +// RUN: %clang_cc1 -split-dwarf-file t-split.dwo -triple=x86_64-linux-elf -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t-ELF_SPLIT -F %S/Inputs %s -o %t-split.o diff --git a/test/Modules/requires.m b/test/Modules/requires.m index 155c6aec5dc4..1a013727108b 100644 --- a/test/Modules/requires.m +++ b/test/Modules/requires.m @@ -6,3 +6,7 @@ @import DependsOnModule.NotObjC; // expected-error{{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}} @import DependsOnModule.CustomReq1; // OK @import DependsOnModule.CustomReq2; // expected-error{{module 'DependsOnModule.CustomReq2' requires feature 'custom_req2'}} + +@import RequiresWithMissingHeader; // OK +@import RequiresWithMissingHeader.HeaderBefore; // expected-error{{module 'RequiresWithMissingHeader.HeaderBefore' requires feature 'missing'}} +@import RequiresWithMissingHeader.HeaderAfter; // expected-error{{module 'RequiresWithMissingHeader.HeaderAfter' requires feature 'missing'}} diff --git a/test/Modules/self-import-header.m b/test/Modules/self-import-header.m index 9b4bd5dee520..83e5c0104d25 100644 --- a/test/Modules/self-import-header.m +++ b/test/Modules/self-import-header.m @@ -1,5 +1,5 @@ // rdar://13840148 - +// REQUIRES: x86-registered-target // RUN: rm -rf %t // RUN: %clang -fsyntax-only -isysroot %S/Inputs/System/usr/include -fmodules -fmodules-cache-path=%t \ // RUN: -target x86_64-darwin \ diff --git a/test/Modules/signal.m b/test/Modules/signal.m index 30059e935113..37a35506447d 100644 --- a/test/Modules/signal.m +++ b/test/Modules/signal.m @@ -1,4 +1,4 @@ -// REQUIRES: shell +// REQUIRES: crash-recovery,shell // RUN: rm -rf %t // Crash building module. diff --git a/test/Modules/submodules-merge-defs.cpp b/test/Modules/submodules-merge-defs.cpp index 92c784440b9e..016b8a8f47a7 100644 --- a/test/Modules/submodules-merge-defs.cpp +++ b/test/Modules/submodules-merge-defs.cpp @@ -69,6 +69,11 @@ J<> pre_j; // expected-error {{declaration of 'J' must be imported}} #endif // expected-note@defs.h:51 +{{here}} +ScopedEnum pre_scopedenum; // expected-error {{must be imported}} expected-error {{must use 'enum'}} +// expected-note@defs.h:99 {{here}} +enum ScopedEnum : int; +ScopedEnum pre_scopedenum_declared; // ok + // Make definitions from second module visible. #ifdef TEXTUAL #include "import-and-redefine.h" diff --git a/test/Modules/templates-2.mm b/test/Modules/templates-2.mm index 78d203ab42b4..9385119679cf 100644 --- a/test/Modules/templates-2.mm +++ b/test/Modules/templates-2.mm @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target @import templates_top; struct TestEmitDefaultedSpecialMembers { diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm index 503f4bb459e0..4c6e4723a3bb 100644 --- a/test/Modules/templates.mm +++ b/test/Modules/templates.mm @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target @import templates_left; void testInlineRedeclEarly() { diff --git a/test/Modules/va_list.m b/test/Modules/va_list.m index d13b39b48f4a..aa140fb45cd4 100644 --- a/test/Modules/va_list.m +++ b/test/Modules/va_list.m @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: rm -rf %t // RUN: %clang_cc1 -triple x86_64-apple-macosx10 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ // RUN: -fmodules-ignore-macro=PREFIX -DPREFIX -I %S/Inputs/va_list \ diff --git a/test/OpenMP/atomic_capture_codegen.cpp b/test/OpenMP/atomic_capture_codegen.cpp index 12f2f3ac4e81..6dd9f7ab2a41 100644 --- a/test/OpenMP/atomic_capture_codegen.cpp +++ b/test/OpenMP/atomic_capture_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/atomic_read_codegen.c b/test/OpenMP/atomic_read_codegen.c index efeec0302d34..fc47c82d8913 100644 --- a/test/OpenMP/atomic_read_codegen.c +++ b/test/OpenMP/atomic_read_codegen.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/atomic_update_codegen.cpp b/test/OpenMP/atomic_update_codegen.cpp index b619a07200dc..df8b538ee165 100644 --- a/test/OpenMP/atomic_update_codegen.cpp +++ b/test/OpenMP/atomic_update_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/atomic_write_codegen.c b/test/OpenMP/atomic_write_codegen.c index 0016dc86c36a..1ee26b078212 100644 --- a/test/OpenMP/atomic_write_codegen.c +++ b/test/OpenMP/atomic_write_codegen.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/barrier_codegen.cpp b/test/OpenMP/barrier_codegen.cpp index 9e393ac83360..398b96f44e8a 100644 --- a/test/OpenMP/barrier_codegen.cpp +++ b/test/OpenMP/barrier_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/cancel_codegen.cpp b/test/OpenMP/cancel_codegen.cpp new file mode 100644 index 000000000000..4bd85a22b1d9 --- /dev/null +++ b/test/OpenMP/cancel_codegen.cpp @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin13.4.0 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics +// REQUIRES: x86-registered-target +#ifndef HEADER +#define HEADER + +int main (int argc, char **argv) { +// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( +#pragma omp parallel +{ +#pragma omp cancel parallel + argv[0][0] = argc; +} +// CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( +#pragma omp sections +{ +#pragma omp cancel sections +} +// CHECK: call i32 @__kmpc_single( +// CHECK-NOT: @__kmpc_cancel +// CHECK: call void @__kmpc_end_single( +// CHECK: call void @__kmpc_barrier(%ident_t* +#pragma omp sections +{ +#pragma omp cancel sections +#pragma omp section + { +#pragma omp cancel sections + } +} +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] +// CHECK: [[EXIT]] +// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* +// CHECK: br label +// CHECK: [[CONTINUE]] +// CHECK: br label +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] +// CHECK: [[EXIT]] +// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* +// CHECK: br label +// CHECK: [[CONTINUE]] +// CHECK: br label +// CHECK: call void @__kmpc_for_static_fini( +#pragma omp for +for (int i = 0; i < argc; ++i) { +#pragma omp cancel for +} +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 2) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] +// CHECK: [[EXIT]] +// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* +// CHECK: br label +// CHECK: [[CONTINUE]] +// CHECK: br label +// CHECK: call void @__kmpc_for_static_fini( +// CHECK: call void @__kmpc_barrier(%ident_t* +#pragma omp task +{ +#pragma omp cancel taskgroup +} +// CHECK: call i8* @__kmpc_omp_task_alloc( +// CHECK: call i32 @__kmpc_omp_task( + return argc; +} + +// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}, +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], +// CHECK: [[EXIT]] +// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* +// CHECK: br label %[[RETURN:.+]] +// CHECK: [[RETURN]] +// CHECK: ret void + +// CHECK: define internal i32 @{{[^(]+}}(i32 +// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 4) +// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 +// CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], +// CHECK: [[EXIT]] +// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* +// CHECK: br label %[[RETURN:.+]] +// CHECK: [[RETURN]] +// CHECK: ret i32 0 + +#endif diff --git a/test/OpenMP/cancellation_point_codegen.cpp b/test/OpenMP/cancellation_point_codegen.cpp index 47903c1f3277..453393082ce8 100644 --- a/test/OpenMP/cancellation_point_codegen.cpp +++ b/test/OpenMP/cancellation_point_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin13.4.0 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp index 26f5edb38038..5cf3446d9f5f 100644 --- a/test/OpenMP/critical_codegen.cpp +++ b/test/OpenMP/critical_codegen.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/flush_codegen.cpp b/test/OpenMP/flush_codegen.cpp index 4ebdf522c28c..cd411cea4573 100644 --- a/test/OpenMP/flush_codegen.cpp +++ b/test/OpenMP/flush_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/for_codegen.cpp b/test/OpenMP/for_codegen.cpp index 30cf484f87a8..082a0d4d8841 100644 --- a/test/OpenMP/for_codegen.cpp +++ b/test/OpenMP/for_codegen.cpp @@ -4,9 +4,9 @@ // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER - // CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* } // CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8* // CHECK-DAG: [[I:@.+]] = global i8 1, diff --git a/test/OpenMP/for_firstprivate_codegen.cpp b/test/OpenMP/for_firstprivate_codegen.cpp index 1ef38661a46f..0d5f83ed4ec3 100644 --- a/test/OpenMP/for_firstprivate_codegen.cpp +++ b/test/OpenMP/for_firstprivate_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -85,7 +86,7 @@ int main() { // LAMBDA: call void @__kmpc_barrier( g = 1; // LAMBDA: call void @__kmpc_for_static_init_4( - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -98,7 +99,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -126,7 +127,7 @@ int main() { // BLOCKS: call void @__kmpc_barrier( g = 1; // BLOCKS: call void @__kmpc_for_static_init_4( - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -137,7 +138,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp index 90c40dde2e9a..880637ea8b94 100644 --- a/test/OpenMP/for_lastprivate_codegen.cpp +++ b/test/OpenMP/for_lastprivate_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -74,7 +75,7 @@ int main() { // LAMBDA: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}} // LAMBDA: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] // LAMBDA: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1) - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -100,7 +101,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -126,7 +127,7 @@ int main() { // BLOCKS: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}} // BLOCKS: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] // BLOCKS: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1) - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -151,7 +152,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/for_private_codegen.cpp b/test/OpenMP/for_private_codegen.cpp index 8172912d04ee..ed6d87bcbae0 100644 --- a/test/OpenMP/for_private_codegen.cpp +++ b/test/OpenMP/for_private_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -55,7 +56,7 @@ int main() { // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4( - // LAMBDA: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -67,7 +68,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] }(); } }(); @@ -87,7 +88,7 @@ int main() { // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // BLOCKS: call {{.*}}void @__kmpc_for_static_init_4( - // BLOCKS: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // BLOCKS: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: double* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -97,7 +98,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp index 6763686dd0fc..7de8dff31c4c 100644 --- a/test/OpenMP/for_reduction_codegen.cpp +++ b/test/OpenMP/for_reduction_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -71,7 +72,7 @@ int main() { // LAMBDA: store double 0.0{{.+}}, double* [[G_PRIVATE_ADDR]] // LAMBDA: call void @__kmpc_for_static_init_4( g = 1; - // LAMBDA: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -106,7 +107,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] }(); } }(); @@ -130,7 +131,7 @@ int main() { // BLOCKS: store double 0.0{{.+}}, double* [[G_PRIVATE_ADDR]] g = 1; // BLOCKS: call void @__kmpc_for_static_init_4( - // BLOCKS: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // BLOCKS: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: double* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -163,7 +164,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/for_simd_codegen.cpp b/test/OpenMP/for_simd_codegen.cpp index 936119201695..a5644013868c 100644 --- a/test/OpenMP/for_simd_codegen.cpp +++ b/test/OpenMP/for_simd_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG -// +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/master_codegen.cpp b/test/OpenMP/master_codegen.cpp index e6ea21a5cb7b..c364c5278baf 100644 --- a/test/OpenMP/master_codegen.cpp +++ b/test/OpenMP/master_codegen.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/ordered_codegen.cpp b/test/OpenMP/ordered_codegen.cpp index 768462387a95..ff8a8047cae4 100644 --- a/test/OpenMP/ordered_codegen.cpp +++ b/test/OpenMP/ordered_codegen.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp index 907d1351356c..6486e44a9dac 100644 --- a/test/OpenMP/parallel_codegen.cpp +++ b/test/OpenMP/parallel_codegen.cpp @@ -2,9 +2,9 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER - // CHECK-DAG: %ident_t = type { i32, i32, i32, i32, i8* } // CHECK-DAG: %struct.anon = type { i32* } // CHECK-DAG: %struct.anon.0 = type { i8*** } diff --git a/test/OpenMP/parallel_copyin_codegen.cpp b/test/OpenMP/parallel_copyin_codegen.cpp index dd0a9b621fca..281d82ce9705 100644 --- a/test/OpenMP/parallel_copyin_codegen.cpp +++ b/test/OpenMP/parallel_copyin_codegen.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s // expected-no-diagnostics #ifndef ARRAY #ifndef HEADER diff --git a/test/OpenMP/parallel_firstprivate_codegen.cpp b/test/OpenMP/parallel_firstprivate_codegen.cpp index 760b96171abc..6e0f014f4d9e 100644 --- a/test/OpenMP/parallel_firstprivate_codegen.cpp +++ b/test/OpenMP/parallel_firstprivate_codegen.cpp @@ -75,7 +75,7 @@ int main() { // LAMBDA: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // LAMBDA: call {{.*}}i32 @__kmpc_cancel_barrier( g = 1; - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -86,7 +86,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -113,7 +113,7 @@ int main() { // BLOCKS: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS: call {{.*}}i32 @__kmpc_cancel_barrier( g = 1; - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -122,7 +122,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/parallel_for_codegen.cpp b/test/OpenMP/parallel_for_codegen.cpp index 2a387d9dc376..9fda8404c6e7 100644 --- a/test/OpenMP/parallel_for_codegen.cpp +++ b/test/OpenMP/parallel_for_codegen.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -O1 -fopenmp -emit-llvm %s -o - | FileCheck %s --check-prefix=CLEANUP -// +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/parallel_for_simd_codegen.cpp b/test/OpenMP/parallel_for_simd_codegen.cpp index adde4242014f..eb1e493230e3 100644 --- a/test/OpenMP/parallel_for_simd_codegen.cpp +++ b/test/OpenMP/parallel_for_simd_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG -// +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/parallel_private_codegen.cpp b/test/OpenMP/parallel_private_codegen.cpp index 55f25c67f063..d2d02a7c3d37 100644 --- a/test/OpenMP/parallel_private_codegen.cpp +++ b/test/OpenMP/parallel_private_codegen.cpp @@ -4,9 +4,9 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER - template <class T> struct S { T f; @@ -53,7 +53,7 @@ int main() { // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -64,7 +64,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -84,7 +84,7 @@ int main() { // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -93,7 +93,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/parallel_reduction_codegen.cpp b/test/OpenMP/parallel_reduction_codegen.cpp index 9ce16e919290..04d19ebea8c5 100644 --- a/test/OpenMP/parallel_reduction_codegen.cpp +++ b/test/OpenMP/parallel_reduction_codegen.cpp @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -68,7 +69,7 @@ int main() { // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]] // LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]] g = 1; - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -100,7 +101,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -129,7 +130,7 @@ int main() { // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]] // BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]] g = 1; - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -159,7 +160,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/parallel_sections_codegen.cpp b/test/OpenMP/parallel_sections_codegen.cpp index ba1bf6cc56a0..2e9e1f95aec5 100644 --- a/test/OpenMP/parallel_sections_codegen.cpp +++ b/test/OpenMP/parallel_sections_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER // CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8* diff --git a/test/OpenMP/sections_codegen.cpp b/test/OpenMP/sections_codegen.cpp index d25230a79907..2c257e83ae30 100644 --- a/test/OpenMP/sections_codegen.cpp +++ b/test/OpenMP/sections_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER // CHECK: [[IMPLICIT_BARRIER_SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8* diff --git a/test/OpenMP/sections_firstprivate_codegen.cpp b/test/OpenMP/sections_firstprivate_codegen.cpp index 4ec16ba02d9b..af9c1fe5fbda 100644 --- a/test/OpenMP/sections_firstprivate_codegen.cpp +++ b/test/OpenMP/sections_firstprivate_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -87,7 +88,7 @@ int main() { // LAMBDA: call void @__kmpc_barrier( g = 1; // LAMBDA: call void @__kmpc_for_static_init_4( - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -101,7 +102,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -129,7 +130,7 @@ int main() { // BLOCKS: call void @__kmpc_barrier( g = 1; // BLOCKS: call void @__kmpc_for_static_init_4( - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -141,7 +142,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/sections_lastprivate_codegen.cpp b/test/OpenMP/sections_lastprivate_codegen.cpp index b57f0b05c0c2..c2f68aa0fe7d 100644 --- a/test/OpenMP/sections_lastprivate_codegen.cpp +++ b/test/OpenMP/sections_lastprivate_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -73,7 +74,7 @@ int main() { // LAMBDA: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}} // LAMBDA: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] // LAMBDA: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1) - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -100,7 +101,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -126,7 +127,7 @@ int main() { // BLOCKS: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}} // BLOCKS: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]] // BLOCKS: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1) - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -151,7 +152,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/sections_private_codegen.cpp b/test/OpenMP/sections_private_codegen.cpp index 90331cbd43a9..9b579a2aa661 100644 --- a/test/OpenMP/sections_private_codegen.cpp +++ b/test/OpenMP/sections_private_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -55,7 +56,7 @@ int main() { // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4( - // LAMBDA: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -68,7 +69,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] }(); } }(); @@ -88,7 +89,7 @@ int main() { // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // BLOCKS: call {{.*}}void @__kmpc_for_static_init_4( - // BLOCKS: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // BLOCKS: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: double* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -99,7 +100,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/sections_reduction_codegen.cpp b/test/OpenMP/sections_reduction_codegen.cpp index a50f04983d4a..4d404dbcc6d1 100644 --- a/test/OpenMP/sections_reduction_codegen.cpp +++ b/test/OpenMP/sections_reduction_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -67,7 +68,7 @@ int main() { // LAMBDA: store double 0.0{{.+}}, double* [[G_PRIVATE_ADDR]] // LAMBDA: call void @__kmpc_for_static_init_4( g = 1; - // LAMBDA: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -103,7 +104,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] }(); } }(); @@ -127,7 +128,7 @@ int main() { // BLOCKS: store double 0.0{{.+}}, double* [[G_PRIVATE_ADDR]] g = 1; // BLOCKS: call void @__kmpc_for_static_init_4( - // BLOCKS: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // BLOCKS: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: double* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -161,7 +162,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/simd_codegen.cpp b/test/OpenMP/simd_codegen.cpp index ae649d8359a8..e67ad5d4c7e0 100644 --- a/test/OpenMP/simd_codegen.cpp +++ b/test/OpenMP/simd_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG -// +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/single_codegen.cpp b/test/OpenMP/single_codegen.cpp index d81739ed9163..327f6fafa834 100644 --- a/test/OpenMP/single_codegen.cpp +++ b/test/OpenMP/single_codegen.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s -// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fnoopenmp-use-tls -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef ARRAY #ifndef HEADER #define HEADER diff --git a/test/OpenMP/single_firstprivate_codegen.cpp b/test/OpenMP/single_firstprivate_codegen.cpp index 059108b37659..01eaea318119 100644 --- a/test/OpenMP/single_firstprivate_codegen.cpp +++ b/test/OpenMP/single_firstprivate_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -79,7 +80,7 @@ int main() { // LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G]] // LAMBDA: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] g = 1; - // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -92,7 +93,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]] - // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] }(); } }(); @@ -113,7 +114,7 @@ int main() { // BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G]] // BLOCKS: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] g = 1; - // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -124,7 +125,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS: store i{{[0-9]+}} 2, i{{[0-9]+}}* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/single_private_codegen.cpp b/test/OpenMP/single_private_codegen.cpp index a7fb2ed54937..e228b1b14887 100644 --- a/test/OpenMP/single_private_codegen.cpp +++ b/test/OpenMP/single_private_codegen.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER @@ -54,7 +55,7 @@ int main() { // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // LAMBDA: call {{.*}}i32 @__kmpc_single( - // LAMBDA: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]] // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) @@ -66,7 +67,7 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] }(); } }(); @@ -86,7 +87,7 @@ int main() { // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], g = 1; // BLOCKS: call {{.*}}i32 @__kmpc_single( - // BLOCKS: store volatile double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], + // BLOCKS: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]], // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: double* [[G_PRIVATE_ADDR]] // BLOCKS-NOT: [[G]]{{[[^:word:]]}} @@ -96,7 +97,7 @@ int main() { // BLOCKS: define {{.+}} void {{@.+}}(i8* g = 2; // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret }(); diff --git a/test/OpenMP/task_codegen.cpp b/test/OpenMP/task_codegen.cpp index cce0a13bc2e4..139ac505a9f6 100644 --- a/test/OpenMP/task_codegen.cpp +++ b/test/OpenMP/task_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/task_firstprivate_codegen.cpp b/test/OpenMP/task_firstprivate_codegen.cpp index e1358d9ecc6a..89aadbeb6a3f 100644 --- a/test/OpenMP/task_firstprivate_codegen.cpp +++ b/test/OpenMP/task_firstprivate_codegen.cpp @@ -5,7 +5,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target // It doesn't pass on win32. // REQUIRES: shell #ifndef ARRAY @@ -72,12 +72,12 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] // LAMBDA: store double* %{{.+}}, double** %{{.+}}, // LAMBDA: define internal i32 [[TASK_ENTRY]](i32, %{{.+}}*) g = 1; - // LAMBDA: store volatile double 1.0{{.+}}, double* %{{.+}}, + // LAMBDA: store double 1.0{{.+}}, double* %{{.+}}, // LAMBDA: call void [[INNER_LAMBDA]](% // LAMBDA: ret [&]() { @@ -105,14 +105,14 @@ int main() { { // BLOCKS: define {{.+}} void {{@.+}}(i8* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret // BLOCKS: store double* %{{.+}}, double** %{{.+}}, // BLOCKS: define internal i32 [[TASK_ENTRY]](i32, %{{.+}}*) g = 1; - // BLOCKS: store volatile double 1.0{{.+}}, double* %{{.+}}, + // BLOCKS: store double 1.0{{.+}}, double* %{{.+}}, // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: call void {{%.+}}(i8 ^{ diff --git a/test/OpenMP/task_if_codegen.cpp b/test/OpenMP/task_if_codegen.cpp index be9b47b79a41..d08c27f5a408 100644 --- a/test/OpenMP/task_if_codegen.cpp +++ b/test/OpenMP/task_if_codegen.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK %s +// REQUIRES: x86-registered-target // expected-no-diagnostics #ifndef HEADER #define HEADER diff --git a/test/OpenMP/task_private_codegen.cpp b/test/OpenMP/task_private_codegen.cpp index 463913f926a4..b29d0d39a1e2 100644 --- a/test/OpenMP/task_private_codegen.cpp +++ b/test/OpenMP/task_private_codegen.cpp @@ -5,7 +5,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target // It doesn't pass on win32. Investigating. // REQUIRES: shell @@ -67,11 +67,11 @@ int main() { // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]] // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]] - // LAMBDA: store volatile double 2.0{{.+}}, double* [[G_REF]] + // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]] // LAMBDA: define internal i32 [[TASK_ENTRY]](i32, %{{.+}}*) g = 1; - // LAMBDA: store volatile double 1.0{{.+}}, double* %{{.+}}, + // LAMBDA: store double 1.0{{.+}}, double* %{{.+}}, // LAMBDA: call void [[INNER_LAMBDA]](% // LAMBDA: ret [&]() { @@ -95,13 +95,13 @@ int main() { { // BLOCKS: define {{.+}} void {{@.+}}(i8* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} - // BLOCKS: store volatile double 2.0{{.+}}, double* + // BLOCKS: store double 2.0{{.+}}, double* // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: ret // BLOCKS: define internal i32 [[TASK_ENTRY]](i32, %{{.+}}*) g = 1; - // BLOCKS: store volatile double 1.0{{.+}}, double* %{{.+}}, + // BLOCKS: store double 1.0{{.+}}, double* %{{.+}}, // BLOCKS-NOT: [[G]]{{[[^:word:]]}} // BLOCKS: call void {{%.+}}(i8 ^{ diff --git a/test/OpenMP/taskgroup_codegen.cpp b/test/OpenMP/taskgroup_codegen.cpp index eb45f3187fa5..c04e4c723b8d 100644 --- a/test/OpenMP/taskgroup_codegen.cpp +++ b/test/OpenMP/taskgroup_codegen.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/taskwait_codegen.cpp b/test/OpenMP/taskwait_codegen.cpp index 85f20e80561f..7521709f01b6 100644 --- a/test/OpenMP/taskwait_codegen.cpp +++ b/test/OpenMP/taskwait_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/taskyield_codegen.cpp b/test/OpenMP/taskyield_codegen.cpp index 6815a0348e1c..759709c33d22 100644 --- a/test/OpenMP/taskyield_codegen.cpp +++ b/test/OpenMP/taskyield_codegen.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s // expected-no-diagnostics - +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp index be2a79c52cbc..2d876c1909fa 100644 --- a/test/OpenMP/threadprivate_ast_print.cpp +++ b/test/OpenMP/threadprivate_ast_print.cpp @@ -1,7 +1,11 @@ -// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s -// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-apple-darwin10.6.0 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10.6.0 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -triple x86_64-apple-darwin10.6.0 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-unknown-linux-gnu -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -triple x86_64-unknown-linux-gnu -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp index eea49443f8c9..7176e0499273 100644 --- a/test/OpenMP/threadprivate_codegen.cpp +++ b/test/OpenMP/threadprivate_codegen.cpp @@ -1,7 +1,13 @@ -// RUN: %clang_cc1 -verify -fopenmp -DBODY -triple x86_64-unknown-unknown -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -DBODY -triple x86_64-unknown-unknown -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -DBODY -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s + +// RUN: %clang_cc1 -verify -fopenmp -DBODY -triple x86_64-unknown-unknown -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefix=CHECK-TLS // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -DBODY -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s +// RUN: %clang_cc1 -fopenmp -DBODY -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-TLS %s + // expected-no-diagnostics +// REQUIRES: x86-registered-target #ifndef HEADER #define HEADER // CHECK-DAG: [[IDENT:%.+]] = type { i32, i32, i32, i32, i8* } @@ -18,6 +24,12 @@ // CHECK-DEBUG-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] } // CHECK-DEBUG-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] } // CHECK-DEBUG-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double } +// CHECK-TLS-DAG: [[S1:%.+]] = type { [[INT:i[0-9]+]] } +// CHECK-TLS-DAG: [[S2:%.+]] = type { [[INT]], double } +// CHECK-TLS-DAG: [[S3:%.+]] = type { [[INT]], float } +// CHECK-TLS-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] } +// CHECK-TLS-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] } +// CHECK-TLS-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double } struct S1 { int a; @@ -132,26 +144,44 @@ struct S5 { // CHECK-DEBUG-DAG: [[ST_INT_ST:@.+]] = linkonce_odr global i32 23 // CHECK-DEBUG-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01 // CHECK-DEBUG-DAG: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer -// CHECK-DEBUG-DAG: [[LOC1:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;162;9;;\00" -// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;217;9;;\00" -// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;304;19;;\00" -// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;329;9;;\00" -// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;342;9;;\00" -// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;359;10;;\00" -// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;376;10;;\00" -// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;402;10;;\00" -// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;423;10;;\00" -// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;438;10;;\00" -// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;455;27;;\00" -// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;472;10;;\00" -// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;551;9;;\00" -// CHECK-DEBUG-DAG: [[LOC14:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;568;10;;\00" -// CHECK-DEBUG-DAG: [[LOC15:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;594;10;;\00" -// CHECK-DEBUG-DAG: [[LOC16:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;615;10;;\00" -// CHECK-DEBUG-DAG: [[LOC17:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;630;10;;\00" -// CHECK-DEBUG-DAG: [[LOC18:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;647;27;;\00" -// CHECK-DEBUG-DAG: [[LOC19:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;664;10;;\00" -// CHECK-DEBUG-DAG: [[LOC20:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;276;9;;\00" +// CHECK-DEBUG-DAG: [[LOC1:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;192;9;;\00" +// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;247;9;;\00" +// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;334;19;;\00" +// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;371;9;;\00" +// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;388;9;;\00" +// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;410;10;;\00" +// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;433;10;;\00" +// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;469;10;;\00" +// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;498;10;;\00" +// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;518;10;;\00" +// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;541;27;;\00" +// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;564;10;;\00" +// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;684;9;;\00" +// CHECK-DEBUG-DAG: [[LOC14:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;707;10;;\00" +// CHECK-DEBUG-DAG: [[LOC15:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;743;10;;\00" +// CHECK-DEBUG-DAG: [[LOC16:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;772;10;;\00" +// CHECK-DEBUG-DAG: [[LOC17:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;792;10;;\00" +// CHECK-DEBUG-DAG: [[LOC18:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;815;27;;\00" +// CHECK-DEBUG-DAG: [[LOC19:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;838;10;;\00" +// CHECK-DEBUG-DAG: [[LOC20:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;306;9;;\00" +// CHECK-TLS-DAG: [[GS1:@.+]] = internal thread_local global [[S1]] zeroinitializer +// CHECK-TLS-DAG: [[GS2:@.+]] = internal global [[S2]] zeroinitializer +// CHECK-TLS-DAG: [[ARR_X:@.+]] = thread_local global [2 x [3 x [[S1]]]] zeroinitializer +// CHECK-TLS-DAG: [[SM:@.+]] = internal thread_local global [[SMAIN]] zeroinitializer +// CHECK-TLS-DAG: [[SM_GUARD:@_ZGVZ4mainE2sm]] = internal thread_local global i8 0 +// CHECK-TLS-DAG: [[STATIC_S:@.+]] = external thread_local global [[S3]] +// CHECK-TLS-DAG: [[GS3:@.+]] = external thread_local global [[S5]] +// CHECK-TLS-DAG: [[ST_INT_ST:@.+]] = linkonce_odr thread_local global i32 23 +// CHECK-TLS-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr thread_local global float 2.300000e+01 +// CHECK-TLS-DAG: [[ST_S4_ST:@.+]] = linkonce_odr thread_local global %struct.S4 zeroinitializer +// CHECK-TLS-DAG: [[ST_S4_ST_GUARD:@_ZGVN2STI2S4E2stE]] = linkonce_odr thread_local global i64 0 +// CHECK-TLS-DAG: @__tls_guard = internal thread_local global i8 0 +// CHECK-TLS-DAG: @__dso_handle = external global i8 +// CHECK-TLS-DAG: [[GS1_TLS_INIT:@_ZTHL3gs1]] = internal alias void ()* @__tls_init +// CHECK-TLS-DAG: [[ARR_X_TLS_INIT:@_ZTH5arr_x]] = alias void ()* @__tls_init +// CHECK-TLS-DAG: [[ST_INT_ST_TLS_INIT:@_ZTHN2STIiE2stE]] = linkonce_odr alias void ()* @__tls_init +// CHECK-TLS-DAG: [[ST_FLOAT_ST_TLS_INIT:@_ZTHN2STIfE2stE]] = linkonce_odr alias void ()* @__tls_init +// CHECK-TLS-DAG: [[ST_S4_ST_TLS_INIT:@_ZTHN2STI2S4E2stE]] = linkonce_odr alias void ()* @__tls_init struct Static { static S3 s; @@ -326,6 +356,18 @@ int main() { // CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]], [[INT]]* [[GS1_A_ADDR]] // CHECK-DEBUG-NEXT: invoke {{.*}} [[SMAIN_CTOR:.*]]([[SMAIN]]* [[SM]], [[INT]] {{.*}}[[GS1_A]]) // CHECK-DEBUG: call {{.*}}void @__cxa_guard_release +// CHECK-TLS: [[IS_INIT_INT:%.*]] = load i8, i8* [[SM_GUARD]] +// CHECK-TLS-NEXT: [[IS_INIT_BOOL:%.*]] = icmp eq i8 [[IS_INIT_INT]], 0 +// CHECK-TLS-NEXT: br i1 [[IS_INIT_BOOL]], label %[[INIT_LABEL:.*]], label %[[INIT_DONE:[^,]+]]{{.*}} +// CHECK-TLS: [[INIT_LABEL]] +// CHECK-TLS-NEXT: [[GS1_ADDR:%.*]] = call [[S1]]* [[GS1_TLS_INITD:@[^,]+]] +// CHECK-TLS-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[GS1_ADDR]], i32 0, i32 0 +// CHECK-TLS-NEXT: [[GS1_A_VAL:%.*]] = load i32, i32* [[GS1_A_ADDR]] +// CHECK-TLS-NEXT: call void [[SM_CTOR1:@.*]]([[SMAIN]]* [[SM]], i32 [[GS1_A_VAL]]) +// CHECK-TLS-NEXT: call i32 @__cxa_thread_atexit(void (i8*)* bitcast (void ([[SMAIN]]*)* [[SM_DTOR1:@.*]] to void (i8*)*), i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i8* @__dso_handle) +// CHECK-TLS-NEXT: store i8 1, i8* [[SM_GUARD]] +// CHECK-TLS-NEXT: br label %[[INIT_DONE]] +// CHECK-TLS: [[INIT_DONE]] #pragma omp threadprivate(sm) // CHECK: [[STATIC_S_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[STATIC_S]].cache.) // CHECK-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]* @@ -339,6 +381,10 @@ int main() { // CHECK-DEBUG-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]], [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 // CHECK-DEBUG-NEXT: [[STATIC_S_A:%.*]] = load [[INT]], [[INT]]* [[STATIC_S_A_ADDR]] // CHECK-DEBUG-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]] + // CHECK-TLS: [[STATIC_S_ADDR:%.*]] = call [[S3]]* [[STATIC_S_TLS_INITD:@[^,]+]] + // CHECK-TLS-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]], [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[STATIC_S_A:%.*]] = load i32, i32* [[STATIC_S_A_ADDR]] + // CHECK-TLS-NEXT: store i32 [[STATIC_S_A]], i32* [[RES_ADDR:[^,]+]] Res = Static::s.a; // CHECK: [[SM_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[SM]].cache.) // CHECK-NEXT: [[SM_ADDR:%.*]] = bitcast i8* [[SM_TEMP_ADDR]] to [[SMAIN]]* @@ -356,6 +402,11 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[SM_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // [[SM]] was initialized already, so it can be used directly + // CHECK-TLS: [[SM_A:%.*]] = load i32, i32* getelementptr inbounds ([[SMAIN]], [[SMAIN]]* [[SM]], i{{.*}} 0, i{{.*}} 0) + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[SM_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += sm.a; // CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.) // CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* @@ -373,6 +424,12 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS1_ADDR:%.*]] = call [[S1]]* [[GS1_TLS_INITD]] + // CHECK-TLS-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[GS1_A:%.*]] = load i32, i32* [[GS1_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[GS1_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += gs1.a; // CHECK: [[GS2_A:%.*]] = load [[INT]], [[INT]]* getelementptr inbounds ([[S2]], [[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) // CHECK-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] @@ -382,6 +439,10 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS2_A:%.*]] = load [[INT]], [[INT]]* getelementptr inbounds ([[S2]], [[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) + // CHECK-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]] + // CHECK-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] Res += gs2.a; // CHECK: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS3]].cache.) // CHECK-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]* @@ -399,6 +460,12 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS3_ADDR:%.*]] = call [[S5]]* [[GS3_TLS_INITD:[^,]+]] + // CHECK-TLS-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]], [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[GS3_A:%.*]] = load i32, i32* [[GS3_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add nsw i32 [[RES]], [[GS3_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += gs3.a; // CHECK: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ARR_X]].cache.) // CHECK-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]* @@ -420,6 +487,14 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ARR_X_ADDR:%.*]] = call [2 x [3 x [[S1]]]]* [[ARR_X_TLS_INITD:[^,]+]] + // CHECK-TLS-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-TLS-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]], [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-TLS-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[ARR_X_1_1_A:%.*]] = load i32, i32* [[ARR_X_1_1_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[ARR_X_1_1_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += arr_x[1][1].a; // CHECK: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_INT_ST]].cache.) // CHECK-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]* @@ -435,6 +510,11 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_INT_ST_ADDR:%.*]] = call i32* [[ST_INT_ST_TLS_INITD:[^,]+]] + // CHECK-TLS-NEXT: [[ST_INT_ST_VAL:%.*]] = load i32, i32* [[ST_INT_ST_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[ST_INT_ST_VAL]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += ST<int>::st; // CHECK: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_FLOAT_ST]].cache.) // CHECK-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float* @@ -452,6 +532,12 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_FLOAT_ST_ADDR:%.*]] = call float* [[ST_FLOAT_ST_TLS_INITD:[^,]+]] + // CHECK-TLS-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float, float* [[ST_FLOAT_ST_ADDR]] + // CHECK-TLS-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to i32 + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[FLOAT_TO_INT_CONV]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += static_cast<int>(ST<float>::st); // CHECK: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_S4_ST]].cache.) // CHECK-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]* @@ -469,11 +555,19 @@ int main() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_S4_ST_ADDR:%.*]] = call [[S4]]* [[ST_S4_ST_TLS_INITD:[^,]+]] + // CHECK-TLS-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]], [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[ST_S4_ST_A:%.*]] = load i32, i32* [[ST_S4_ST_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[ST_S4_ST_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += ST<S4>::st.a; // CHECK: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-NEXT: ret [[INT]] [[RES]] // CHECK-DEBUG: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: ret [[INT]] [[RES]] + // CHECK-TLS: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: ret i32 [[RES]] return Res; } // CHECK: } @@ -523,12 +617,47 @@ int main() { // CHECK-DEBUG: call {{.*}} [[SMAIN_DTOR:@.+]]([[SMAIN]]* // CHECK-DEBUG: } // CHECK-DEBUG: define {{.*}} [[SMAIN_DTOR]]([[SMAIN]]* {{.*}}) +// CHECK-TLS: define internal [[S1]]* [[GS1_TLS_INITD]] { +// CHECK-TLS-NEXT: call void [[GS1_TLS_INIT]] +// CHECK-TLS-NEXT: ret [[S1]]* [[GS1]] +// CHECK-TLS-NEXT: } +// CHECK-TLS: define internal void [[SM_CTOR1]]([[SMAIN]]* %this, i32 {{.*}}) {{.*}} { +// CHECK-TLS: void [[SM_CTOR2:@.*]]([[SMAIN]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define internal void [[SM_DTOR1]]([[SMAIN]]* %this) {{.*}} { +// CHECK-TLS: void [[SM_DTOR2:@.*]]([[SMAIN]]* {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} [[S3]]* [[STATIC_S_TLS_INITD]] +// CHECK-TLS: call void [[STATIC_S_TLS_INIT:[^,]+]] +// CHECK-TLS: ret [[S3]]* [[STATIC_S]] +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} [[S5]]* [[GS3_TLS_INITD]] +// CHECK-TLS: call void [[GS3_TLS_INIT:@[^,]+]] +// CHECK-TLS: ret [[S5]]* [[GS3]] +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} [2 x [3 x [[S1]]]]* [[ARR_X_TLS_INITD]] +// CHECK-TLS: call void [[ARR_X_TLS_INIT]] +// CHECK-TLS: ret [2 x [3 x [[S1]]]]* [[ARR_X]] +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} i32* [[ST_INT_ST_TLS_INITD]] { +// CHECK-TLS: call void [[ST_INT_ST_TLS_INIT]] +// CHECK-TLS: ret i32* [[ST_INT_ST]] +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} float* [[ST_FLOAT_ST_TLS_INITD]] { +// CHECK-TLS: call void [[ST_FLOAT_ST_TLS_INIT]] +// CHECK-TLS: ret float* [[ST_FLOAT_ST]] +// CHECK-TLS: } +// CHECK-TLS: define {{.*}} [[S4]]* [[ST_S4_ST_TLS_INITD]] { +// CHECK-TLS: call void [[ST_S4_ST_TLS_INIT]] +// CHECK-TLS: ret [[S4]]* [[ST_S4_ST]] +// CHECK-TLS: } #endif #ifdef BODY // CHECK-LABEL: @{{.*}}foobar{{.*}}() // CHECK-DEBUG-LABEL: @{{.*}}foobar{{.*}}() +// CHECK-TLS: @{{.*}}foobar{{.*}}() int foobar() { // CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] int Res; @@ -548,6 +677,10 @@ int foobar() { // CHECK-DEBUG-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]], [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 // CHECK-DEBUG-NEXT: [[STATIC_S_A:%.*]] = load [[INT]], [[INT]]* [[STATIC_S_A_ADDR]] // CHECK-DEBUG-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]] + // CHECK-TLS: [[STATIC_S_ADDR:%.*]] = call [[S3]]* [[STATIC_S_TLS_INITD]] + // CHECK-TLS-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]], [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[STATIC_S_A:%.*]] = load i32, i32* [[STATIC_S_A_ADDR]] + // CHECK-TLS-NEXT: store i32 [[STATIC_S_A]], i32* [[RES_ADDR:[^,]+]] Res = Static::s.a; // CHECK: [[GS1_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS1]].cache.) // CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* @@ -565,6 +698,12 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS1_ADDR:%.*]] = call [[S1]]* [[GS1_TLS_INITD]] + // CHECK-TLS-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[GS1_A:%.*]] = load i32, i32* [[GS1_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[GS1_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES_ADDR]] Res += gs1.a; // CHECK: [[GS2_A:%.*]] = load [[INT]], [[INT]]* getelementptr inbounds ([[S2]], [[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) // CHECK-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] @@ -574,6 +713,10 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS2_A:%.*]] = load i32, i32* getelementptr inbounds ([[S2]], [[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) + // CHECK-TLS-NEXT: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} i32 [[RES]], [[GS2_A]] + // CHECK-TLS-NEXT: store i32 [[ADD]], i32* [[RES:.+]] Res += gs2.a; // CHECK: [[GS3_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[GS3]].cache.) // CHECK-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]* @@ -591,6 +734,12 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[GS3_ADDR:%.*]] = call [[S5]]* [[GS3_TLS_INITD]] + // CHECK-TLS-DEBUG: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]], [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-DEBUG: [[GS3_A:%.*]] = load i32, i32* [[GS3_A_ADDR]] + // CHECK-TLS-DEBUG: [[RES:%.*]] = load i32, i32* [[RES_ADDR]] + // CHECK-TLS-DEBUG: [[ADD:%.*]]= add nsw i32 [[RES]], [[GS3_A]] + // CHECK-TLS-DEBUG: store i32 [[ADD]], i32* [[RES_ADDR]] Res += gs3.a; // CHECK: [[ARR_X_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ARR_X]].cache.) // CHECK-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]* @@ -612,6 +761,14 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ARR_X_ADDR:%.*]] = call [2 x [3 x [[S1]]]]* [[ARR_X_TLS_INITD]] + // CHECK-TLS-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-TLS-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]], [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-TLS-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]], [[INT]]* [[ARR_X_1_1_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]] + // CHECK-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] Res += arr_x[1][1].a; // CHECK: [[ST_INT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_INT_ST]].cache.) // CHECK-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]* @@ -627,6 +784,11 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_INT_ST_ADDR:%.*]] = call i32* [[ST_INT_ST_TLS_INITD]] + // CHECK-TLS-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]], [[INT]]* [[ST_INT_ST_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]] + // CHECK-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] Res += ST<int>::st; // CHECK: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_FLOAT_ST]].cache.) // CHECK-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float* @@ -644,6 +806,12 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_FLOAT_ST_ADDR:%.*]] = call float* [[ST_FLOAT_ST_TLS_INITD]] + // CHECK-TLS-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float, float* [[ST_FLOAT_ST_ADDR]] + // CHECK-TLS-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]] + // CHECK-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] Res += static_cast<int>(ST<float>::st); // CHECK: [[ST_S4_ST_TEMP_ADDR:%.*]] = call {{.*}}i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[ST_S4_ST]].cache.) // CHECK-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]* @@ -661,11 +829,19 @@ int foobar() { // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]] // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-TLS: [[ST_S4_ST_ADDR:%.*]] = call [[S4]]* [[ST_S4_ST_TLS_INITD]] + // CHECK-TLS-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]], [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-TLS-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]], [[INT]]* [[ST_S4_ST_A_ADDR]] + // CHECK-TLS-NEXT: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]] + // CHECK-TLS-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] Res += ST<S4>::st.a; // CHECK: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-NEXT: ret [[INT]] [[RES]] // CHECK-DEBUG: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] // CHECK-DEBUG-NEXT: ret [[INT]] [[RES]] + // CHECK-TLS: [[RES:%.*]] = load [[INT]], [[INT]]* [[RES_ADDR]] + // CHECK-TLS-NEXT: ret [[INT]] [[RES]] return Res; } #endif @@ -706,3 +882,71 @@ int foobar() { // CHECK: ret void // CHECK-DEBUG: define internal {{.*}}void {{@.*}}() // CHECK-DEBUG: ret void + +// CHECK-TLS: define internal void [[GS1_CXX_INIT:@.*]]() +// CHECK-TLS: call void [[GS1_CTOR1:@.*]]([[S1]]* [[GS1]], i32 5) +// CHECK-TLS: call i32 @__cxa_thread_atexit(void (i8*)* bitcast (void ([[S1]]*)* [[GS1_DTOR1:.*]] to void (i8*)*), i8* bitcast ([[S1]]* [[GS1]] to i8*) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS1_CTOR1]]([[S1]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: call void [[GS1_CTOR2:@.*]]([[S1]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS1_DTOR1]]([[S1]]* {{.*}}) +// CHECK-TLS: call void [[GS1_DTOR2:@.*]]([[S1]]* {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS1_CTOR2]]([[S1]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: define {{.*}}void [[GS1_DTOR2]]([[S1]]* {{.*}}) + +// CHECK-TLS: define internal void [[GS2_CXX_INIT:@.*]]() +// CHECK-TLS: call void [[GS2_CTOR1:@.*]]([[S2]]* [[GS2]], i32 27) +// CHECK-TLS: call i32 @__cxa_atexit(void (i8*)* bitcast (void ([[S2]]*)* [[GS2_DTOR1:.*]] to void (i8*)*), i8* bitcast ([[S2]]* [[GS2]] to i8*) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS2_CTOR1]]([[S2]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: call void [[GS2_CTOR2:@.*]]([[S2]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS2_DTOR1]]([[S2]]* {{.*}}) +// CHECK-TLS: call void [[GS2_DTOR2:@.*]]([[S2]]* {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[GS2_CTOR2]]([[S2]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: define {{.*}}void [[GS2_DTOR2]]([[S2]]* {{.*}}) + +// CHECK-TLS: define internal void [[ARR_X_CXX_INIT:@.*]]() +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 0, i{{.*}} 0), i{{.*}} 1) +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 0, i{{.*}} 1), i{{.*}} 2) +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 0, i{{.*}} 2), i{{.*}} 3) +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 1, i{{.*}} 0), i{{.*}} 4) +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 1, i{{.*}} 1), i{{.*}} 5) +// CHECK-TLS: invoke void [[GS1_CTOR1]]([[S1]]* getelementptr inbounds ([2 x [3 x [[S1]]]], [2 x [3 x [[S1]]]]* [[ARR_X]], i{{.*}} 0, i{{.*}} 1, i{{.*}} 2), i{{.*}} 6) +// CHECK-TLS: call i32 @__cxa_thread_atexit(void (i8*)* [[ARR_X_CXX_DTOR:@[^,]+]] +// CHECK-TLS: define internal void [[ARR_X_CXX_DTOR]](i8*) +// CHECK-TLS: void [[GS1_DTOR1]]([[S1]]* {{.*}}) + +// CHECK-TLS: define {{.*}}void [[SM_CTOR2]]([[SMAIN]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: define {{.*}}void [[SM_DTOR2]]([[SMAIN]]* {{.*}}) + +// CHECK-TLS: define internal void [[ST_S4_ST_CXX_INIT:@.*]]() +// CHECK-TLS: call void [[ST_S4_ST_CTOR1:@.*]]([[S4]]* [[ST_S4_ST]], i32 23) +// CHECK-TLS: call i32 @__cxa_thread_atexit(void (i8*)* bitcast (void ([[S4]]*)* [[ST_S4_ST_DTOR1:.*]] to void (i8*)*), i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[ST_S4_ST_CTOR1]]([[S4]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: call void [[ST_S4_ST_CTOR2:@.*]]([[S4]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[ST_S4_ST_DTOR1]]([[S4]]* {{.*}}) +// CHECK-TLS: call void [[ST_S4_ST_DTOR2:@.*]]([[S4]]* {{.*}}) +// CHECK-TLS: } +// CHECK-TLS: define {{.*}}void [[ST_S4_ST_CTOR2]]([[S4]]* {{.*}}, i32 {{.*}}) +// CHECK-TLS: define {{.*}}void [[ST_S4_ST_DTOR2]]([[S4]]* {{.*}}) + +// CHECK-TLS: define internal void @__tls_init() +// CHECK-TLS: [[GRD:%.*]] = load i8, i8* @__tls_guard +// CHECK-TLS-NEXT: [[IS_INIT:%.*]] = icmp eq i8 [[GRD]], 0 +// CHECK-TLS-NEXT: store i8 1, i8* @__tls_guard +// CHECK-TLS-NEXT: br i1 [[IS_INIT]], label %[[INIT_LABEL:[^,]+]], label %[[DONE_LABEL:[^,]+]]{{.*}} +// CHECK-TLS: [[INIT_LABEL]] +// CHECK-TLS: call void [[GS1_CXX_INIT]] +// CHECK-TLS-NOT call void [[GS2_CXX_INIT]] +// CHECK-TLS: call void [[ARR_X_CXX_INIT]] +// CHECK-TLS: call void [[ST_S4_ST_CXX_INIT]] +// CHECK-TLS: [[DONE_LABEL]] + +// CHECK-TLS: declare {{.*}} void [[GS3_TLS_INIT]] +// CHECK-TLS: declare {{.*}} void [[STATIC_S_TLS_INIT]] diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp index 70ab5441aba0..39a4431f0c5b 100644 --- a/test/OpenMP/threadprivate_messages.cpp +++ b/test/OpenMP/threadprivate_messages.cpp @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -fnoopenmp-use-tls -ferror-limit 100 -emit-llvm -o - %s // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -emit-llvm -o - %s #pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} diff --git a/test/PCH/__va_list_tag.c b/test/PCH/__va_list_tag.c index efe5c1b36630..81cda8963b23 100644 --- a/test/PCH/__va_list_tag.c +++ b/test/PCH/__va_list_tag.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // PR13189 // rdar://problem/11741429 // Test this without pch. diff --git a/test/PCH/arc.m b/test/PCH/arc.m index 466b31705596..63c77778f40a 100644 --- a/test/PCH/arc.m +++ b/test/PCH/arc.m @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // Test this without pch. // RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-arc -include %S/Inputs/arc.h -fsyntax-only -emit-llvm-only %s diff --git a/test/PCH/asm.c b/test/PCH/asm.c index 160829b7a6e7..cabd03cac9ae 100644 --- a/test/PCH/asm.c +++ b/test/PCH/asm.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // Test this without pch. // RUN: %clang_cc1 -triple i386-unknown-unknown -include %S/asm.h -fsyntax-only -verify %s diff --git a/test/PCH/chain-external-defs.c b/test/PCH/chain-external-defs.c index 742229442865..f7c723338996 100644 --- a/test/PCH/chain-external-defs.c +++ b/test/PCH/chain-external-defs.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // Test with pch. // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t1.pch %S/Inputs/chain-external-defs1.h // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t2.pch %S/Inputs/chain-external-defs2.h -include-pch %t1.pch diff --git a/test/PCH/chain-openmp-threadprivate.cpp b/test/PCH/chain-openmp-threadprivate.cpp index a2a885ae8cfd..c75b872ba2a0 100644 --- a/test/PCH/chain-openmp-threadprivate.cpp +++ b/test/PCH/chain-openmp-threadprivate.cpp @@ -1,7 +1,16 @@ // no PCH -// RUN: %clang_cc1 -fopenmp -emit-llvm -include %s -include %s %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -emit-llvm -include %s -include %s %s -o - | FileCheck %s // with PCH -// RUN: %clang_cc1 -fopenmp -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s +// no PCH +// RUN: %clang_cc1 -fopenmp -emit-llvm -include %s -include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-1 +// RUN: %clang_cc1 -fopenmp -emit-llvm -include %s -include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-2 +// with PCH +// RUN: %clang_cc1 -fopenmp -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-1 +// RUN: %clang_cc1 -fopenmp -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s -check-prefix=CHECK-TLS-2 + +// REQUIRES: tls + #if !defined(PASS1) #define PASS1 @@ -16,11 +25,17 @@ int *a = malloc(20); #else // CHECK: call {{.*}} @__kmpc_threadprivate_register( +// CHECK-TLS-1: @{{a|\"\\01\?a@@3PE?AHE?A\"}} = {{.*}}thread_local {{.*}}global {{.*}}i32* // CHECK-LABEL: foo +// CHECK-TLS-LABEL: foo int foo() { return *a; // CHECK: call {{.*}} @__kmpc_global_thread_num( // CHECK: call {{.*}} @__kmpc_threadprivate_cached( + // CHECK-TLS-1: call {{.*}} @{{_ZTW1a|\"\\01\?\?__Ea@@YAXXZ\"}}() } + +// CHECK-TLS-2: define {{.*}} @{{_ZTW1a|\"\\01\?\?__Ea@@YAXXZ\"}}() + #endif diff --git a/test/PCH/chain-trivial.c b/test/PCH/chain-trivial.c index a0f5827fb91d..4cc7890de04f 100644 --- a/test/PCH/chain-trivial.c +++ b/test/PCH/chain-trivial.c @@ -1,2 +1,3 @@ +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t1 %S/Inputs/chain-trivial1.h // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t2 -include-pch %t1 %S/Inputs/chain-trivial2.h diff --git a/test/PCH/cxx-ms-function-specialization-class-scope.cpp b/test/PCH/cxx-ms-function-specialization-class-scope.cpp index afbb80b7376e..f97a8d183c7a 100644 --- a/test/PCH/cxx-ms-function-specialization-class-scope.cpp +++ b/test/PCH/cxx-ms-function-specialization-class-scope.cpp @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -x c++-header -emit-pch -o %t %S/cxx-ms-function-specialization-class-scope.h // RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s // expected-no-diagnostics diff --git a/test/PCH/cxx1y-variable-templates.cpp b/test/PCH/cxx1y-variable-templates.cpp index 77eeea22a23d..29b66a11e8ce 100644 --- a/test/PCH/cxx1y-variable-templates.cpp +++ b/test/PCH/cxx1y-variable-templates.cpp @@ -89,8 +89,8 @@ namespace join { namespace diff_types { #ifdef ERROR - template<typename T> extern T err0; // expected-error {{redefinition of 'err0' with a different type: 'T' vs 'float'}} // expected-note@42 {{previous definition is here}} - template<typename T> extern float err1; // expected-error {{redefinition of 'err1' with a different type: 'float' vs 'T'}} // expected-note@43 {{previous definition is here}} + template<typename T> extern T err0; // expected-error {{redeclaration of 'err0' with a different type: 'T' vs 'float'}} // expected-note@42 {{previous declaration is here}} + template<typename T> extern float err1; // expected-error {{redeclaration of 'err1' with a different type: 'float' vs 'T'}} // expected-note@43 {{previous declaration is here}} #endif template<typename T> extern T def; } diff --git a/test/PCH/external-defs.c b/test/PCH/external-defs.c index 5c2582a9c361..5e906b246bc7 100644 --- a/test/PCH/external-defs.c +++ b/test/PCH/external-defs.c @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // Test with pch. // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t.pch %S/external-defs.h // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s diff --git a/test/PCH/floating-literal.c b/test/PCH/floating-literal.c index 738e45a41517..b5ff6fe84b88 100644 --- a/test/PCH/floating-literal.c +++ b/test/PCH/floating-literal.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-pch -o %t %s +// REQUIRES: mips-registered-target // RUN: %clang_cc1 -x ast -ast-print %t | FileCheck %s // Make sure the semantics of FloatingLiterals are stored correctly in diff --git a/test/PCH/local_static.cpp b/test/PCH/local_static.cpp index 1085d81d3175..b4131bffde22 100644 --- a/test/PCH/local_static.cpp +++ b/test/PCH/local_static.cpp @@ -1,3 +1,4 @@ +// REQUIRES: x86-registered-target // Test this without PCH. // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -include %S/local_static.h -fsyntax-only %s -emit-llvm -o %t.no_pch.ll %s // RUN: FileCheck --input-file %t.no_pch.ll %s diff --git a/test/PCH/objc_kindof.m b/test/PCH/objc_kindof.m new file mode 100644 index 000000000000..437c41710408 --- /dev/null +++ b/test/PCH/objc_kindof.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-pch %s -o %t +// RUN: %clang_cc1 -include-pch %t -verify %s + +#ifndef HEADER_INCLUDED + +#define HEADER_INCLUDED +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableString : NSString +@end + +@interface NSNumber : NSObject <NSCopying> +@end + +extern __kindof NSObject <NSCopying> *kindof_NSObject_NSCopying; + +#else +void testPrettyPrint(int *ip) { + ip = kindof_NSObject_NSCopying; // expected-warning{{from '__kindof NSObject<NSCopying> *'}} +} + +#endif diff --git a/test/PCH/objc_parameterized_classes.m b/test/PCH/objc_parameterized_classes.m new file mode 100644 index 000000000000..0c1885871045 --- /dev/null +++ b/test/PCH/objc_parameterized_classes.m @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -emit-pch %s -o %t +// RUN: %clang_cc1 -include-pch %t -verify %s + +#ifndef HEADER_INCLUDED + +#define HEADER_INCLUDED + +@protocol NSObject +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +@interface PC1<__covariant T, U : NSObject *> : NSObject +// expected-note@-2{{type parameter 'U' declared here}} +@end + +@interface PC1<__covariant T, U : NSObject *> (Cat1) +@end + +typedef PC1<id, NSObject *> PC1Specialization1; + +typedef PC1Specialization1 <NSObject> PC1Specialization2; +#else + +@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}} + // expected-note@15{{type parameter 'T' declared here}} + U : id> (Cat2) // expected-error{{type bound 'id' for type parameter 'U' conflicts with previous bound 'NSObject *'}} + // expected-note@15{{type parameter 'U' declared here}} +@end + +typedef PC1Specialization1<id, NSObject *> PC1Specialization3; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}} + +typedef PC1Specialization2<id, NSObject *> PC1Specialization4; // expected-error{{already-specialized class type 'PC1Specialization2' (aka 'PC1Specialization1<NSObject>')}} + +@interface NSString : NSObject +@end + +void testCovariance(PC1<NSObject *, NSObject *> *pc1a, + PC1<NSString *, NSObject *> *pc1b) { + pc1a = pc1b; +} + +#endif diff --git a/test/PCH/pchpch.c b/test/PCH/pchpch.c index d68a6ad4aee6..5ea661abd555 100644 --- a/test/PCH/pchpch.c +++ b/test/PCH/pchpch.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t1 %S/pchpch1.h // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t2 %S/pchpch2.h -include-pch %t1 // RUN: %clang_cc1 -triple i386-unknown-unknown -fsyntax-only %s -include-pch %t2 +// REQUIRES: x86-registered-target // The purpose of this test is to make sure that a PCH created while including // an existing PCH can be loaded. diff --git a/test/PCH/reloc.c b/test/PCH/reloc.c index 8dabb8b03d0b..bf70ab6f6922 100644 --- a/test/PCH/reloc.c +++ b/test/PCH/reloc.c @@ -3,6 +3,7 @@ // RUN: %clang -target x86_64-apple-darwin10 -fsyntax-only \ // RUN: -include-pch %t -isysroot %S/libroot %s -Xclang -verify // RUN: not %clang -target x86_64-apple-darwin10 -include-pch %t %s +// REQUIRES: x86-registered-target #include <reloc.h> diff --git a/test/PCH/subscripting-literals.m b/test/PCH/subscripting-literals.m index 725e5802a5dd..52491dbc2008 100644 --- a/test/PCH/subscripting-literals.m +++ b/test/PCH/subscripting-literals.m @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t.nopch.ll %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch -o %t.pch %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t.pch.ll %s -include-pch %t.pch +// REQUIRES: x86-registered-target // RUN: diff %t.nopch.ll %t.pch.ll #ifndef HEADER diff --git a/test/PCH/target-options.c b/test/PCH/target-options.c index 2b85efe07abf..06a09502f9ab 100644 --- a/test/PCH/target-options.c +++ b/test/PCH/target-options.c @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-pch -o %t.pch %S/target-options.h // RUN: not %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include-pch %t.pch %s -emit-llvm -o - > %t.err 2>&1 // RUN: FileCheck %s < %t.err +// REQUIRES: x86-registered-target // CHECK: for the target diff --git a/test/PCH/tentative-defs.c b/test/PCH/tentative-defs.c index 42882307dc73..7163316a93de 100644 --- a/test/PCH/tentative-defs.c +++ b/test/PCH/tentative-defs.c @@ -1,6 +1,7 @@ // Test with pch. // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-pch -o %t.pch %S/tentative-defs.h // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -include-pch %t.pch -verify -emit-llvm -o %t %s +// REQUIRES: x86-registered-target // RUN: grep "@variable = common global i32 0" %t | count 1 // RUN: grep "@incomplete_array = common global .*1 x i32" %t | count 1 diff --git a/test/PCH/thread-local.cpp b/test/PCH/thread-local.cpp index f65c12af0925..ab37f7b3f7ed 100644 --- a/test/PCH/thread-local.cpp +++ b/test/PCH/thread-local.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -pedantic-errors -std=c++11 -triple x86_64-linux-gnu -emit-pch %s -o %t // RUN: %clang_cc1 -pedantic-errors -std=c++11 -triple x86_64-linux-gnu -include-pch %t -verify %s - +// REQUIRES: x86-registered-target #ifndef HEADER_INCLUDED #define HEADER_INCLUDED diff --git a/test/PCH/va_arg.c b/test/PCH/va_arg.c index 1fb2a838e4f7..dba9eea8de42 100644 --- a/test/PCH/va_arg.c +++ b/test/PCH/va_arg.c @@ -1,5 +1,6 @@ // Test this without pch. // RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include %S/va_arg.h %s -emit-llvm -o - +// REQUIRES: x86-registered-target // Test with pch. // RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -emit-pch -o %t %S/va_arg.h diff --git a/test/PCH/va_arg.cpp b/test/PCH/va_arg.cpp index 7c8dc6b316f3..0b3c3b107c06 100644 --- a/test/PCH/va_arg.cpp +++ b/test/PCH/va_arg.cpp @@ -1,5 +1,6 @@ // Test this without pch. // RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include %S/Inputs/va_arg.h %s -emit-llvm -o - +// REQUIRES: x86-registered-target // Test with pch. // RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -emit-pch -x c++-header -o %t %S/Inputs/va_arg.h diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c index 389cf6dfc03c..a29f6c0b5492 100644 --- a/test/Parser/MicrosoftExtensions.c +++ b/test/Parser/MicrosoftExtensions.c @@ -55,8 +55,6 @@ int foo1([SA_Post(attr=1)] void *param); [unbalanced(attribute) /* expected-note {{to match this '['}} */ void f(void); /* expected-error {{expected ']'}} */ -[] __interface I {}; /* expected-error {{Microsoft attribute block cannot be empty}} */ - void ms_intrinsics(int a) { __noop(); __assume(a); diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 1686515d6881..e674d0101e97 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -400,3 +400,10 @@ static_assert(__alignof(struct align_before_key1) == 16, ""); static_assert(__alignof(struct align_before_key2) == 16, ""); static_assert(__alignof(struct align_before_key3) == 16, ""); } + +namespace PR24027 { +struct S { + template <typename T> + S(T); +} f([] {}); +} diff --git a/test/Parser/cxx-default-delete.cpp b/test/Parser/cxx-default-delete.cpp index df24b3d0075a..8766d861732e 100644 --- a/test/Parser/cxx-default-delete.cpp +++ b/test/Parser/cxx-default-delete.cpp @@ -19,5 +19,5 @@ struct foo { void baz() = delete; struct quux { - int quux() = default; // expected-error{{constructor cannot have a return type}} expected-error {{member 'quux' has the same name as its class}} + int quux() = default; // expected-error{{constructor cannot have a return type}} }; diff --git a/test/Parser/objc-error-qualified-implementation.m b/test/Parser/objc-error-qualified-implementation.m index 664737223e67..179e2d27479b 100644 --- a/test/Parser/objc-error-qualified-implementation.m +++ b/test/Parser/objc-error-qualified-implementation.m @@ -17,7 +17,7 @@ @interface K @end -@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} +@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-note{{to match this '<'}} @end // expected-error {{expected '>'}} // rdar://13920026 diff --git a/test/Parser/objcxx11-protocol-in-template.mm b/test/Parser/objcxx11-protocol-in-template.mm index 8cb499396d42..c5c3b6c75a47 100644 --- a/test/Parser/objcxx11-protocol-in-template.mm +++ b/test/Parser/objcxx11-protocol-in-template.mm @@ -4,12 +4,7 @@ template<class T> class vector {}; @protocol P @end -#if __cplusplus >= 201103L - // expected-no-diagnostics -#else - // expected-error@14{{a space is required between consecutive right angle brackets}} - // expected-error@15{{a space is required between consecutive right angle brackets}} -#endif +// expected-no-diagnostics vector<id<P>> v; vector<vector<id<P>>> v2; diff --git a/test/Parser/placeholder-recovery.m b/test/Parser/placeholder-recovery.m index 3fe1d62c3042..b43b0e4a57cb 100644 --- a/test/Parser/placeholder-recovery.m +++ b/test/Parser/placeholder-recovery.m @@ -3,10 +3,9 @@ // FIXME: We could do much better with this, if we recognized // placeholders somehow. However, we're content with not generating // bogus 'archaic' warnings with bad location info. -@protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \ -// expected-error{{cannot find protocol declaration for 'NSObject'}} \ +@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \ +// expected-error 2{{expected identifier}} \ // expected-warning{{protocol has no object type specified; defaults to qualified 'id'}} +<#methods#> -<#methods#> // expected-error{{expected identifier}} - -@end // expected-error{{prefix attribute}} +@end diff --git a/test/Profile/Inputs/gcc-flag-compatibility.proftext b/test/Profile/Inputs/gcc-flag-compatibility.proftext new file mode 100644 index 000000000000..99d41bb03f39 --- /dev/null +++ b/test/Profile/Inputs/gcc-flag-compatibility.proftext @@ -0,0 +1,5 @@ +main +4 +2 +1 +100 diff --git a/test/Profile/gcc-flag-compatibility.c b/test/Profile/gcc-flag-compatibility.c new file mode 100644 index 000000000000..5f76c62483f4 --- /dev/null +++ b/test/Profile/gcc-flag-compatibility.c @@ -0,0 +1,43 @@ +// Tests for -fprofile-generate and -fprofile-use flag compatibility. These two +// flags behave similarly to their GCC counterparts: +// +// -fprofile-generate Generates the profile file ./default.profraw +// -fprofile-generate=<dir> Generates the profile file <dir>/default.profraw +// -fprofile-use Uses the profile file ./default.profdata +// -fprofile-use=<dir> Uses the profile file <dir>/default.profdata +// -fprofile-use=<dir>/file Uses the profile file <dir>/file + +// Check that -fprofile-generate uses the runtime default profile file. +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate | FileCheck -check-prefix=PROFILE-GEN %s +// PROFILE-GEN: @__llvm_profile_runtime = external global i32 +// PROFILE-GEN-NOT: call void @__llvm_profile_override_default_filename +// PROFILE-GEN-NOT: declare void @__llvm_profile_override_default_filename(i8*) + +// Check that -fprofile-generate=/path/to generates /path/to/default.profraw +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to | FileCheck -check-prefix=PROFILE-GEN-EQ %s +// PROFILE-GEN-EQ: private constant [25 x i8] c"/path/to{{/|\\5C}}default.profraw\00" +// PROFILE-GEN-EQ: call void @__llvm_profile_override_default_filename(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @0, i32 0, i32 0)) +// PROFILE-GEN-EQ: declare void @__llvm_profile_override_default_filename(i8*) + +// Check that -fprofile-use=some/path reads some/path/default.profdata +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/default.profdata +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-use=%t.dir/some/path | FileCheck -check-prefix=PROFILE-USE-2 %s +// PROFILE-USE-2: = !{!"branch_weights", i32 101, i32 2} + +// Check that -fprofile-use=some/path/file.prof reads some/path/file.prof +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/file.prof +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof | FileCheck -check-prefix=PROFILE-USE-3 %s +// PROFILE-USE-3: = !{!"branch_weights", i32 101, i32 2} + +int X = 0; + +int main() { + int i; + for (i = 0; i < 100; i++) + X += i; + return 0; +} diff --git a/test/Sema/array-declared-as-incorrect-type.c b/test/Sema/array-declared-as-incorrect-type.c index b93fa9a0edf7..0ff9e949085c 100644 --- a/test/Sema/array-declared-as-incorrect-type.c +++ b/test/Sema/array-declared-as-incorrect-type.c @@ -3,14 +3,14 @@ extern int a1[]; int a1[1]; -extern int a2[]; // expected-note {{previous definition is here}} +extern int a2[]; // expected-note {{previous declaration is here}} float a2[1]; // expected-error {{redefinition of 'a2'}} extern int a3[][2]; int a3[1][2]; -extern int a4[][2]; // expected-note {{previous definition is here}} +extern int a4[][2]; // expected-note {{previous declaration is here}} int a4[2]; // expected-error {{redefinition of 'a4'}} -extern int a5[1][2][3]; // expected-note {{previous definition is here}} +extern int a5[1][2][3]; // expected-note {{previous declaration is here}} int a5[3][2][1]; // expected-error {{redefinition of 'a5'}} diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c index e066abdb72d3..3ca1baa299c1 100644 --- a/test/Sema/dllimport.c +++ b/test/Sema/dllimport.c @@ -81,14 +81,14 @@ __declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' __declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}} // Import in local scope. -__declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} -__declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}} -__declspec(dllimport) float LocalRedecl3; // expected-note{{previous definition is here}} +__declspec(dllimport) float LocalRedecl1; // expected-note{{previous declaration is here}} +__declspec(dllimport) float LocalRedecl2; // expected-note{{previous declaration is here}} +__declspec(dllimport) float LocalRedecl3; // expected-note{{previous declaration is here}} __declspec(dllimport) float LocalRedecl4; void functionScope() { - __declspec(dllimport) int LocalRedecl1; // expected-error{{redefinition of 'LocalRedecl1' with a different type: 'int' vs 'float'}} - int *__attribute__((dllimport)) LocalRedecl2; // expected-error{{redefinition of 'LocalRedecl2' with a different type: 'int *' vs 'float'}} - int LocalRedecl3 __attribute__((dllimport)); // expected-error{{redefinition of 'LocalRedecl3' with a different type: 'int' vs 'float'}} + __declspec(dllimport) int LocalRedecl1; // expected-error{{redeclaration of 'LocalRedecl1' with a different type: 'int' vs 'float'}} + int *__attribute__((dllimport)) LocalRedecl2; // expected-error{{redeclaration of 'LocalRedecl2' with a different type: 'int *' vs 'float'}} + int LocalRedecl3 __attribute__((dllimport)); // expected-error{{redeclaration of 'LocalRedecl3' with a different type: 'int' vs 'float'}} __declspec(dllimport) int LocalVarDecl; __declspec(dllimport) int LocalVarDef = 1; // expected-error{{definition of dllimport data}} diff --git a/test/Sema/enable_if.c b/test/Sema/enable_if.c index 4644858593d6..7faae43b577e 100644 --- a/test/Sema/enable_if.c +++ b/test/Sema/enable_if.c @@ -77,6 +77,21 @@ void test3(int c) { #endif } +// Verify that the alternate spelling __enable_if__ works as well. +int isdigit2(int c) __attribute__((overloadable)); // expected-note{{candidate function}} +int isdigit2(int c) __attribute__((overloadable)) // expected-note{{candidate function has been explicitly made unavailable}} + __attribute__((__enable_if__(c <= -1 || c > 255, "'c' must have the value of an unsigned char or EOF"))) + __attribute__((unavailable("'c' must have the value of an unsigned char or EOF"))); + +void test4(int c) { + isdigit2(c); + isdigit2(10); +#ifndef CODEGEN + isdigit2(-10); // expected-error{{call to unavailable function 'isdigit2': 'c' must have the value of an unsigned char or EOF}} +#endif +} + + #ifndef CODEGEN __attribute__((enable_if(n == 0, "chosen when 'n' is zero"))) void f1(int n); // expected-error{{use of undeclared identifier 'n'}} diff --git a/test/Sema/inline-asm-validate-tmpl.cpp b/test/Sema/inline-asm-validate-tmpl.cpp new file mode 100644 index 000000000000..cf7eac3d83d4 --- /dev/null +++ b/test/Sema/inline-asm-validate-tmpl.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s + + +// this template, when instantiated with 300, violates the range contraint +template <int N> void test(int value) +{ + asm("rol %1, %0" :"=r"(value): "I"(N + 1)); // expected-error{{value '301' out of range for constraint 'I'}} +} + +int main() { test<300>(10); } // expected-note{{in instantiation of function template specialization 'test<300>' requested here}} + + +// this template is not used, but the error is detectable +template <int N> void testb(int value) +{ + asm("rol %1, %0" :"=r"(value): "I"(301)); // expected-error{{value '301' out of range for constraint 'I'}} +} + +// these should compile without error +template <int N> void testc(int value) +{ + asm("rol %1, %0" :"=r"(value): "I"(N + 1)); +} +int foo() { testc<2>(10); } diff --git a/test/Sema/mrtd.c b/test/Sema/mrtd.c index ba1720e8d7dc..7bdeb27293b7 100644 --- a/test/Sema/mrtd.c +++ b/test/Sema/mrtd.c @@ -17,8 +17,8 @@ void variadic(int a, ...); void __attribute__((stdcall)) variadic(int a, ...); #ifdef MRTD -// expected-note@+3 {{previous definition is here}} -// expected-error@+3 {{redefinition of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}} +// expected-note@+3 {{previous declaration is here}} +// expected-error@+3 {{redeclaration of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}} #endif extern void (*a)(int, int); __attribute__((cdecl)) extern void (*a)(int, int); @@ -27,8 +27,8 @@ extern void (*b)(int, ...); __attribute__((cdecl)) extern void (*b)(int, ...); #ifndef MRTD -// expected-note@+3 {{previous definition is here}} -// expected-error@+3 {{redefinition of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}} +// expected-note@+3 {{previous declaration is here}} +// expected-error@+3 {{redeclaration of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}} #endif extern void (*c)(int, int); __attribute__((stdcall)) extern void (*c)(int, int); diff --git a/test/Sema/shift.c b/test/Sema/shift.c index d35554488513..07c5fe5280ed 100644 --- a/test/Sema/shift.c +++ b/test/Sema/shift.c @@ -39,7 +39,8 @@ void test() { i = 1 << (WORD_BIT - 2); i = 2 << (WORD_BIT - 1); // expected-warning {{bits to represent, but 'int' only has}} i = 1 << (WORD_BIT - 1); // expected-warning {{sets the sign bit of the shift expression}} - i = -1 << (WORD_BIT - 1); + i = -1 << (WORD_BIT - 1); // expected-warning {{shifting a negative signed value is undefined}} + i = -1 << 0; // expected-warning {{shifting a negative signed value is undefined}} i = 0 << (WORD_BIT - 1); i = (char)1 << (WORD_BIT - 2); @@ -48,7 +49,7 @@ void test() { u = 5U << (WORD_BIT - 1); long long int lli; - lli = INT_MIN << 2; // expected-warning {{bits to represent, but 'int' only has}} + lli = INT_MIN << 2; // expected-warning {{shifting a negative signed value is undefined}} lli = 1LL << (sizeof(long long) * CHAR_BIT - 2); } diff --git a/test/Sema/struct-compat.c b/test/Sema/struct-compat.c index 65bef9f60555..68bb2cad45e1 100644 --- a/test/Sema/struct-compat.c +++ b/test/Sema/struct-compat.c @@ -1,8 +1,8 @@ /* RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify */ -extern struct {int a;} x; // expected-note {{previous definition is here}} -extern struct {int a;} x; // expected-error {{redefinition of 'x'}} +extern struct {int a;} x; // expected-note {{previous declaration is here}} +extern struct {int a;} x; // expected-error {{redeclaration of 'x'}} struct x; int a(struct x* b) { diff --git a/test/Sema/tls_alignment.cpp b/test/Sema/tls_alignment.cpp new file mode 100644 index 000000000000..5a7bb2c463f3 --- /dev/null +++ b/test/Sema/tls_alignment.cpp @@ -0,0 +1,75 @@ +// TLS variable cannot be aligned to more than 32 bytes on PS4. + +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -verify %s + + +// A non-aligned type. +struct non_aligned_struct { + int some_data[16]; // 64 bytes of stuff, non aligned. +}; + +// An aligned type. +struct __attribute__(( aligned(64) )) aligned_struct { + int some_data[12]; // 48 bytes of stuff, aligned to 64. +}; + +// A type with an aligned field. +struct struct_with_aligned_field { + int some_aligned_data[12] __attribute__(( aligned(64) )); // 48 bytes of stuff, aligned to 64. +}; + +// A typedef of the aligned struct. +typedef aligned_struct another_aligned_struct; + +// A typedef to redefine a non-aligned struct as aligned. +typedef __attribute__(( aligned(64) )) non_aligned_struct yet_another_aligned_struct; + +// Non aligned variable doesn't cause an error. +__thread non_aligned_struct foo; + +// Variable aligned because of its type should cause an error. +__thread aligned_struct bar; // expected-error{{alignment (64) of thread-local variable}} + +// Variable explicitly aligned in the declaration should cause an error. +__thread non_aligned_struct bar2 __attribute__(( aligned(64) )); // expected-error{{alignment (64) of thread-local variable}} + +// Variable aligned because of one of its fields should cause an error. +__thread struct_with_aligned_field bar3; // expected-error{{alignment (64) of thread-local variable}} + +// Variable aligned because of typedef, first case. +__thread another_aligned_struct bar4; // expected-error{{alignment (64) of thread-local variable}} + +// Variable aligned because of typedef, second case. +__thread yet_another_aligned_struct bar5; // expected-error{{alignment (64) of thread-local variable}} + +int baz () +{ + return foo.some_data[0] + bar.some_data[1] + bar2.some_data[2] + + bar3.some_aligned_data[3] + bar4.some_data[4] + + bar5.some_data[5]; +} + + +// Verify alignment check where a dependent type is involved. +// The check is (correctly) not performed on "t", but the check still is +// performed on the structure as a whole once it has been instantiated. + +template<class T> struct templated_tls { + static __thread T t; + T other_t __attribute__(( aligned(64) )); +}; +__thread templated_tls<int> blah; // expected-error{{alignment (64) of thread-local variable}} + +int blag() { + return blah.other_t * 2; +} + + +// Verify alignment check where the alignment is a template parameter. +// The check is only performed during instantiation. +template <int N> +struct S { + static int __thread __attribute__((aligned(N))) x; // expected-error{{alignment (64) of thread-local variable}} +}; + +S<64> s_instance; // expected-note{{in instantiation of template class 'S<64>' requested here}} diff --git a/test/Sema/types.c b/test/Sema/types.c index 5614d164a5f4..9981be50ad4f 100644 --- a/test/Sema/types.c +++ b/test/Sema/types.c @@ -45,7 +45,7 @@ extern int i[1LL]; int i[(short)1]; enum e { e_1 }; -extern int j[sizeof(enum e)]; // expected-note {{previous definition}} +extern int j[sizeof(enum e)]; // expected-note {{previous declaration}} int j[42]; // expected-error {{redefinition of 'j' with a different type: 'int [42]' vs 'int [4]'}} // rdar://6880104 diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c index 811e9f10bf20..024bfd436a42 100644 --- a/test/Sema/var-redecl.c +++ b/test/Sema/var-redecl.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s int outer1; // expected-note{{previous definition is here}} -extern int outer2; // expected-note{{previous definition is here}} +extern int outer2; // expected-note{{previous declaration is here}} int outer4; int outer4; // expected-note{{previous definition is here}} int outer5; @@ -9,17 +9,17 @@ int outer6(float); // expected-note{{previous definition is here}} int outer7(float); void outer_test() { - extern float outer1; // expected-error{{redefinition of 'outer1' with a different type}} - extern float outer2; // expected-error{{redefinition of 'outer2' with a different type}} - extern float outer3; // expected-note{{previous definition is here}} + extern float outer1; // expected-error{{redeclaration of 'outer1' with a different type}} + extern float outer2; // expected-error{{redeclaration of 'outer2' with a different type}} + extern float outer3; // expected-note{{previous declaration is here}} double outer4; - extern int outer5; // expected-note{{previous definition is here}} + extern int outer5; // expected-note{{previous declaration is here}} extern int outer6; // expected-error{{redefinition of 'outer6' as different kind of symbol}} int outer7; extern int outer8; // expected-note{{previous definition is here}} extern int outer9; { - extern int outer9; // expected-note{{previous definition is here}} + extern int outer9; // expected-note{{previous declaration is here}} } } @@ -29,22 +29,22 @@ float outer5; // expected-error{{redefinition of 'outer5' with a different type int outer8(int); // expected-error{{redefinition of 'outer8' as different kind of symbol}} float outer9; // expected-error{{redefinition of 'outer9' with a different type}} -extern int outer13; // expected-note{{previous definition is here}} +extern int outer13; // expected-note{{previous declaration is here}} void outer_shadowing_test() { extern int outer10; - extern int outer11; // expected-note{{previous definition is here}} - extern int outer12; // expected-note{{previous definition is here}} + extern int outer11; // expected-note{{previous declaration is here}} + extern int outer12; // expected-note{{previous declaration is here}} { float outer10; float outer11; float outer12; { extern int outer10; // okay - extern float outer11; // expected-error{{redefinition of 'outer11' with a different type}} + extern float outer11; // expected-error{{redeclaration of 'outer11' with a different type}} static double outer12; { - extern float outer12; // expected-error{{redefinition of 'outer12' with a different type}} - extern float outer13; // expected-error{{redefinition of 'outer13' with a different type}} + extern float outer12; // expected-error{{redeclaration of 'outer12' with a different type}} + extern float outer13; // expected-error{{redeclaration of 'outer13' with a different type}} } } } @@ -66,5 +66,5 @@ void f(int x) { // expected-note {{previous definition is here}} } extern int b[]; -void g20() { extern int b[3]; } // expected-note{{previous definition is here}} -void g21() { extern int b[4]; } // expected-error{{redefinition of 'b' with a different type: 'int [4]' vs 'int [3]'}} +void g20() { extern int b[3]; } // expected-note{{previous declaration is here}} +void g21() { extern int b[4]; } // expected-error{{redeclaration of 'b' with a different type: 'int [4]' vs 'int [3]'}} diff --git a/test/Sema/x86_64-linux-android.c b/test/Sema/x86_64-linux-android.c index e09d50ca079c..252570579f60 100644 --- a/test/Sema/x86_64-linux-android.c +++ b/test/Sema/x86_64-linux-android.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-linux-android -emit-pch -o %t %s // RUN: %clang_cc1 -x ast -ast-print %t | FileCheck %s - +// REQUIRES: x86-registered-target extern int a1_0[sizeof(long double) == 16 ? 1 : -1]; extern int a1_i[__alignof(long double) == 16 ? 1 : -1]; diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp index 89efc501d82c..d5eb27a66132 100644 --- a/test/SemaCXX/alias-template.cpp +++ b/test/SemaCXX/alias-template.cpp @@ -68,12 +68,10 @@ namespace InFunctions { namespace ClassNameRedecl { class C0 { - // FIXME: this diagnostic is pretty poor - template<typename U> using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}} + template<typename U> using C0 = int; // expected-error {{member 'C0' has the same name as its class}} }; class C1 { - // FIXME: this diagnostic is pretty poor - template<typename U> using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}} + template<typename U> using C1 = C1; // expected-error {{member 'C1' has the same name as its class}} }; class C2 { template<typename U> using C0 = C1; // ok diff --git a/test/SemaCXX/array-bound-merge.cpp b/test/SemaCXX/array-bound-merge.cpp index c6085fb0a965..a360d007c3b7 100644 --- a/test/SemaCXX/array-bound-merge.cpp +++ b/test/SemaCXX/array-bound-merge.cpp @@ -10,5 +10,5 @@ int c[] = {1,2}; // expected-error {{excess elements in array initializer}} int d[1][]; // expected-error {{array has incomplete element type 'int []'}} -extern const int e[2]; // expected-note {{previous definition is here}} +extern const int e[2]; // expected-note {{previous declaration is here}} int e[] = { 1 }; // expected-error {{redefinition of 'e' with a different type: 'int []' vs 'const int [2]'}} diff --git a/test/SemaCXX/cast-lvalue-to-rvalue-reference.cpp b/test/SemaCXX/cast-lvalue-to-rvalue-reference.cpp new file mode 100644 index 000000000000..45e72d2924fe --- /dev/null +++ b/test/SemaCXX/cast-lvalue-to-rvalue-reference.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 +// expected-no-diagnostics + +struct S {}; +int x; +S&& y1 = (S&&)x; +S&& y2 = reinterpret_cast<S&&>(x); +S& z1 = (S&)x; diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index fa930bdb95dc..105605c6e37b 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -15,8 +15,7 @@ class Foo { virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}} Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}} - int Foo(int, int); // expected-error{{constructor cannot have a return type}} \ - // expected-error{{member 'Foo' has the same name as its class}} + int Foo(int, int); // expected-error{{constructor cannot have a return type}} volatile Foo(float); // expected-error{{constructor cannot have a return type}} }; diff --git a/test/SemaCXX/cxx11-thread-local.cpp b/test/SemaCXX/cxx11-thread-local.cpp index f1dddc1c3bf7..a974d8198561 100644 --- a/test/SemaCXX/cxx11-thread-local.cpp +++ b/test/SemaCXX/cxx11-thread-local.cpp @@ -19,5 +19,5 @@ thread_local int z[3]; // expected-note {{previous}} void f() { thread_local int x; static thread_local int y; - extern thread_local int z; // expected-error {{redefinition of 'z' with a different type}} + extern thread_local int z; // expected-error {{redeclaration of 'z' with a different type}} } diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp index b49a6418ea85..c937c6728c2b 100644 --- a/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -948,3 +948,41 @@ auto f(T x) { auto x = f(0)(); } + +namespace PR13987 { +class Enclosing { + void Method(char c = []()->char { + int d = [](auto x)->int { + struct LocalClass { + int Method() { return 0; } + }; + return 0; + }(0); + return d; }() + ); +}; + +class Enclosing2 { + void Method(char c = [](auto x)->char { + int d = []()->int { + struct LocalClass { + int Method() { return 0; } + }; + return 0; + }(); + return d; }(0) + ); +}; + +class Enclosing3 { + void Method(char c = [](auto x)->char { + int d = [](auto y)->int { + struct LocalClass { + int Method() { return 0; } + }; + return 0; + }(0); + return d; }(0) + ); +}; +} diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 9ff73daa82d4..123fcfff7f7a 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -214,7 +214,7 @@ namespace in_class_template { template<typename T> class D0a { template<typename U> static U Data; - template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}} + template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous declaration is here}} }; template<> template<typename U> U D0a<float>::Data<U*> = U(100); // expected-error {{redefinition of 'Data'}} @@ -228,7 +228,7 @@ namespace in_class_template { template<typename T> class D1 { template<typename U> static U Data; - template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}} + template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous declaration is here}} }; template<> template<typename U> U D1<float>::Data = U(10); diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp index 4e62941e6818..145bc49fff1f 100644 --- a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -98,8 +98,8 @@ namespace odr_tmpl { namespace pvt_extern { template<typename T> T v = T(); template<typename T> extern T v; // redeclaration is allowed \ - // expected-note {{previous definition is here}} - template<typename T> extern int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}} + // expected-note {{previous declaration is here}} + template<typename T> extern int v; // expected-error {{redeclaration of 'v' with a different type: 'int' vs 'T'}} #ifndef PRECXX11 template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}} @@ -117,7 +117,7 @@ namespace odr_tmpl { template<typename T> auto v2 = T(); // expected-note {{previous definition is here}} template<typename T> T v2; // expected-error {{redefinition of 'v2'}} template<typename T> auto v3 = T(); // expected-note {{previous definition is here}} - template<typename T> extern T v3; // expected-error {{redefinition of 'v3' with a different type: 'T' vs 'auto'}} + template<typename T> extern T v3; // expected-error {{redeclaration of 'v3' with a different type: 'T' vs 'auto'}} template<typename T> auto v4 = T(); template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}} } diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index 0f616d43c89d..2fa10756da48 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -95,13 +95,13 @@ __declspec(dllimport) auto InternalAutoTypeGlobal = Internal(); // expected-erro __declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}} // Import in local scope. -__declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} -__declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}} -__declspec(dllimport) float LocalRedecl3; // expected-note{{previous definition is here}} +__declspec(dllimport) float LocalRedecl1; // expected-note{{previous declaration is here}} +__declspec(dllimport) float LocalRedecl2; // expected-note{{previous declaration is here}} +__declspec(dllimport) float LocalRedecl3; // expected-note{{previous declaration is here}} void functionScope() { - __declspec(dllimport) int LocalRedecl1; // expected-error{{redefinition of 'LocalRedecl1' with a different type: 'int' vs 'float'}} - int *__attribute__((dllimport)) LocalRedecl2; // expected-error{{redefinition of 'LocalRedecl2' with a different type: 'int *' vs 'float'}} - int LocalRedecl3 __attribute__((dllimport)); // expected-error{{redefinition of 'LocalRedecl3' with a different type: 'int' vs 'float'}} + __declspec(dllimport) int LocalRedecl1; // expected-error{{redeclaration of 'LocalRedecl1' with a different type: 'int' vs 'float'}} + int *__attribute__((dllimport)) LocalRedecl2; // expected-error{{redeclaration of 'LocalRedecl2' with a different type: 'int *' vs 'float'}} + int LocalRedecl3 __attribute__((dllimport)); // expected-error{{redeclaration of 'LocalRedecl3' with a different type: 'int' vs 'float'}} __declspec(dllimport) int LocalVarDecl; __declspec(dllimport) int LocalVarDef = 1; // expected-error{{definition of dllimport data}} diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp index dfbf38667c5e..295d1f305ee2 100644 --- a/test/SemaCXX/extern-c.cpp +++ b/test/SemaCXX/extern-c.cpp @@ -21,7 +21,7 @@ float test2_x; // expected-error {{declaration of 'test2_x' in global scope conf namespace test3 { extern "C" { void test3_f() { - extern int test3_b; // expected-note {{previous definition is here}} + extern int test3_b; // expected-note {{previous declaration is here}} } } extern "C" { diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 7911c1b7cc53..72adcdbce2fe 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -446,3 +446,33 @@ namespace PR21857 { template<typename Fn> fun<Fn> wrap(Fn fn); auto x = wrap([](){}); } + +namespace PR13987 { +class Enclosing { + void Method(char c = []()->char { + int d = []()->int { + struct LocalClass { + int Method() { return 0; } + }; + return 0; + }(); + return d; }() + ); +}; +} + +namespace PR23860 { +template <class> struct A { + void f(int x = []() { + struct B { + void g() {} + }; + return 0; + }()); +}; + +int main() { +} + +A<int> a; +} diff --git a/test/SemaCXX/lookup-member.cpp b/test/SemaCXX/lookup-member.cpp index 39f5a15d0811..a2256a89d11c 100644 --- a/test/SemaCXX/lookup-member.cpp +++ b/test/SemaCXX/lookup-member.cpp @@ -1,12 +1,11 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics namespace A { - class String; + class String; // expected-note {{target of using declaration}} }; -using A::String; -class String; +using A::String; // expected-note {{using declaration}} +class String; // expected-error {{conflicts with target of using declaration}} // rdar://8603569 union value { diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp index 706ec5688ba5..7375319186a1 100644 --- a/test/SemaCXX/struct-class-redecl.cpp +++ b/test/SemaCXX/struct-class-redecl.cpp @@ -8,8 +8,8 @@ template<typename T> struct Y; // expected-note{{did you mean class here?}} template<class U> class Y { }; // expected-warning{{previously declared}} template <typename> -struct Z { // expected-note{{previous definition is here}} - struct Z { // expected-error{{nested redefinition of 'Z'}} +struct Z { + struct Z { // expected-error{{member 'Z' has the same name as its class}} }; }; diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp index e730c9d63a20..ca532692c1cb 100644 --- a/test/SemaCXX/using-decl-1.cpp +++ b/test/SemaCXX/using-decl-1.cpp @@ -263,3 +263,67 @@ struct B : A { static int f() { return n; } // expected-error {{invalid use of member 'n' in static member function}} }; } + +namespace PR24030 { + namespace X { + class A; // expected-note {{target}} + int i; // expected-note {{target}} + } + namespace Y { + using X::A; // expected-note {{using}} + using X::i; // expected-note {{using}} + class A {}; // expected-error {{conflicts}} + int i; // expected-error {{conflicts}} + } +} + +namespace PR24033 { + extern int a; // expected-note 2{{target of using declaration}} + void f(); // expected-note 2{{target of using declaration}} + struct s; // expected-note 2{{target of using declaration}} + enum e {}; // expected-note 2{{target of using declaration}} + + template<typename> extern int vt; // expected-note 2{{target of using declaration}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-note 2{{target of using declaration}} + template<typename> struct st; // expected-note 2{{target of using declaration}} + + namespace X { + using PR24033::a; // expected-note {{using declaration}} + using PR24033::f; // expected-note {{using declaration}} + using PR24033::s; // expected-note {{using declaration}} + using PR24033::e; // expected-note {{using declaration}} + + using PR24033::vt; // expected-note {{using declaration}} + using PR24033::ft; // expected-note {{using declaration}} + using PR24033::st; // expected-note {{using declaration}} + + extern int a; // expected-error {{declaration conflicts with target of using declaration already in scope}} + void f(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + struct s; // expected-error {{declaration conflicts with target of using declaration already in scope}} + enum e {}; // expected-error {{declaration conflicts with target of using declaration already in scope}} + + template<typename> extern int vt; // expected-error {{declaration conflicts with target of using declaration already in scope}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + template<typename> struct st; // expected-error {{declaration conflicts with target of using declaration already in scope}} + } + + namespace Y { + extern int a; // expected-note {{conflicting declaration}} + void f(); // expected-note {{conflicting declaration}} + struct s; // expected-note {{conflicting declaration}} + enum e {}; // expected-note {{conflicting declaration}} + + template<typename> extern int vt; // expected-note {{conflicting declaration}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-note {{conflicting declaration}} + template<typename> struct st; // expected-note {{conflicting declaration}} + + using PR24033::a; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::f; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::s; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::e; // expected-error {{target of using declaration conflicts with declaration already in scope}} + + using PR24033::vt; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::ft; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::st; // expected-error {{target of using declaration conflicts with declaration already in scope}} + } +} diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m index b2c4398dc3c5..96c781b6a561 100644 --- a/test/SemaObjC/block-type-safety.m +++ b/test/SemaObjC/block-type-safety.m @@ -198,3 +198,11 @@ void Test3() { NSObject<NSObject, P1, NSCopying> *NSO5 = aBlock; // expected-error {{initializing 'NSObject<NSObject,P1,NSCopying> *' with an expression of incompatible type 'void (^)()'}} NSObject<NSCopying> *NSO6 = aBlock; // Ok } + +// rdar://problem/19420731 +typedef NSObject<P1> NSObject_P1; +typedef NSObject_P1<P2> NSObject_P1_P2; + +void Test4(void (^handler)(NSObject_P1_P2 *p)) { + Test4(^(NSObject<P2> *p) { }); +} diff --git a/test/SemaObjC/conditional-expr-8.m b/test/SemaObjC/conditional-expr-8.m index beddd205a907..35f4e75314bd 100644 --- a/test/SemaObjC/conditional-expr-8.m +++ b/test/SemaObjC/conditional-expr-8.m @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // expected-no-diagnostics -// rdar://9296866 +// rdar://9296866 @interface NSResponder @end @@ -24,3 +24,34 @@ } @end +// rdar://problem/19572837 +@protocol NSObject +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@protocol Goable <NSObject> +- (void)go; +@end + +@protocol Drivable <Goable> +- (void)drive; +@end + +@interface Car : NSObject +- (NSObject <Goable> *)bestGoable:(NSObject <Goable> *)drivable; +@end + +@interface Car(Category) <Drivable> +@end + +@interface Truck : Car +@end + +@implementation Truck +- (NSObject <Goable> *)bestGoable:(NSObject <Goable> *)drivable value:(int)value{ + return value > 0 ? self : drivable; +} +@end diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index 71e108cce673..71bdb1b2d341 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -51,6 +51,10 @@ @end @protocol P2 @end +@protocol P3 <P1> +@end +@protocol P4 <P1> +@end @interface A <P0> @end @@ -64,6 +68,9 @@ @interface D @end +@interface E : A +@end + void f0(id<P0> x) { x.intProp = 1; } @@ -118,3 +125,7 @@ void f11(int a, id<P0> x, id<P1> y) { void f12(int a, A<P0> *x, A<P1> *y) { A<P1>* l0 = (a ? x : y ); // expected-warning {{incompatible pointer types initializing 'A<P1> *' with an expression of type 'A<P0> *'}} } + +void f13(int a, B<P3, P0> *x, E<P0, P4> *y) { + int *ip = a ? x : y; // expected-warning{{expression of type 'A<P1> *'}} +} diff --git a/test/SemaObjC/interface-1.m b/test/SemaObjC/interface-1.m index 79fbad8ba4bf..0e47fa08bd77 100644 --- a/test/SemaObjC/interface-1.m +++ b/test/SemaObjC/interface-1.m @@ -3,7 +3,7 @@ @interface NSWhatever : NSObject // expected-error {{cannot find interface declaration for 'NSObject'}} -<NSCopying> // expected-error {{cannot find protocol declaration for 'NSCopying'}} +<NSCopying> // expected-error {{no type or protocol named 'NSCopying'}} @end diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m new file mode 100644 index 000000000000..b19e42372078 --- /dev/null +++ b/test/SemaObjC/kindof.m @@ -0,0 +1,304 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only %s -verify + +// Tests Objective-C 'kindof' types. + +#if !__has_feature(objc_kindof) +#error does not support __kindof +#endif + +@protocol NSObject +@end + +@protocol NSCopying +- (id)copy; ++ (Class)classCopy; +@end + +@protocol NSRandomProto +- (void)randomMethod; ++ (void)randomClassMethod; +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +- (NSObject *)retain; +@end + +@interface NSString : NSObject <NSCopying> +- (NSString *)stringByAppendingString:(NSString *)string; ++ (instancetype)string; +@end + +@interface NSMutableString : NSString +- (void)appendString:(NSString *)string; +@end + +@interface NSNumber : NSObject <NSCopying> +- (NSNumber *)numberByAddingNumber:(NSNumber *)number; +@end + +// --------------------------------------------------------------------------- +// Parsing and semantic analysis for __kindof +// --------------------------------------------------------------------------- + +// Test proper application of __kindof. +typedef __kindof NSObject *typedef1; +typedef NSObject __kindof *typedef2; +typedef __kindof NSObject<NSCopying> typedef3; +typedef NSObject<NSCopying> __kindof *typedef4; +typedef __kindof id<NSCopying> typedef5; +typedef __kindof Class<NSCopying> typedef6; + +// Test redundancy of __kindof. +typedef __kindof id __kindof redundant_typedef1; +typedef __kindof NSObject __kindof *redundant_typedef2; + +// Test application of __kindof to typedefs. +typedef NSObject *NSObject_ptr_typedef; +typedef NSObject NSObject_typedef; +typedef __kindof NSObject_ptr_typedef typedef_typedef1; +typedef __kindof NSObject_typedef typedef_typedef2; + +// Test application of __kindof to non-object types. +typedef __kindof int nonobject_typedef1; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'int'}} +typedef NSObject **NSObject_ptr_ptr; +typedef __kindof NSObject_ptr_ptr nonobject_typedef2; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'NSObject_ptr_ptr' (aka 'NSObject **')}} + +// Test application of __kindof outside of the decl-specifiers. +typedef NSObject * __kindof bad_specifier_location1; // expected-error{{'__kindof' type specifier must precede the declarator}} +typedef NSObject bad_specifier_location2 __kindof; // expected-error{{expected ';' after top level declarator}} +// expected-warning@-1{{declaration does not declare anything}} + +// --------------------------------------------------------------------------- +// Pretty printing of __kindof +// --------------------------------------------------------------------------- +void test_pretty_print(int *ip) { + __kindof NSObject *kindof_NSObject; + ip = kindof_NSObject; // expected-warning{{from '__kindof NSObject *'}} + + __kindof NSObject_ptr_typedef kindof_NSObject_ptr; + ip = kindof_NSObject_ptr; // expected-warning{{from '__kindof NSObject_ptr_typedef'}} + + __kindof id <NSCopying> *kindof_NSCopying; + ip = kindof_NSCopying; // expected-warning{{from '__kindof id<NSCopying> *'}} + + __kindof NSObject_ptr_typedef *kindof_NSObject_ptr_typedef; + ip = kindof_NSObject_ptr_typedef; // expected-warning{{from '__kindof NSObject_ptr_typedef *'}} +} + +// --------------------------------------------------------------------------- +// Basic implicit conversions (dropping __kindof, upcasts, etc.) +// --------------------------------------------------------------------------- +void test_add_remove_kindof_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + + // Conversion back and forth + kindof_NSObject_obj = NSObject_obj; + NSObject_obj = kindof_NSObject_obj; + + // Qualified-id conversion back and forth. + __kindof id <NSCopying> kindof_id_NSCopying_obj; + id <NSCopying> id_NSCopying_obj; + kindof_id_NSCopying_obj = id_NSCopying_obj; + id_NSCopying_obj = kindof_id_NSCopying_obj; +} + +void test_upcast_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + + // Upcasts + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + kindof_NSObject_obj = kindof_NSString_obj; + kindof_NSObject_obj = NSString_obj; + NSObject_obj = kindof_NSString_obj; + NSObject_obj = NSString_obj; + + // "Upcasts" with qualified-id. + __kindof id <NSCopying> kindof_id_NSCopying_obj; + id <NSCopying> id_NSCopying_obj; + kindof_id_NSCopying_obj = kindof_NSString_obj; + kindof_id_NSCopying_obj = NSString_obj; + id_NSCopying_obj = kindof_NSString_obj; + id_NSCopying_obj = NSString_obj; +} + + +void test_ptr_object_conversions(void) { + __kindof NSObject **ptr_kindof_NSObject_obj; + NSObject **ptr_NSObject_obj; + + // Conversions back and forth. + ptr_kindof_NSObject_obj = ptr_NSObject_obj; + ptr_NSObject_obj = ptr_kindof_NSObject_obj; + + // Conversions back and forth with qualified-id. + __kindof id <NSCopying> *ptr_kindof_id_NSCopying_obj; + id <NSCopying> *ptr_id_NSCopying_obj; + ptr_kindof_id_NSCopying_obj = ptr_id_NSCopying_obj; + ptr_id_NSCopying_obj = ptr_kindof_id_NSCopying_obj; + + // Upcasts. + __kindof NSString **ptr_kindof_NSString_obj; + NSString **ptr_NSString_obj; + ptr_kindof_NSObject_obj = ptr_kindof_NSString_obj; + ptr_kindof_NSObject_obj = ptr_NSString_obj; + ptr_NSObject_obj = ptr_kindof_NSString_obj; + ptr_NSObject_obj = ptr_NSString_obj; +} + +// --------------------------------------------------------------------------- +// Implicit downcasting +// --------------------------------------------------------------------------- +void test_downcast_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + + // Implicit downcasting. + kindof_NSString_obj = kindof_NSObject_obj; + kindof_NSString_obj = NSObject_obj; // expected-warning{{assigning to '__kindof NSString *' from 'NSObject *'}} + NSString_obj = kindof_NSObject_obj; + NSString_obj = NSObject_obj; // expected-warning{{assigning to 'NSString *' from 'NSObject *'}} + + // Implicit downcasting with qualified id. + __kindof id <NSCopying> kindof_NSCopying_obj; + id <NSCopying> NSCopying_obj; + kindof_NSString_obj = kindof_NSCopying_obj; + kindof_NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + NSString_obj = kindof_NSCopying_obj; + NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + kindof_NSObject_obj = kindof_NSCopying_obj; + kindof_NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + NSObject_obj = kindof_NSCopying_obj; + NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} +} + +void test_crosscast_conversions(void) { + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + __kindof NSNumber *kindof_NSNumber_obj; + NSNumber *NSNumber_obj; + + NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}} +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- +void test_block_conversions(void) { + // Adding/removing __kindof from return type. + __kindof NSString *(^kindof_NSString_void_block)(void); + NSString *(^NSString_void_block)(void); + kindof_NSString_void_block = NSString_void_block; + NSString_void_block = kindof_NSString_void_block; + + // Covariant return type. + __kindof NSMutableString *(^kindof_NSMutableString_void_block)(void); + NSMutableString *(^NSMutableString_void_block)(void); + kindof_NSString_void_block = NSMutableString_void_block; + NSString_void_block = kindof_NSMutableString_void_block; + kindof_NSString_void_block = NSMutableString_void_block; + NSString_void_block = kindof_NSMutableString_void_block; + + // "Covariant" return type via downcasting rule. + kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} + NSMutableString_void_block = kindof_NSString_void_block; + kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} + NSMutableString_void_block = kindof_NSString_void_block; + + // Cross-casted return type. + __kindof NSNumber *(^kindof_NSNumber_void_block)(void); + NSNumber *(^NSNumber_void_block)(void); + kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} + NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} + kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} + NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} + + // Adding/removing __kindof from argument type. + void (^void_kindof_NSString_block)(__kindof NSString *); + void (^void_NSString_block)(NSString *); + void_kindof_NSString_block = void_NSString_block; + void_NSString_block = void_kindof_NSString_block; + + // Contravariant argument type. + void (^void_kindof_NSMutableString_block)(__kindof NSMutableString *); + void (^void_NSMutableString_block)(NSMutableString *); + void_kindof_NSMutableString_block = void_kindof_NSString_block; + void_kindof_NSMutableString_block = void_NSString_block; + void_NSMutableString_block = void_kindof_NSString_block; + void_NSMutableString_block = void_NSString_block; + + // "Contravariant" argument type via downcasting rule. + void_kindof_NSString_block = void_kindof_NSMutableString_block; + void_kindof_NSString_block = void_NSMutableString_block; + void_NSString_block = void_kindof_NSMutableString_block; // expected-error{{from 'void (^)(__kindof NSMutableString *)'}} + void_NSString_block = void_NSMutableString_block; // expected-error{{from 'void (^)(NSMutableString *)'}} +} + +// --------------------------------------------------------------------------- +// Messaging __kindof types. +// --------------------------------------------------------------------------- +void message_kindof_object(__kindof NSString *kindof_NSString) { + [kindof_NSString retain]; // in superclass + [kindof_NSString stringByAppendingString:0]; // in class + [kindof_NSString appendString:0]; // in subclass + [kindof_NSString numberByAddingNumber: 0]; // FIXME: in unrelated class + [kindof_NSString randomMethod]; // in protocol +} + +void message_kindof_qualified_id(__kindof id <NSCopying> kindof_NSCopying) { + [kindof_NSCopying copy]; // in protocol + [kindof_NSCopying stringByAppendingString:0]; // in some class + [kindof_NSCopying randomMethod]; // in unrelated protocol +} + +void message_kindof_qualified_class( + __kindof Class <NSCopying> kindof_NSCopying) { + [kindof_NSCopying classCopy]; // in protocol + [kindof_NSCopying string]; // in some class + [kindof_NSCopying randomClassMethod]; // in unrelated protocol +} + +// --------------------------------------------------------------------------- +// __kindof within specialized types +// --------------------------------------------------------------------------- +@interface NSArray<T> : NSObject +@end + +void implicit_convert_array(NSArray<__kindof NSString *> *kindofStringsArray, + NSArray<NSString *> *stringsArray, + NSArray<__kindof NSMutableString *> + *kindofMutStringsArray, + NSArray<NSMutableString *> *mutStringsArray) { + // Adding/removing __kindof is okay. + kindofStringsArray = stringsArray; + stringsArray = kindofStringsArray; + + // Other covariant and contravariant conversions still not permitted. + kindofStringsArray = mutStringsArray; // expected-warning{{incompatible pointer types}} + stringsArray = kindofMutStringsArray; // expected-warning{{incompatible pointer types}} + mutStringsArray = kindofStringsArray; // expected-warning{{incompatible pointer types}} + + // Adding/removing nested __kindof is okay. + NSArray<NSArray<__kindof NSString *> *> *kindofStringsArrayArray; + NSArray<NSArray<NSString *> *> *stringsArrayArray; + kindofStringsArrayArray = stringsArrayArray; + stringsArrayArray = kindofStringsArrayArray; +} + +// --------------------------------------------------------------------------- +// __kindof + nullability +// --------------------------------------------------------------------------- + +void testNullability() { + // The base type being a pointer type tickles the bug. + extern __kindof id <NSCopying> _Nonnull getSomeCopyable(); + NSString *string = getSomeCopyable(); // no-warning + + void processCopyable(__typeof(getSomeCopyable()) string); + processCopyable(0); // expected-warning{{null passed to a callee that requires a non-null argument}} +} diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m index 673a7417e384..232f8dd794d6 100644 --- a/test/SemaObjC/objc2-merge-gc-attribue-decl.m +++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m @@ -13,17 +13,17 @@ extern __strong id CFRunLoopGetMain(); extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}} extern id WLoopGetMain(); // expected-error {{conflicting types for 'WLoopGetMain'}} -extern id p3; // expected-note {{previous definition is here}} -extern __weak id p3; // expected-error {{redefinition of 'p3' with a different type}} +extern id p3; // expected-note {{previous declaration is here}} +extern __weak id p3; // expected-error {{redeclaration of 'p3' with a different type}} -extern void *p4; // expected-note {{previous definition is here}} -extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}} +extern void *p4; // expected-note {{previous declaration is here}} +extern void * __strong p4; // expected-error {{redeclaration of 'p4' with a different type}} extern id p5; extern __strong id p5; -extern char* __strong p6; // expected-note {{previous definition is here}} -extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} +extern char* __strong p6; // expected-note {{previous declaration is here}} +extern char* p6; // expected-error {{redeclaration of 'p6' with a different type}} -extern __strong char* p7; // expected-note {{previous definition is here}} -extern char* p7; // expected-error {{redefinition of 'p7' with a different type}} +extern __strong char* p7; // expected-note {{previous declaration is here}} +extern char* p7; // expected-error {{redeclaration of 'p7' with a different type}} diff --git a/test/SemaObjC/parameterized_classes.m b/test/SemaObjC/parameterized_classes.m new file mode 100644 index 000000000000..644fe3a329af --- /dev/null +++ b/test/SemaObjC/parameterized_classes.m @@ -0,0 +1,357 @@ +// RUN: %clang_cc1 -fblocks %s -verify + +#if !__has_feature(objc_generics) +# error Compiler does not support Objective-C generics? +#endif + +#if !__has_feature(objc_generics_variance) +# error Compiler does not support co- and contr-variance? +#endif + +@protocol NSObject // expected-note{{'NSObject' declared here}} +@end + +@protocol NSCopying // expected-note{{'NSCopying' declared here}} +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> // expected-note{{'NSObject' defined here}} +@end + +@interface NSString : NSObject <NSCopying> +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized classes. +// -------------------------------------------------------------------------- + +// Parse type parameters with a bound +@interface PC1<T, U : NSObject*> : NSObject // expected-note{{'PC1' declared here}} +// expected-note@-1{{type parameter 'T' declared here}} +// expected-note@-2{{type parameter 'U' declared here}} +// expected-note@-3{{type parameter 'U' declared here}} +@end + +// Parse a type parameter with a bound that terminates in '>>'. +@interface PC2<T : id<NSObject>> : NSObject +@end + +// Parse multiple type parameters. +@interface PC3<T, U : id> : NSObject +@end + +// Parse multiple type parameters--grammatically ambiguous with protocol refs. +@interface PC4<T, U, V> : NSObject // expected-note 2{{'PC4' declared here}} +@end + +// Parse a type parameter list without a superclass. +@interface PC5<T : id> +@end + +// Parse a type parameter with name conflicts. +@interface PC6<T, U, + T> : NSObject // expected-error{{redeclaration of type parameter 'T'}} +@end + +// Parse Objective-C protocol references. +@interface PC7<T> // expected-error{{cannot find protocol declaration for 'T'}} +@end + +// Parse both type parameters and protocol references. +@interface PC8<T> : NSObject <NSObject> +@end + +// Type parameters with improper bounds. +@interface PC9<T : int, // expected-error{{type bound 'int' for type parameter 'T' is not an Objective-C pointer type}} + U : NSString> : NSObject // expected-error{{missing '*' in type bound 'NSString' for type parameter 'U'}} +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized forward declarations classes. +// -------------------------------------------------------------------------- + +// Okay: forward declaration without type parameters. +@class PC10; + +// Okay: forward declarations with type parameters. +@class PC10<T, U : NSObject *>, PC11<T : NSObject *, U : id>; // expected-note{{type parameter 'T' declared here}} + +// Okay: forward declaration without type parameters following ones +// with type parameters. +@class PC10, PC11; + +// Okay: definition of class with type parameters that was formerly +// declared with the same type parameters. +@interface PC10<T, U : NSObject *> : NSObject +@end + +// Mismatched parameters in declaration of @interface following @class. +@interface PC11<T, U> : NSObject // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @interface}} +@end + +@interface PC12<T : NSObject *> : NSObject // expected-note{{type parameter 'T' declared here}} +@end + +@class PC12; + +// Mismatched parameters in subsequent forward declarations. +@class PC13<T : NSObject *>; // expected-note{{type parameter 'T' declared here}} +@class PC13; +@class PC13<U>; // expected-error{{missing type bound 'NSObject *' for type parameter 'U' in @class}} + +// Mismatch parameters in declaration of @class following @interface. +@class PC12<T>; // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @class}} + +// Parameterized forward declaration a class that is not parameterized. +@class NSObject<T>; // expected-error{{forward declaration of non-parameterized class 'NSObject' cannot have type parameters}} +// expected-note@-1{{'NSObject' declared here}} + +// Parameterized forward declaration preceding the definition (that is +// not parameterized). +@class NSNumber<T : NSObject *>; // expected-note{{'NSNumber' declared here}} +@interface NSNumber : NSObject // expected-error{{class 'NSNumber' previously declared with type parameters}} +@end + +@class PC14; + +// Okay: definition of class with type parameters that was formerly +// declared without type parameters. +@interface PC14<T, U : NSObject *> : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized categories and extensions. +// -------------------------------------------------------------------------- + +// Inferring type bounds +@interface PC1<T, U> (Cat1) <NSObject> +@end + +// Matching type bounds +@interface PC1<T : id, U : NSObject *> (Cat2) <NSObject> +@end + +// Inferring type bounds +@interface PC1<T, U> () <NSObject> +@end + +// Matching type bounds +@interface PC1<T : id, U : NSObject *> () <NSObject> +@end + +// Missing type parameters. +@interface PC1<T> () // expected-error{{extension has too few type parameters (expected 2, have 1)}} +@end + +// Extra type parameters. +@interface PC1<T, U, V> (Cat3) // expected-error{{category has too many type parameters (expected 2, have 3)}} +@end + +// Mismatched bounds. +@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id'}} + X : id> () // expected-error{{type bound 'id' for type parameter 'X' conflicts with previous bound 'NSObject *'for type parameter 'U'}} +@end + +// Parameterized category/extension of non-parameterized class. +@interface NSObject<T> (Cat1) // expected-error{{category of non-parameterized class 'NSObject' cannot have type parameters}} +@end + +@interface NSObject<T> () // expected-error{{extension of non-parameterized class 'NSObject' cannot have type parameters}} +@end + +// -------------------------------------------------------------------------- +// @implementations cannot have type parameters +// -------------------------------------------------------------------------- +@implementation PC1<T : id> // expected-error{{@implementation cannot have type parameters}} +@end + +@implementation PC2<T> // expected-error{{@implementation declaration cannot be protocol qualified}} +@end + +@implementation PC1<T> (Cat1) // expected-error{{@implementation cannot have type parameters}} +@end + +@implementation PC1<T : id> (Cat2) // expected-error{{@implementation cannot have type parameters}} +@end + +// -------------------------------------------------------------------------- +// Interfaces involving type parameters +// -------------------------------------------------------------------------- +@interface PC20<T : id, U : NSObject *, V : NSString *> : NSObject { + T object; +} + +- (U)method:(V)param; +@end + +@interface PC20<T, U, V> (Cat1) +- (U)catMethod:(V)param; +@end + +@interface PC20<X, Y, Z>() +- (X)extMethod:(Y)param; +@end + +// -------------------------------------------------------------------------- +// Parsing type arguments. +// -------------------------------------------------------------------------- + +typedef NSString * ObjCStringRef; // expected-note{{'ObjCStringRef' declared here}} + +// Type arguments with a mix of identifiers and type-names. +typedef PC4<id, NSObject *, NSString *> typeArgs1; + +// Type arguments with only identifiers. +typedef PC4<id, id, id> typeArgs2; + +// Type arguments with only identifiers; one is ambiguous (resolved as +// types). +typedef PC4<NSObject, id, id> typeArgs3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type arguments with only identifiers; one is ambiguous (resolved as +// protocol qualifiers). +typedef PC4<NSObject, NSCopying> protocolQuals1; + +// Type arguments and protocol qualifiers. +typedef PC4<id, NSObject *, id><NSObject, NSCopying> typeArgsAndProtocolQuals1; + +// Type arguments and protocol qualifiers in the wrong order. +typedef PC4<NSObject, NSCopying><id, NSObject *, id> typeArgsAndProtocolQuals2; // expected-error{{protocol qualifiers must precede type arguments}} + +// Type arguments and protocol qualifiers (identifiers). +typedef PC4<id, NSObject, id><NSObject, NSCopying> typeArgsAndProtocolQuals3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: protocol bias. +typedef PC4<NSCopying, NSObjec> protocolQuals2; // expected-error{{cannot find protocol declaration for 'NSObjec'; did you mean 'NSObject'?}} + +// Typo correction: type bias. +typedef PC4<id, id, NSObjec> typeArgs4; // expected-error{{unknown class name 'NSObjec'; did you mean 'NSObject'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: bias set by correction itself to a protocol. +typedef PC4<NSObject, NSObject, NSCopyin> protocolQuals3; // expected-error{{cannot find protocol declaration for 'NSCopyin'; did you mean 'NSCopying'?}} + +// Typo correction: bias set by correction itself to a type. +typedef PC4<NSObject, NSObject, ObjCStringref> typeArgs5; // expected-error{{unknown type name 'ObjCStringref'; did you mean 'ObjCStringRef'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} +// expected-error@-2{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type/protocol conflict. +typedef PC4<NSCopying, ObjCStringRef> typeArgsProtocolQualsConflict1; // expected-error{{angle brackets contain both a type ('ObjCStringRef') and a protocol ('NSCopying')}} + +// Handling the '>>' in type argument lists. +typedef PC4<id<NSCopying>, NSObject *, id<NSObject>> typeArgs6; + +// -------------------------------------------------------------------------- +// Checking type arguments. +// -------------------------------------------------------------------------- + +@interface PC15<T : id, U : NSObject *, V : id<NSCopying>> : NSObject +// expected-note@-1{{type parameter 'V' declared here}} +// expected-note@-2{{type parameter 'V' declared here}} +// expected-note@-3{{type parameter 'U' declared here}} +@end + +typedef PC4<NSString *> tooFewTypeArgs1; // expected-error{{too few type arguments for class 'PC4' (have 1, expected 3)}} + +typedef PC4<NSString *, NSString *, NSString *, NSString *> tooManyTypeArgs1; // expected-error{{too many type arguments for class 'PC4' (have 4, expected 3)}} + +typedef PC15<int (^)(int, int), // block pointers as 'id' + NSString *, // subclass + NSString *> typeArgs7; // class that conforms to the protocol + +typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8; + +typedef PC15<NSObject *, NSObject *, + NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + id, // expected-error{{type argument 'id' does not satisfy the bound ('NSObject *') of type parameter 'U'}} + id> typeArgs9; + +typedef PC15<id, NSObject *, + id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + int (^)(int, int), // okay + id<NSCopying, NSObject>> typeArgs11; + +typedef PC15<id, NSString *, int (^)(int, int)> typeArgs12; // okay + +typedef NSObject<id, id> typeArgs13; // expected-error{{type arguments cannot be applied to non-parameterized class 'NSObject'}} + +typedef id<id, id> typeArgs14; // expected-error{{type arguments cannot be applied to non-class type 'id'}} + +typedef PC1<NSObject *, NSString *> typeArgs15; + +typedef PC1<NSObject *, NSString *><NSCopying> typeArgsAndProtocolQuals4; + +typedef typeArgs15<NSCopying> typeArgsAndProtocolQuals5; + +typedef typeArgs15<NSObject *, NSString *> typeArgs16; // expected-error{{type arguments cannot be applied to already-specialized class type 'typeArgs15' (aka 'PC1<NSObject *,NSString *>')}} + +typedef typeArgs15<NSObject> typeArgsAndProtocolQuals6; + +void testSpecializedTypePrinting() { + int *ip; + + ip = (typeArgs15*)0; // expected-warning{{'typeArgs15 *' (aka 'PC1<NSObject *,NSString *> *')}} + ip = (typeArgsAndProtocolQuals4*)0; // expected-warning{{'typeArgsAndProtocolQuals4 *' (aka 'PC1<NSObject *,NSString *><NSCopying> *')}} + ip = (typeArgsAndProtocolQuals5*)0; // expected-warning{{'typeArgsAndProtocolQuals5 *' (aka 'typeArgs15<NSCopying> *')}} + ip = (typeArgsAndProtocolQuals6)0; // expected-error{{used type 'typeArgsAndProtocolQuals6' (aka 'typeArgs15<NSObject>')}} + ip = (typeArgsAndProtocolQuals6*)0;// expected-warning{{'typeArgsAndProtocolQuals6 *' (aka 'typeArgs15<NSObject> *')}} +} + +// -------------------------------------------------------------------------- +// Specialized superclasses +// -------------------------------------------------------------------------- +@interface PC21<T : NSObject *> : PC1<T, T> +@end + +@interface PC22<T : NSObject *> : PC1<T> // expected-error{{too few type arguments for class 'PC1' (have 1, expected 2)}} +@end + +@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}} +@end + +@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}} +@end + +@interface NSFoo : PC1<NSObject *, NSObject *> // okay +@end + +// -------------------------------------------------------------------------- +// Co- and contra-variance. +// -------------------------------------------------------------------------- +@class Variance1<T, U>; + +@class Variance1<__covariant T, __contravariant U>; + +@interface Variance1<__covariant T, __contravariant U> : NSObject // expected-note 2{{declared here}} +@end + +@interface Variance1<T, U> () // okay, inferred +@end + +@interface Variance1<T, U> (Cat1) // okay, inferred +@end + +@class Variance1<T, U>; // okay, inferred + +@interface Variance1<__covariant T, __contravariant U> () // okay, matches +@end + +@interface Variance1<__covariant T, __contravariant U> (Cat2) // okay, matches +@end + +@class Variance1<__covariant T, __contravariant U>; // okay, matches + +@interface Variance1<__contravariant X, // expected-error{{contravariant type parameter 'X' conflicts with previous covariant type parameter 'T'}} + __covariant Y> () // expected-error{{covariant type parameter 'Y' conflicts with previous contravariant type parameter 'U'}} +@end + +@class Variance2<__covariant T, __contravariant U>; // expected-note 2{{declared here}} + +@interface Variance2<__contravariant T, // expected-error{{contravariant type parameter 'T' conflicts with previous covariant type parameter 'T'}} + U> : NSObject // expected-error{{invariant type parameter 'U' conflicts with previous contravariant type parameter 'U'}} +@end diff --git a/test/SemaObjC/parameterized_classes_collection_literal.m b/test/SemaObjC/parameterized_classes_collection_literal.m new file mode 100644 index 000000000000..472746e09db9 --- /dev/null +++ b/test/SemaObjC/parameterized_classes_collection_literal.m @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s + +#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 +typedef unsigned long NSUInteger; +#else +typedef unsigned int NSUInteger; +#endif + +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSNumber : NSObject <NSCopying> ++ (NSNumber *)numberWithInt:(int)value; +@end + +@interface NSArray<T> : NSObject <NSCopying> ++ (instancetype)arrayWithObjects:(const T [])objects count:(NSUInteger)cnt; +@end + +@interface NSDictionary<K, V> : NSObject <NSCopying> ++ (instancetype)dictionaryWithObjects:(const V [])objects forKeys:(const K [])keys count:(NSUInteger)cnt; +@end + +void testArrayLiteral(void) { + NSArray<NSString *> *array1 = @[@"hello", + @1, // expected-warning{{of type 'NSNumber *' is not compatible with array element type 'NSString *'}} + @"world", + @[@1, @2]]; // expected-warning{{of type 'NSArray *' is not compatible with array element type 'NSString *'}} + + NSArray<NSArray<NSString *> *> *array2 = @[@[@"hello", @"world"], + @"blah", // expected-warning{{object of type 'NSString *' is not compatible with array element type 'NSArray<NSString *> *'}} + @[@1]]; // expected-warning{{object of type 'NSNumber *' is not compatible with array element type 'NSString *'}} +} + +void testDictionaryLiteral(void) { + NSDictionary<NSString *, NSNumber *> *dict1 = @{ + @"hello" : @17, + @18 : @18, // expected-warning{{object of type 'NSNumber *' is not compatible with dictionary key type 'NSString *'}} + @"world" : @"blah" // expected-warning{{object of type 'NSString *' is not compatible with dictionary value type 'NSNumber *'}} + }; +} diff --git a/test/SemaObjC/parameterized_classes_subst.m b/test/SemaObjC/parameterized_classes_subst.m new file mode 100644 index 000000000000..f90ee9093592 --- /dev/null +++ b/test/SemaObjC/parameterized_classes_subst.m @@ -0,0 +1,428 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify +// +// Test the substitution of type arguments for type parameters when +// using parameterized classes in Objective-C. + +@protocol NSObject +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> ++ (instancetype)alloc; +- (instancetype)init; +@end + +@protocol NSCopying +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableString : NSString +@end + +@interface NSNumber : NSObject <NSCopying> +@end + +@interface NSArray<T> : NSObject <NSCopying> { +@public + T *data; // don't try this at home +} +- (T)objectAtIndexedSubscript:(int)index; ++ (NSArray<T> *)array; ++ (void)setArray:(NSArray <T> *)array; +@property (copy,nonatomic) T lastObject; +@end + +@interface NSMutableArray<T> : NSArray<T> +-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}} +- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}} +@end + +@interface NSStringArray : NSArray<NSString *> +@end + +@interface NSSet<T> : NSObject <NSCopying> +- (T)firstObject; +@property (nonatomic, copy) NSArray<T> *allObjects; +@end + +// Parameterized inheritance (simple case) +@interface NSMutableSet<U : id<NSCopying>> : NSSet<U> +- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} +@end + +@interface Widget : NSObject <NSCopying> +@end + +// Non-parameterized class inheriting from a specialization of a +// parameterized class. +@interface WidgetSet : NSMutableSet<Widget *> +@end + +// Parameterized inheritance with a more interesting transformation in +// the specialization. +@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*> +@end + +// Inheriting from an unspecialized form of a parameterized type. +@interface UntypedMutableSet : NSMutableSet +@end + +@interface Window : NSObject +@end + +@interface NSDictionary<K, V> : NSObject <NSCopying> +- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} +@end + +@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> +- (void)setObject:(V)object forKeyedSubscript:(K)key; +// expected-note@-1 {{parameter 'object' here}} +// expected-note@-2 {{parameter 'object' here}} +// expected-note@-3 {{parameter 'key' here}} +// expected-note@-4 {{parameter 'key' here}} + +@property (strong) K someRandomKey; +@end + +@interface WindowArray : NSArray<Window *> +@end + +@interface NSSet<T> (Searching) +- (T)findObject:(T)object; +@end + +@interface NSView : NSObject +@end + +@interface NSControl : NSView +- (void)toggle; +@end + +@interface NSViewController<ViewType : NSView *> : NSObject +@property (nonatomic,retain) ViewType view; +@end + +// -------------------------------------------------------------------------- +// Nullability +// -------------------------------------------------------------------------- +typedef NSControl * _Nonnull Nonnull_NSControl; + +@interface NSNullableTest<ViewType : NSView *> : NSObject +- (ViewType)view; +- (nullable ViewType)maybeView; +@end + +@interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}} +@end + +void test_nullability(void) { + NSControl * _Nonnull nonnull_NSControl; + + // Nullability introduced by substitution. + NSNullableTest<NSControl *> *unspecifiedControl; + nonnull_NSControl = [unspecifiedControl view]; + nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}} + + // Nullability overridden by substitution. + NSNullableTest<Nonnull_NSControl> *nonnullControl; + nonnull_NSControl = [nonnullControl view]; + nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}} + + // Nullability cannot be specified directly on a type argument. + NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}} +} + +// -------------------------------------------------------------------------- +// Message sends. +// -------------------------------------------------------------------------- +void test_message_send_result( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSArray<NSString *> *stringArray, + NSArray<__kindof NSString *> *kindofStringArray, + void (^block)(void)) { + int *ip; + ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}} + ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}} + ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}} + ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}} + ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = [set firstObject]; // expected-warning{{from 'id'}} + ip = [mutSet firstObject]; // expected-warning{{from 'id'}} + ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}} + ip = [block firstObject]; // expected-warning{{from 'id'}} + + ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}} + + // Class messages. + ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}} + ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}} + ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}} + ip = [MutableSetOfArrays alloc]; // expected-warning{{from 'MutableSetOfArrays *'}} + ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = [[NSMutableArray<NSString *> alloc] init]; // expected-warning{{from 'NSMutableArray<NSString *> *'}} + + [[NSMutableArray alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}} + + ip = [[[NSViewController alloc] init] view]; // expected-warning{{from '__kindof NSView *'}} + [[[[NSViewController alloc] init] view] toggle]; + + NSMutableString *mutStr = kindofStringArray[0]; + NSNumber *number = kindofStringArray[0]; // expected-warning{{of type '__kindof NSString *'}} +} + +void test_message_send_param( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + void (^block)(void)) { + Window *window; + + [mutStringSet addObject: window]; // expected-warning{{parameter of type 'NSString *'}} + [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}} + [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}} + [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Property accesses. +// -------------------------------------------------------------------------- +void test_property_read( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + ip = stringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}} + ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}} + ip = set.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}} + + ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}} + + ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}} +} + +void test_property_write( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + + mutStringSet.allObjects = ip; // expected-warning{{to 'NSArray<NSString *> *'}} + widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}} + untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}} + mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + + mutDict.someRandomKey = ip; // expected-warning{{to 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Subscripting +// -------------------------------------------------------------------------- +void test_subscripting( + NSArray<NSString *> *stringArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray, + NSDictionary<NSString *, Widget *> *stringWidgetDict, + NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, + NSDictionary *dict, + NSMutableDictionary *mutDict) { + int *ip; + NSString *string; + Widget *widget; + Window *window; + + ip = stringArray[0]; // expected-warning{{from 'NSString *'}} + + ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}} + mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}} + + ip = array[0]; // expected-warning{{from 'id'}} + + ip = mutArray[0]; // expected-warning{{from 'id'}} + mutArray[0] = ip; // expected-warning{{parameter of type 'id'}} + + ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}} + widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} + + ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}} + widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} + mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}} + mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}} + + ip = dict[string]; // expected-warning{{from 'id'}} + + ip = mutDict[string]; // expected-warning{{from 'id'}} + mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}} + + widget = mutDict[window]; + mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Instance variable access. +// -------------------------------------------------------------------------- +void test_instance_variable(NSArray<NSString *> *stringArray, + NSArray *array) { + int *ip; + + ip = stringArray->data; // expected-warning{{from 'NSString **'}} + ip = array->data; // expected-warning{{from 'id *'}} +} + +@implementation WindowArray +- (void)testInstanceVariable { + int *ip; + + ip = data; // expected-warning{{from 'Window **'}} +} +@end + +// -------------------------------------------------------------------------- +// Implicit conversions. +// -------------------------------------------------------------------------- +void test_implicit_conversions(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray) { + // Specialized -> unspecialized (same level) + array = stringArray; + + // Unspecialized -> specialized (same level) + stringArray = array; + + // Specialized -> specialized failure (same level). + stringArray = numberArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}} + + // Specialized -> specialized (different levels). + stringArray = mutStringArray; + + // Specialized -> specialized failure (different levels). + numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}} + + // Unspecialized -> specialized (different levels). + stringArray = mutArray; + + // Specialized -> unspecialized (different levels). + array = mutStringArray; +} + +@interface NSCovariant1<__covariant T> +@end + +@interface NSContravariant1<__contravariant T> +@end + +void test_variance(NSCovariant1<NSString *> *covariant1, + NSCovariant1<NSMutableString *> *covariant2, + NSCovariant1<NSString *(^)(void)> *covariant3, + NSCovariant1<NSMutableString *(^)(void)> *covariant4, + NSCovariant1<id> *covariant5, + NSCovariant1<id<NSCopying>> *covariant6, + NSContravariant1<NSString *> *contravariant1, + NSContravariant1<NSMutableString *> *contravariant2) { + covariant1 = covariant2; // okay + covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} + + covariant3 = covariant4; // okay + covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)(void)> *' from 'NSCovariant1<NSString *(^)(void)> *'}} + + covariant5 = covariant1; // okay + covariant1 = covariant5; // okay: id is promiscuous + + covariant5 = covariant3; // okay + covariant3 = covariant5; // okay + + contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} + contravariant2 = contravariant1; // okay +} + +// -------------------------------------------------------------------------- +// Ternary operator +// -------------------------------------------------------------------------- +void test_ternary_operator(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSStringArray *stringArray2, + NSArray *array, + NSMutableArray *mutArray, + int cond) { + int *ip; + id object; + + ip = cond ? stringArray : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = cond ? stringArray : mutArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? stringArray2 : mutArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? mutArray : stringArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? mutArray : stringArray2; // expected-warning{{from 'NSArray *'}} + + object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} +} + +// -------------------------------------------------------------------------- +// super +// -------------------------------------------------------------------------- +@implementation NSStringArray +- (void)useSuperMethod { + int *ip; + ip = super.lastObject; // expected-warning{{from 'NSString *'}} + super.lastObject = ip; // expected-warning{{to 'NSString *'}} + ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}} +} + ++ (void)useSuperMethod { + int *ip; + ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}} + super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}} + ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}} +} +@end + +// -------------------------------------------------------------------------- +// warning about likely protocol/class name typos. +// -------------------------------------------------------------------------- +typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m index 788edf276d7b..f2f6025a5ad6 100644 --- a/test/SemaObjC/protocol-archane.m +++ b/test/SemaObjC/protocol-archane.m @@ -40,3 +40,7 @@ Class <SomeProtocol> UnfortunateGCCExtension; - (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}} } @end + +typedef <SomeProtocol> id TwoTypeSpecs; // expected-warning{{no object type specified}} +// expected-error@-1{{typedef redefinition with different types ('id<SomeProtocol>' vs 'id')}} +// expected-error@-2{{expected ';' after top level declarator}} diff --git a/test/SemaObjC/protocol-warn.m b/test/SemaObjC/protocol-warn.m index 2d042380582e..04df5031ab47 100644 --- a/test/SemaObjC/protocol-warn.m +++ b/test/SemaObjC/protocol-warn.m @@ -51,5 +51,5 @@ UIWebPDFView *getView() { UIWebBrowserView *browserView; UIWebPDFView *pdfView; - return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView<NSObject> *' from a function with result type 'UIWebPDFView *'}} + return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView *' from a function with result type 'UIWebPDFView *'}} } diff --git a/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h b/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h new file mode 100644 index 000000000000..9a51fa1e9903 --- /dev/null +++ b/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h @@ -0,0 +1,21 @@ +#pragma clang assume_nonnull begin + +__attribute__((objc_root_class)) +@interface B +@end + +@interface C : B +@end + +__attribute__((objc_root_class)) +@interface NSGeneric<T : B *> // expected-note{{type parameter 'T' declared here}} +- (T)tee; +- (nullable T)maybeTee; +@end + +typedef NSGeneric<C *> *Generic_with_C; + +#pragma clang assume_nonnull end + +@interface NSGeneric<T : C *>(Blah) // expected-error{{type bound 'C *' for type parameter 'T' conflicts with previous bound 'B *'}} +@end diff --git a/test/SemaObjCXX/nullability-pragmas.mm b/test/SemaObjCXX/nullability-pragmas.mm index dbf4f37f4019..817d056a14ac 100644 --- a/test/SemaObjCXX/nullability-pragmas.mm +++ b/test/SemaObjCXX/nullability-pragmas.mm @@ -2,6 +2,7 @@ #include "nullability-pragmas-1.h" #include "nullability-pragmas-2.h" +#include "nullability-pragmas-generics-1.h" #if !__has_feature(assume_nonnull) # error assume_nonnull feature is not set @@ -43,3 +44,14 @@ void test_pragmas_1(A * _Nonnull a, AA * _Nonnull aa) { ptr = aa->ivar1; // expected-error{{from incompatible type 'id'}} ptr = aa->ivar2; // expected-error{{from incompatible type 'id _Nonnull'}} } + +void test_pragmas_generics(void) { + float *fp; + + NSGeneric<C *> *genC; + fp = [genC tee]; // expected-error{{from incompatible type 'C *'}} + fp = [genC maybeTee]; // expected-error{{from incompatible type 'C * _Nullable'}} + + Generic_with_C genC2; + fp = genC2; // expected-error{{from incompatible type 'Generic_with_C' (aka 'NSGeneric<C *> *')}} +} diff --git a/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm index 7be5f17daa80..9166ba65b9fa 100644 --- a/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm +++ b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm @@ -35,17 +35,17 @@ extern ID CFRunLoopGetMain8(); extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}} extern id WLoopGetMain(); // expected-error {{functions that differ only in their return type cannot be overloaded}} -extern id p3; // expected-note {{previous definition is here}} -extern __weak id p3; // expected-error {{redefinition of 'p3' with a different type}} +extern id p3; // expected-note {{previous declaration is here}} +extern __weak id p3; // expected-error {{redeclaration of 'p3' with a different type}} -extern void *p4; // expected-note {{previous definition is here}} -extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}} +extern void *p4; // expected-note {{previous declaration is here}} +extern void * __strong p4; // expected-error {{redeclaration of 'p4' with a different type}} extern id p5; extern __strong id p5; -extern char* __strong p6; // expected-note {{previous definition is here}} -extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} +extern char* __strong p6; // expected-note {{previous declaration is here}} +extern char* p6; // expected-error {{redeclaration of 'p6' with a different type}} -extern __strong char* p7; // expected-note {{previous definition is here}} -extern char* p7; // expected-error {{redefinition of 'p7' with a different type}} +extern __strong char* p7; // expected-note {{previous declaration is here}} +extern char* p7; // expected-error {{redeclaration of 'p7' with a different type}} diff --git a/test/SemaObjCXX/parameterized_classes.mm b/test/SemaObjCXX/parameterized_classes.mm new file mode 100644 index 000000000000..48542634bdd9 --- /dev/null +++ b/test/SemaObjCXX/parameterized_classes.mm @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify + +// expected-no-diagnostics +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized classes. +// -------------------------------------------------------------------------- +@interface PC1<T, U, V> : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing type arguments. +// -------------------------------------------------------------------------- +typedef PC1<::NSString *, NSString *, id<NSCopying>> typeArgs1; diff --git a/test/SemaObjCXX/parameterized_classes_subst.mm b/test/SemaObjCXX/parameterized_classes_subst.mm new file mode 100644 index 000000000000..f342ac0224ce --- /dev/null +++ b/test/SemaObjCXX/parameterized_classes_subst.mm @@ -0,0 +1,440 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %s -verify +// +// Test the substitution of type arguments for type parameters when +// using parameterized classes in Objective-C. + +__attribute__((objc_root_class)) +@interface NSObject ++ (instancetype)alloc; +- (instancetype)init; +@end + +@protocol NSCopying +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableString : NSString +@end + +@interface NSNumber : NSObject <NSCopying> +@end + +@interface NSArray<T> : NSObject <NSCopying> { +@public + T *data; // don't try this at home +} +- (T)objectAtIndexedSubscript:(int)index; ++ (NSArray<T> *)array; +@property (copy,nonatomic) T lastObject; +@end + +@interface NSMutableArray<T> : NSArray<T> +-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}} +- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}} +@end + +@interface NSStringArray : NSArray<NSString *> +@end + +@interface NSSet<T> : NSObject <NSCopying> +- (T)firstObject; +@property (nonatomic, copy) NSArray<T> *allObjects; +@end + +// Parameterized inheritance (simple case) +@interface NSMutableSet<U : id<NSCopying>> : NSSet<U> +- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} +@end + +@interface Widget : NSObject <NSCopying> +@end + +// Non-parameterized class inheriting from a specialization of a +// parameterized class. +@interface WidgetSet : NSMutableSet<Widget *> +@end + +// Parameterized inheritance with a more interesting transformation in +// the specialization. +@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*> +@end + +// Inheriting from an unspecialized form of a parameterized type. +@interface UntypedMutableSet : NSMutableSet +@end + +@interface Window : NSObject +@end + +@interface NSDictionary<K, V> : NSObject <NSCopying> +- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} +@end + +@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> // expected-note 2{{type parameter 'K' declared here}} \ +// expected-note 2{{'NSMutableDictionary' declared here}} +- (void)setObject:(V)object forKeyedSubscript:(K)key; +// expected-note@-1 {{parameter 'object' here}} +// expected-note@-2 {{parameter 'object' here}} +// expected-note@-3 {{parameter 'key' here}} +// expected-note@-4 {{parameter 'key' here}} + +@property (strong) K someRandomKey; +@end + +@interface WindowArray : NSArray<Window *> +@end + +@interface NSSet<T> (Searching) +- (T)findObject:(T)object; +@end + + +// -------------------------------------------------------------------------- +// Message sends. +// -------------------------------------------------------------------------- +void test_message_send_result( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSArray<NSString *> *stringArray, + void (^block)(void)) { + int *ip; + ip = [stringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}} + ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}} + ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}} + ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}} + ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = [set firstObject]; // expected-error{{from incompatible type 'id'}} + ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}} + ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}} + ip = [block firstObject]; // expected-error{{from incompatible type 'id'}} + + ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}} + + // Class messages. + ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}} + ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}} + ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}} + ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}} + ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + + ip = [[NSMutableArray<NSString *> alloc] init]; // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}} + + [[NSMutableArray alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}} +} + +void test_message_send_param( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + void (^block)(void)) { + Window *window; + + [mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}} + [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}} + [untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} + [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}} + [mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} + [mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} + [block addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Property accesses. +// -------------------------------------------------------------------------- +void test_property_read( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}} + ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}} + ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + + ip = mutDict.someRandomKey; // expected-error{{from incompatible type '__kindof id<NSCopying>'}} +} + +void test_property_write( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + + mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}} + widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}} + untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}} + mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}} + + mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Subscripting +// -------------------------------------------------------------------------- +void test_subscripting( + NSArray<NSString *> *stringArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray, + NSDictionary<NSString *, Widget *> *stringWidgetDict, + NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, + NSDictionary *dict, + NSMutableDictionary *mutDict) { + int *ip; + NSString *string; + Widget *widget; + Window *window; + + ip = stringArray[0]; // expected-error{{from incompatible type 'NSString *'}} + + ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}} + mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}} + + ip = array[0]; // expected-error{{from incompatible type 'id'}} + + ip = mutArray[0]; // expected-error{{from incompatible type 'id'}} + mutArray[0] = ip; // expected-error{{parameter of type 'id'}} + + ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}} + widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}} + + ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}} + widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}} + mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}} + mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}} + + ip = dict[string]; // expected-error{{from incompatible type 'id'}} + + ip = mutDict[string]; // expected-error{{incompatible type 'id'}} + mutDict[string] = ip; // expected-error{{parameter of type 'id'}} + + widget = mutDict[window]; + mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Instance variable access. +// -------------------------------------------------------------------------- +void test_instance_variable(NSArray<NSString *> *stringArray, + NSArray *array) { + int *ip; + + ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}} + ip = array->data; // expected-error{{from incompatible type 'id *'}} +} + +@implementation WindowArray +- (void)testInstanceVariable { + int *ip; + + ip = data; // expected-error{{from incompatible type 'Window **'}} +} +@end + +// -------------------------------------------------------------------------- +// Implicit conversions. +// -------------------------------------------------------------------------- +void test_implicit_conversions(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray) { + // Specialized -> unspecialized (same level) + array = stringArray; + + // Unspecialized -> specialized (same level) + stringArray = array; + + // Specialized -> specialized failure (same level). + stringArray = numberArray; // expected-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}} + + // Specialized -> specialized (different levels). + stringArray = mutStringArray; + + // Specialized -> specialized failure (different levels). + numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}} + + // Unspecialized -> specialized (different levels). + stringArray = mutArray; + + // Specialized -> unspecialized (different levels). + array = mutStringArray; +} + +@interface NSCovariant1<__covariant T> +@end + +@interface NSContravariant1<__contravariant T> +@end + +void test_variance(NSCovariant1<NSString *> *covariant1, + NSCovariant1<NSMutableString *> *covariant2, + NSCovariant1<NSString *(^)(void)> *covariant3, + NSCovariant1<NSMutableString *(^)(void)> *covariant4, + NSCovariant1<id> *covariant5, + NSCovariant1<id<NSCopying>> *covariant6, + NSContravariant1<NSString *> *contravariant1, + NSContravariant1<NSMutableString *> *contravariant2) { + covariant1 = covariant2; // okay + covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} + + covariant3 = covariant4; // okay + covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)()> *' from 'NSCovariant1<NSString *(^)()> *'}} + + covariant5 = covariant1; // okay + covariant1 = covariant5; // okay: id is promiscuous + + covariant5 = covariant3; // okay + covariant3 = covariant5; // okay + + contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} + contravariant2 = contravariant1; // okay +} + +// -------------------------------------------------------------------------- +// Ternary operator +// -------------------------------------------------------------------------- +void test_ternary_operator(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSStringArray *stringArray2, + NSArray *array, + NSMutableArray *mutArray, + int cond) { + int *ip; + id object; + + ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + + ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + + ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}} + + ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}} + + ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}} + + ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}} + + object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} +} + +// -------------------------------------------------------------------------- +// super +// -------------------------------------------------------------------------- +@implementation NSStringArray +- (void)useSuperMethod { + int *ip; + ip = super.lastObject; // expected-error{{from incompatible type 'NSString *'}} + ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}} +} + ++ (void)useSuperMethod { + int *ip; + ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} + ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} +} +@end + +// -------------------------------------------------------------------------- +// Template instantiation +// -------------------------------------------------------------------------- +template<typename K, typename V> +struct NSMutableDictionaryOf { + typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}} +}; + +template<typename ...Args> +struct VariadicNSMutableDictionaryOf { + typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}} + // expected-error@-1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}} + // expected-error@-2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}} +}; + +void testInstantiation() { + int *ip; + + typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1; + Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}} + + typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}} +} + +void testVariadicInstantiation() { + int *ip; + + typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1; + Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}} + + typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}} + + typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}} + + typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}} +} + +// -------------------------------------------------------------------------- +// Parameterized classes are not templates +// -------------------------------------------------------------------------- +template<template<typename T, typename U> class TT> +struct AcceptsTemplateTemplate { }; + +typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}} + +template<typename T> +struct DependentTemplate { + typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} +}; + +struct NSMutableDictionaryBuilder { + typedef NSMutableDictionary apply; +}; + +typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}} + +template<typename K, typename V> +struct NonDependentTemplate { + typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} + // expected-error@-1{{expected member name or }} +}; + +// However, one can use an alias template to turn a parameterized +// class into a template. +template<typename K, typename V> +using NSMutableDictionaryAlias = NSMutableDictionary<K, V>; + +typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay + + diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp index 4c21d2585d32..7349fdf392d4 100644 --- a/test/SemaTemplate/injected-class-name.cpp +++ b/test/SemaTemplate/injected-class-name.cpp @@ -60,3 +60,9 @@ namespace ForwardDecls { typename xt::foo *t; }; } + +namespace ConflictingRedecl { + template<typename> struct Nested { + template<typename> struct Nested; // expected-error {{member 'Nested' has the same name as its class}} + }; +} diff --git a/test/Tooling/ms-asm-no-target.cpp b/test/Tooling/ms-asm-no-target.cpp index 68930b159680..9041ad37b75e 100644 --- a/test/Tooling/ms-asm-no-target.cpp +++ b/test/Tooling/ms-asm-no-target.cpp @@ -1,13 +1,13 @@ -// RUN: not clang-check "%s" -- -fasm-blocks -target x86_64-apple-darwin10 2>&1 | FileCheck -check-prefix=CHECK-X86 %s +// RUN: clang-check "%s" -- -fasm-blocks -target x86_64-apple-darwin10 2>&1 | FileCheck -check-prefix=CHECK-X86 %s -allow-empty // RUN: not clang-check "%s" -- -fasm-blocks -target powerpc-apple-darwin10 2>&1 | FileCheck -check-prefix=CHECK-PPC %s - -// Test that we diagnose instead of crashing when the application hasn't -// initialized LLVM targets supporting the MS-style inline asm parser. -// Also test that the ordinary error is emitted on unsupported architectures. +// REQUIRES: x86-registered-target void Break() { __asm { int 3 } } -// CHECK-X86: error: MS-style inline assembly is not available +// clang-check should initialize the x86 target, so x86 should work. +// CHECK-X86-NOT: error: MS-style inline assembly is not available + +// Test that the ordinary error is emitted on unsupported architectures. // CHECK-PPC: error: Unsupported architecture 'powerpc' for MS-style inline assembly diff --git a/test/lit.cfg b/test/lit.cfg index 0e947dd437bb..f853b3f7db4f 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -421,6 +421,10 @@ if not re.match(r'.*-(cygwin|mingw32|windows-gnu)$', config.target_triple): if platform.system() not in ['Windows']: config.available_features.add('can-remove-opened-file') +# Not set for targeting tls-incapable targets. +if not re.match(r'.*-cygwin$', config.target_triple): + config.available_features.add('tls') + # Returns set of available features, registered-target(s) and asserts. def get_llvm_config_props(): set_of_features = set() diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile index fff05f828254..03e0c9e58c4d 100644 --- a/tools/c-arcmt-test/Makefile +++ b/tools/c-arcmt-test/Makefile @@ -21,11 +21,20 @@ NO_INSTALL = 1 # LINK_COMPONENTS before including Makefile.rules include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option +LINK_COMPONENTS := $(TARGETS_TO_BUILD) \ + AsmParser \ + BitReader \ + BitWriter \ + IPO \ + MC \ + ObjCARCOpts \ + Option \ + Support # Note that 'USEDLIBS' must include all of the core clang libraries # when -static is given to linker on cygming. USEDLIBS = clang.a \ + clangCodeGen.a \ clangARCMigrate.a \ clangIndex.a \ clangFormat.a \ diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index 62bc9348dbf5..b757b477958e 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -22,11 +22,20 @@ TOOL_NO_EXPORTS = 1 # LINK_COMPONENTS before including Makefile.rules include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option +LINK_COMPONENTS := $(TARGETS_TO_BUILD) \ + AsmParser \ + BitReader \ + BitWriter \ + IPO \ + MC \ + ObjCARCOpts \ + Option \ + Support # Note that 'USEDLIBS' must include all of the core clang libraries # when -static is given to linker on cygming. USEDLIBS = clang.a \ + clangCodeGen.a \ clangIndex.a clangFormat.a clangRewrite.a \ clangFrontend.a clangDriver.a \ clangTooling.a \ diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt index 8b9cd888c8c7..d1572cb16639 100644 --- a/tools/clang-check/CMakeLists.txt +++ b/tools/clang-check/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LLVM_LINK_COMPONENTS +set( LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Option Support ) @@ -10,6 +11,7 @@ add_clang_executable(clang-check target_link_libraries(clang-check clangAST clangBasic + clangCodeGen clangDriver clangFrontend clangRewriteFrontend diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp index 7992026a7ccf..2682e0fcd83f 100644 --- a/tools/clang-check/ClangCheck.cpp +++ b/tools/clang-check/ClangCheck.cpp @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" +#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Driver/Options.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" @@ -29,6 +30,7 @@ #include "llvm/Option/OptTable.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" using namespace clang::driver; using namespace clang::tooling; @@ -149,9 +151,17 @@ public: int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); + + // Initialize targets for clang module support. + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory); ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); + OptionsParser.getSourcePathList(), + std::make_shared<clang::ObjectFilePCHContainerOperations>()); // Clear adjusters because -fsyntax-only is inserted by the default chain. Tool.clearArgumentsAdjusters(); diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile index e98a131de5a9..da010ab1f32a 100644 --- a/tools/clang-check/Makefile +++ b/tools/clang-check/Makefile @@ -15,11 +15,14 @@ TOOLNAME = clang-check TOOL_NO_EXPORTS = 1 include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option -USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \ +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader ipo objcarcopts \ + instrumentation bitwriter support mc option +USEDLIBS = clangFrontend.a clangCodeGen.a clangIndex.a \ + clangSerialization.a clangDriver.a \ clangTooling.a clangParse.a clangSema.a \ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \ clangStaticAnalyzerCore.a clangAnalysis.a clangRewriteFrontend.a \ - clangRewrite.a clangEdit.a clangAST.a clangLex.a clangBasic.a + clangRewrite.a clangEdit.a clangAST.a clangLex.a \ + clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py index 49ca773b049d..5cb41fcfa371 100644 --- a/tools/clang-format/clang-format.py +++ b/tools/clang-format/clang-format.py @@ -14,6 +14,15 @@ # VISUAL mode. The line or region is extended to the next bigger syntactic # entity. # +# You can also pass in the variable "l:lines" to choose the range for +# formatting. This variable can either contain "<start line>:<end line>" or +# "all" to format the full file. So, to format the full file, write a function +# like: +# :function FormatFile() +# : let l:lines="all" +# : pyf <path-to-this-file>/clang-format.py +# :endfunction +# # It operates on the current, potentially unsaved buffer and does not create # or save any files. To revert a formatting, just undo. @@ -44,7 +53,10 @@ def main(): text = '\n'.join(buf) # Determine range to format. - lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1) + if vim.eval('exists("l:lines")') == '1': + lines = vim.eval('l:lines') + else: + lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1) # Determine the cursor position. cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 @@ -60,7 +72,9 @@ def main(): startupinfo.wShowWindow = subprocess.SW_HIDE # Call formatter. - command = [binary, '-lines', lines, '-style', style, '-cursor', str(cursor)] + command = [binary, '-style', style, '-cursor', str(cursor)] + if lines != 'all': + command.extend(['-lines', lines]) if fallback_style: command.extend(['-fallback-style', fallback_style]) if vim.current.buffer.name: diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index e592acadf17f..3f1ed40abe4d 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -33,12 +33,17 @@ add_clang_executable(clang target_link_libraries(clang clangBasic + clangCodeGen clangDriver clangFrontend clangFrontendTool ) -set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION}) +if(WIN32 AND NOT CYGWIN) + # Prevent versioning if the buildhost is targeting for Win32. +else() + set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION}) +endif() # Support plugins. if(CLANG_PLUGIN_SUPPORT) diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 972bf5bf3e10..65f845ddc458 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Option/Arg.h" -#include "clang/Frontend/PCHContainerOperations.h" +#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Frontend/CompilerInstance.h" @@ -65,8 +65,8 @@ void initializePollyPasses(llvm::PassRegistry &Registry); #endif int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { - std::unique_ptr<CompilerInstance> Clang( - new CompilerInstance(std::make_shared<RawPCHContainerOperations>())); + std::unique_ptr<CompilerInstance> Clang(new CompilerInstance( + std::make_shared<ObjectFilePCHContainerOperations>())); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); // Initialize targets first, so that --version shows registered targets. diff --git a/tools/libclang/BuildSystem.cpp b/tools/libclang/BuildSystem.cpp index e9423c328698..fe3db755eba8 100644 --- a/tools/libclang/BuildSystem.cpp +++ b/tools/libclang/BuildSystem.cpp @@ -84,6 +84,10 @@ clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned, return CXError_Success; } +void clang_free(void *buffer) { + free(buffer); +} + void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) { delete unwrap(VFO); } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index bf5b58253ad0..6e48bab9f509 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -29,6 +29,7 @@ #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -53,6 +54,7 @@ #include "llvm/Support/Program.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/Threading.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -916,6 +918,18 @@ bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return false; } +bool CursorVisitor::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + // Visit the bound, if it's explicit. + if (D->hasExplicitBound()) { + if (auto TInfo = D->getTypeSourceInfo()) { + if (Visit(TInfo->getTypeLoc())) + return true; + } + } + + return false; +} + bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { if (TypeSourceInfo *TSInfo = ND->getReturnTypeSourceInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -1021,6 +1035,9 @@ bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { TU))) return true; + if (VisitObjCTypeParamList(ND->getTypeParamList())) + return true; + ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), E = ND->protocol_end(); I != E; ++I, ++PL) @@ -1080,12 +1097,29 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { return false; } +bool CursorVisitor::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) { + if (!typeParamList) + return false; + + for (auto *typeParam : *typeParamList) { + // Visit the type parameter. + if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest))) + return true; + } + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { if (!D->isThisDeclarationADefinition()) { // Forward declaration is treated like a reference. return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU)); } + // Objective-C type parameters. + if (VisitObjCTypeParamList(D->getTypeParamListAsWritten())) + return true; + // Issue callbacks for super class. if (D->getSuperClass() && Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), @@ -1093,6 +1127,10 @@ bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { TU))) return true; + if (TypeSourceInfo *SuperClassTInfo = D->getSuperClassTInfo()) + if (Visit(SuperClassTInfo->getTypeLoc())) + return true; + ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++PL) @@ -1486,6 +1524,11 @@ bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) return true; + for (unsigned I = 0, N = TL.getNumTypeArgs(); I != N; ++I) { + if (Visit(TL.getTypeArgTInfo(I)->getTypeLoc())) + return true; + } + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) @@ -2835,7 +2878,14 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH, // registered once. (void)*RegisterFatalErrorHandlerOnce; - CIndexer *CIdxr = new CIndexer(); + // Initialize targets for clang module support. + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + + CIndexer *CIdxr = + new CIndexer(std::make_shared<ObjectFilePCHContainerOperations>()); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); if (displayDiagnostics) @@ -3052,6 +3102,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, /*UserFilesAreVolatile=*/true, ForSerialization, &ErrUnit)); + // Early failures in LoadFromCommandLine may return with ErrUnit unset. + if (!Unit && !ErrUnit) { + PTUI->result = CXError_ASTReadError; + return; + } + if (NumErrors != Diags->getClient()->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. if (CXXIdx->getDisplayDiagnostics()) @@ -4411,7 +4467,12 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, *BestCursor = getTypeRefedCallExprCursor(*BestCursor); return CXChildVisit_Recurse; } - + + // If we already have an Objective-C superclass reference, don't + // update it further. + if (BestCursor->kind == CXCursor_ObjCSuperClassRef) + return CXChildVisit_Break; + *BestCursor = cursor; return CXChildVisit_Recurse; } @@ -5038,6 +5099,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::ObjCTypeParam: return C; // Declaration kinds that don't make any sense here, but are @@ -6321,6 +6383,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) { case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: + case Decl::ObjCTypeParam: return CXLanguage_ObjC; case Decl::CXXConstructor: case Decl::CXXConversion: diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index a7b8e292047b..9609a693abdf 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -542,7 +542,7 @@ namespace { StoredResults.reserve(StoredResults.size() + NumResults); for (unsigned I = 0; I != NumResults; ++I) { CodeCompletionString *StoredCompletion - = Results[I].CreateCodeCompletionString(S, getAllocator(), + = Results[I].CreateCodeCompletionString(S, Context, getAllocator(), getCodeCompletionTUInfo(), includeBriefComments()); diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 26f88a97c574..fb292090565d 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -40,6 +40,7 @@ set(SOURCES set(LIBS clangAST clangBasic + clangCodeGen clangFrontend clangIndex clangLex @@ -91,6 +92,7 @@ add_clang_library(libclang ${ENABLE_SHARED} ${ENABLE_STATIC} ${LIBS} LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Core Support ) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index fe9ba4eac1b1..099edcf14fed 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -1298,6 +1298,7 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) { CodeCompletionString *String = Result.CreateCodeCompletionString(unit->getASTContext(), unit->getPreprocessor(), + CodeCompletionContext::CCC_Other, unit->getCodeCompletionTUInfo().getAllocator(), unit->getCodeCompletionTUInfo(), true); @@ -1308,10 +1309,13 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) { const IdentifierInfo *MacroInfo = definition->getName(); ASTUnit *unit = getCursorASTUnit(cursor); CodeCompletionResult Result(MacroInfo); - CodeCompletionString *String = Result.CreateCodeCompletionString( - unit->getASTContext(), unit->getPreprocessor(), - unit->getCodeCompletionTUInfo().getAllocator(), - unit->getCodeCompletionTUInfo(), false); + CodeCompletionString *String + = Result.CreateCodeCompletionString(unit->getASTContext(), + unit->getPreprocessor(), + CodeCompletionContext::CCC_Other, + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo(), + false); return String; } return nullptr; diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h index 1b2a922204f8..91f63b40f6a5 100644 --- a/tools/libclang/CursorVisitor.h +++ b/tools/libclang/CursorVisitor.h @@ -217,11 +217,13 @@ public: bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); bool VisitObjCMethodDecl(ObjCMethodDecl *ND); bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); + bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index 97f663cde478..84914e0f4609 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -16,19 +16,21 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := AsmParser BitReader Core MC MCParser Option Support +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter core \ + instrumentation ipo mc mcparser objcarcopts option support \ + object USEDLIBS = clangIndex.a clangARCMigrate.a \ clangRewriteFrontend.a \ clangFormat.a \ clangTooling.a clangToolingCore.a \ - clangFrontend.a clangDriver.a \ + clangFrontend.a clangCodeGen.a clangDriver.a \ clangSerialization.a \ clangParse.a clangSema.a \ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ clangRewrite.a \ clangAnalysis.a clangEdit.a \ clangASTMatchers.a \ - clangAST.a clangLex.a clangBasic.a \ + clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index f78f9981a98b..f6a7175579aa 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -132,6 +132,7 @@ clang_findIncludesInFileWithBlock clang_findReferencesInFile clang_findReferencesInFileWithBlock clang_formatDiagnostic +clang_free clang_getArgType clang_getArrayElementType clang_getArraySize diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 17b69dac45a1..d79a3175b476 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -164,6 +164,7 @@ testing::AssertionResult matchesConditionallyWithCuda( std::vector<std::string> Args; Args.push_back("-xcuda"); Args.push_back("-fno-ms-extensions"); + Args.push_back("--cuda-host-only"); Args.push_back(CompileArg); if (!runToolOnCodeWithArgs(Factory->create(), CudaHeader + Code, Args)) { diff --git a/unittests/ASTMatchers/Dynamic/Makefile b/unittests/ASTMatchers/Dynamic/Makefile index dfd0086c883e..df253b8a1d32 100644 --- a/unittests/ASTMatchers/Dynamic/Makefile +++ b/unittests/ASTMatchers/Dynamic/Makefile @@ -14,7 +14,9 @@ include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ clangRewrite.a clangRewriteFrontend.a clangParse.a clangSema.a \ + clangDynamicASTMatchers.a \ clangAnalysis.a clangEdit.a clangAST.a clangASTMatchers.a \ - clangLex.a clangBasic.a clangDynamicASTMatchers.a + clangLex.a \ + clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index 5e6cadd19624..45b0910ab0a2 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -162,7 +162,7 @@ using ast_matchers::internal::Matcher; Parser::NamedValueMap getTestNamedValues() { Parser::NamedValueMap Values; - Values["nameX"] = std::string("x"); + Values["nameX"] = llvm::StringRef("x"); Values["hasParamA"] = VariantMatcher::SingleMatcher(hasParameter(0, hasName("a"))); return Values; diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 5483f8f35804..a6b0a1b41d6b 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -144,7 +144,7 @@ TEST_F(RegistryTest, CanConstructNoArgs) { TEST_F(RegistryTest, ConstructWithSimpleArgs) { Matcher<Decl> Value = constructMatcher( - "namedDecl", constructMatcher("hasName", std::string("X"))) + "namedDecl", constructMatcher("hasName", StringRef("X"))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("class X {};", Value)); EXPECT_FALSE(matches("int x;", Value)); @@ -178,7 +178,7 @@ TEST_F(RegistryTest, ConstructWithMatcherArgs) { Matcher<Decl> HasParameter = functionDecl(constructMatcher( - "hasParameter", 1, constructMatcher("hasName", std::string("x"))) + "hasParameter", 1, constructMatcher("hasName", StringRef("x"))) .getTypedMatcher<FunctionDecl>()); EXPECT_TRUE(matches("void f(int a, int x);", HasParameter)); EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); @@ -196,7 +196,7 @@ TEST_F(RegistryTest, OverloadedMatchers) { constructMatcher( "callee", constructMatcher("methodDecl", - constructMatcher("hasName", std::string("x"))))) + constructMatcher("hasName", StringRef("x"))))) .getTypedMatcher<Stmt>(); std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }"; @@ -209,7 +209,7 @@ TEST_F(RegistryTest, OverloadedMatchers) { Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc( constructMatcher( - "loc", constructMatcher("asString", std::string("const double *"))) + "loc", constructMatcher("asString", StringRef("const double *"))) .getTypedMatcher<TypeLoc>())); Matcher<NestedNameSpecifierLoc> NNSL = @@ -244,7 +244,7 @@ TEST_F(RegistryTest, PolymorphicMatchers) { Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); Matcher<Decl> RecordDecl = constructMatcher( - "recordDecl", constructMatcher("hasName", std::string("Foo")), + "recordDecl", constructMatcher("hasName", StringRef("Foo")), VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>(); EXPECT_TRUE(matches("int Foo;", Anything)); @@ -261,7 +261,7 @@ TEST_F(RegistryTest, PolymorphicMatchers) { constructMatcher( "methodDecl", constructMatcher( - "ofClass", constructMatcher("hasName", std::string("Foo")))))) + "ofClass", constructMatcher("hasName", StringRef("Foo")))))) .getTypedMatcher<Stmt>(); EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr)); EXPECT_TRUE( @@ -274,7 +274,7 @@ TEST_F(RegistryTest, TemplateArgument) { constructMatcher( "hasAnyTemplateArgument", constructMatcher("refersToType", - constructMatcher("asString", std::string("int"))))) + constructMatcher("asString", StringRef("int"))))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", HasTemplateArgument)); @@ -304,7 +304,7 @@ TEST_F(RegistryTest, CXXCtorInitializer) { constructMatcher( "hasAnyConstructorInitializer", constructMatcher("forField", - constructMatcher("hasName", std::string("foo"))))) + constructMatcher("hasName", StringRef("foo"))))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); @@ -317,7 +317,7 @@ TEST_F(RegistryTest, Adaptative) { constructMatcher( "has", constructMatcher("recordDecl", - constructMatcher("hasName", std::string("X"))))) + constructMatcher("hasName", StringRef("X"))))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("class X {};", D)); EXPECT_TRUE(matches("class Y { class X {}; };", D)); @@ -328,7 +328,7 @@ TEST_F(RegistryTest, Adaptative) { constructMatcher( "hasDescendant", constructMatcher("varDecl", - constructMatcher("hasName", std::string("X"))))) + constructMatcher("hasName", StringRef("X"))))) .getTypedMatcher<Stmt>(); EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); @@ -346,9 +346,9 @@ TEST_F(RegistryTest, VariadicOp) { Matcher<Decl> D = constructMatcher( "anyOf", constructMatcher("recordDecl", - constructMatcher("hasName", std::string("Foo"))), + constructMatcher("hasName", StringRef("Foo"))), constructMatcher("functionDecl", - constructMatcher("hasName", std::string("foo")))) + constructMatcher("hasName", StringRef("foo")))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("void foo(){}", D)); @@ -360,8 +360,8 @@ TEST_F(RegistryTest, VariadicOp) { constructMatcher( "namedDecl", constructMatcher("anyOf", - constructMatcher("hasName", std::string("Foo")), - constructMatcher("hasName", std::string("Bar"))))) + constructMatcher("hasName", StringRef("Foo")), + constructMatcher("hasName", StringRef("Bar"))))) .getTypedMatcher<Decl>(); EXPECT_FALSE(matches("void foo(){}", D)); @@ -375,14 +375,14 @@ TEST_F(RegistryTest, VariadicOp) { constructMatcher( "unless", constructMatcher("namedDecl", - constructMatcher("hasName", std::string("Bar")))) + constructMatcher("hasName", StringRef("Bar")))) .getTypedMatcher<Decl>()); EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); D = constructMatcher( - "namedDecl", constructMatcher("hasName", std::string("Foo")), + "namedDecl", constructMatcher("hasName", StringRef("Foo")), constructMatcher("unless", constructMatcher("recordDecl"))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("void Foo(){}", D)); @@ -396,7 +396,7 @@ TEST_F(RegistryTest, Errors) { EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", Error->toString()); Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); + EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull()); EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", Error->toString()); Error.reset(new Diagnostics()); @@ -404,14 +404,14 @@ TEST_F(RegistryTest, Errors) { EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", Error->toString()); Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(), + EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(), Error.get()).isNull()); EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", Error->toString()); // Bad argument type Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull()); + EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull()); EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " "(Actual = String)", Error->toString()); @@ -425,7 +425,7 @@ TEST_F(RegistryTest, Errors) { // Bad argument type with variadic. Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(), + EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(), Error.get()).isNull()); EXPECT_EQ( "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", @@ -434,7 +434,7 @@ TEST_F(RegistryTest, Errors) { EXPECT_TRUE(constructMatcher( "recordDecl", constructMatcher("allOf", - constructMatcher("isDerivedFrom", std::string("FOO")), + constructMatcher("isDerivedFrom", StringRef("FOO")), constructMatcher("isArrow")), Error.get()).isNull()); EXPECT_EQ("Incorrect type for arg 1. " @@ -495,7 +495,7 @@ TEST_F(RegistryTest, Completion) { TEST_F(RegistryTest, HasArgs) { Matcher<Decl> Value = constructMatcher( - "decl", constructMatcher("hasAttr", std::string("attr::WarnUnused"))) + "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused"))) .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value)); EXPECT_FALSE(matches("struct X {};", Value)); diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp index 524b73dc5244..268463da4533 100644 --- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -32,7 +32,7 @@ TEST(VariantValueTest, Unsigned) { } TEST(VariantValueTest, String) { - const ::std::string kString = "string"; + const StringRef kString = "string"; VariantValue Value = kString; EXPECT_TRUE(Value.isString()); @@ -74,7 +74,7 @@ TEST(VariantValueTest, DynTypedMatcher) { } TEST(VariantValueTest, Assignment) { - VariantValue Value = std::string("A"); + VariantValue Value = StringRef("A"); EXPECT_TRUE(Value.isString()); EXPECT_EQ("A", Value.getString()); EXPECT_TRUE(Value.hasValue()); @@ -115,7 +115,7 @@ TEST(VariantValueTest, ImplicitBool) { EXPECT_FALSE(IfTrue); EXPECT_TRUE(!Value); - Value = std::string(); + Value = StringRef(); IfTrue = false; if (Value) { IfTrue = true; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 0e67ec71537e..6636d82db74d 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -23,7 +23,8 @@ add_subdirectory(Format) add_subdirectory(Rewrite) add_subdirectory(Sema) add_subdirectory(CodeGen) -# FIXME: Why are the libclang unit tests disabled on Windows? +# FIXME: libclang unit tests are disabled on Windows due +# to failures, mostly in libclang.VirtualFileOverlay_*. if(NOT WIN32) add_subdirectory(libclang) endif() diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 0d85789a1ddb..d61dc7f662c2 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -516,6 +516,10 @@ TEST_F(FormatTest, FormatsForLoop) { " aaaaaaaaaa);\n" " iter; ++iter) {\n" "}"); + verifyFormat("for (auto aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaa != bbbbbbbbbbbbbbbbbbbbbbb;\n" + " ++aaaaaaaaaaaaaaaaaaaaaaaaaaa) {"); FormatStyle NoBinPacking = getLLVMStyle(); NoBinPacking.BinPackParameters = false; @@ -3216,6 +3220,24 @@ TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) { verifyFormat("enum E {}"); } +TEST_F(FormatTest, FormatBeginBlockEndMacros) { + FormatStyle Style = getLLVMStyle(); + Style.MacroBlockBegin = "^[A-Z_]+_BEGIN$"; + Style.MacroBlockEnd = "^[A-Z_]+_END$"; + verifyFormat("FOO_BEGIN\n" + " FOO_ENTRY\n" + "FOO_END", Style); + verifyFormat("FOO_BEGIN\n" + " NESTED_FOO_BEGIN\n" + " NESTED_FOO_ENTRY\n" + " NESTED_FOO_END\n" + "FOO_END", Style); + verifyFormat("FOO_BEGIN(Foo, Bar)\n" + " int x;\n" + " x = 1;\n" + "FOO_END(Baz)", Style); +} + //===----------------------------------------------------------------------===// // Line break tests. //===----------------------------------------------------------------------===// @@ -5535,6 +5557,11 @@ TEST_F(FormatTest, UnderstandsAttributes) { verifyFormat("SomeType s __attribute__((unused)) (InitValue);"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n" "aaaaaaaaaaaaaaaaaaaaaaa(int i);"); + FormatStyle AfterType = getLLVMStyle(); + AfterType.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; + verifyFormat("__attribute__((nodebug)) void\n" + "foo() {}\n", + AfterType); } TEST_F(FormatTest, UnderstandsEllipsis) { @@ -8552,6 +8579,50 @@ TEST_F(FormatTest, LinuxBraceBreaking) { LinuxBraceStyle); } +TEST_F(FormatTest, MozillaBraceBreaking) { + FormatStyle MozillaBraceStyle = getLLVMStyle(); + MozillaBraceStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; + verifyFormat("namespace a {\n" + "class A\n" + "{\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + " void g() { return; }\n" + "};\n" + "enum E\n" + "{\n" + " A,\n" + " // foo\n" + " B,\n" + " C\n" + "};\n" + "struct B\n" + "{\n" + " int x;\n" + "};\n" + "}\n", + MozillaBraceStyle); + verifyFormat("struct S\n" + "{\n" + " int Type;\n" + " union\n" + " {\n" + " int x;\n" + " double y;\n" + " } Value;\n" + " class C\n" + " {\n" + " MyFavoriteType Value;\n" + " } Class;\n" + "}\n", + MozillaBraceStyle); +} + TEST_F(FormatTest, StroustrupBraceBreaking) { FormatStyle StroustrupBraceStyle = getLLVMStyle(); StroustrupBraceStyle.BreakBeforeBraces = FormatStyle::BS_Stroustrup; @@ -9192,6 +9263,8 @@ TEST_F(FormatTest, ParsesConfiguration) { FormatStyle::BS_Attach); CHECK_PARSE("BreakBeforeBraces: Linux", BreakBeforeBraces, FormatStyle::BS_Linux); + CHECK_PARSE("BreakBeforeBraces: Mozilla", BreakBeforeBraces, + FormatStyle::BS_Mozilla); CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces, FormatStyle::BS_Stroustrup); CHECK_PARSE("BreakBeforeBraces: Allman", BreakBeforeBraces, @@ -9788,6 +9861,20 @@ TEST_F(FormatTest, FormatsLambdas) { " << std::count_if(v.begin(), v.end(), [](int x) {\n" " return x == 2; // force break\n" " });"); + verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa([=](\n" + " int iiiiiiiiiiii) {\n" + " return aaaaaaaaaaaaaaaaaaaaaaa != aaaaaaaaaaaaaaaaaaaaaaa;\n" + "});", + getLLVMStyleWithColumns(60)); + verifyFormat("SomeFunction({[&] {\n" + " // comment\n" + " },\n" + " [&] {\n" + " // comment\n" + " }});"); + verifyFormat("SomeFunction({[&] {\n" + " // comment\n" + "}});"); // Lambdas with return types. verifyFormat("int c = []() -> int { return 2; }();\n"); diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index e6c12f4ce0f1..d068d35d7d39 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -687,6 +687,10 @@ TEST_F(FormatTestJS, ClassDeclarations) { verifyFormat("class C {\n static x(): string { return 'asd'; }\n}"); verifyFormat("class C extends P implements I {}"); verifyFormat("class C extends p.P implements i.I {}"); + verifyFormat("class Test {\n" + " aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n" + " aaaaaaaaaaaaaaaaaaaaaa {}\n" + "}"); // ':' is not a type declaration here. verifyFormat("class X {\n" @@ -703,6 +707,10 @@ TEST_F(FormatTestJS, InterfaceDeclarations) { " x: string;\n" "}\n" "var y;"); + // Ensure that state is reset after parsing the interface. + verifyFormat("interface a {}\n" + "export function b() {}\n" + "var x;"); } TEST_F(FormatTestJS, EnumDeclarations) { @@ -885,6 +893,9 @@ TEST_F(FormatTestJS, TypeArguments) { verifyFormat("function f(): List<any> {}"); verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}"); + verifyFormat("function aaaaaaaaaa(aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa):\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}"); } TEST_F(FormatTestJS, OptionalTypes) { diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt index a1310e885a55..5b5fdc9a54fe 100644 --- a/unittests/Frontend/CMakeLists.txt +++ b/unittests/Frontend/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_unittest(FrontendTests ) target_link_libraries(FrontendTests clangAST + clangBasic clangFrontend clangLex clangSema diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index e827ebc0da86..becebf076d61 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/unittests/libclang/LibclangTest.cpp @@ -63,7 +63,7 @@ struct TestVFO { clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize); std::string BufStr(BufPtr, BufSize); EXPECT_STREQ(Contents, BufStr.c_str()); - free(BufPtr); + clang_free(BufPtr); } clang_VirtualFileOverlay_dispose(VFO); } @@ -345,7 +345,7 @@ TEST(libclang, ModuleMapDescriptor) { clang_ModuleMapDescriptor_writeToBuffer(MMD, 0, &BufPtr, &BufSize); std::string BufStr(BufPtr, BufSize); EXPECT_STREQ(Contents, BufStr.c_str()); - free(BufPtr); + clang_free(BufPtr); clang_ModuleMapDescriptor_dispose(MMD); } diff --git a/unittests/libclang/Makefile b/unittests/libclang/Makefile index f8e83aa83a1b..037dea34d299 100644 --- a/unittests/libclang/Makefile +++ b/unittests/libclang/Makefile @@ -12,11 +12,20 @@ TESTNAME = libclang LINK_LIBS_IN_SHARED := 1 include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option +LINK_COMPONENTS := $(TARGETS_TO_BUILD) \ + AsmParser \ + BitReader \ + BitWriter \ + IPO \ + MC \ + ObjCArcOpts \ + Option \ + Support # Note that 'USEDLIBS' must include all of the core clang libraries # when -static is given to linker on cygming. USEDLIBS = clang.a \ + clangCodeGen.a \ clangIndex.a clangFormat.a clangRewrite.a \ clangFrontend.a clangDriver.a \ clangTooling.a \ diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index f79c4a5f9212..5dc33a000a42 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1066,7 +1066,7 @@ createArgument(const Record &Arg, StringRef Attr, if (!Ptr) { // Search in reverse order so that the most-derived type is handled first. - std::vector<Record*> Bases = Search->getSuperClasses(); + ArrayRef<Record*> Bases = Search->getSuperClasses(); for (const auto *Base : llvm::make_range(Bases.rbegin(), Bases.rend())) { if ((Ptr = createArgument(Arg, Attr, Base))) break; @@ -1456,7 +1456,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (!R.getValueAsBit("ASTNode")) continue; - const std::vector<Record *> Supers = R.getSuperClasses(); + ArrayRef<Record *> Supers = R.getSuperClasses(); assert(!Supers.empty() && "Forgot to specify a superclass for the attr"); std::string SuperName; for (const auto *Super : llvm::make_range(Supers.rbegin(), Supers.rend())) { diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py index a1f7a5649c5e..ce5ddfb3add4 100755 --- a/utils/analyzer/CmpRuns.py +++ b/utils/analyzer/CmpRuns.py @@ -37,7 +37,7 @@ import CmpRuns class SingleRunInfo: def __init__(self, path, root="", verboseLog=None): self.path = path - self.root = root + self.root = root.rstrip("/\\") self.verboseLog = verboseLog class AnalysisDiagnostic: @@ -50,8 +50,8 @@ class AnalysisDiagnostic: def getFileName(self): root = self._report.run.root fileName = self._report.files[self._loc['file']] - if fileName.startswith(root) : - return fileName[len(root):] + if fileName.startswith(root) and len(root) > 0: + return fileName[len(root)+1:] return fileName def getLine(self): diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 20839c24e18a..2d91ba41e24c 100644 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -16,6 +16,7 @@ Repository Directory structure: - Project Dir2 - ReferenceOutput .. +Note that the build tree must be inside the project dir. To test the build of the analyzer one would: - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that @@ -337,6 +338,18 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): if IsReferenceBuild : runCleanupScript(Dir, PBuildLogFile) + + # Make the absolute paths relative in the reference results. + for (DirPath, Dirnames, Filenames) in os.walk(SBOutputDir): + for F in Filenames: + if (not F.endswith('plist')): + continue + Plist = os.path.join(DirPath, F) + Data = plistlib.readPlist(Plist) + Paths = [SourceFile[len(Dir)+1:] if SourceFile.startswith(Dir)\ + else SourceFile for SourceFile in Data['files']] + Data['files'] = Paths + plistlib.writePlist(Data, Plist) finally: PBuildLogFile.close() @@ -450,7 +463,7 @@ def runCmpResults(Dir, Strictness = 0): print " Comparing Results: %s %s" % (RefDir, NewDir) DiffsPath = os.path.join(NewDir, DiffsSummaryFileName) - Opts = CmpRuns.CmpOptions(DiffsPath) + Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir) # Discard everything coming out of stdout (CmpRun produces a lot of them). OLD_STDOUT = sys.stdout sys.stdout = Discarder() diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index e3363e4450df..c8ac750aa72e 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -28,7 +28,7 @@ <!--*************************************************************************--> <h1>C++ Defect Report Support in Clang</h1> <!--*************************************************************************--> -<p>Last updated: $Date: 2015-05-14 21:10:42 +0200 (Thu, 14 May 2015) $</p> +<p>Last updated: $Date: 2015-07-06 03:45:27 +0200 (Mon, 06 Jul 2015) $</p> <h2 id="cxxdr">C++ defect report implementation status</h2> @@ -5503,7 +5503,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#948">948</a></td> <td>C++11</td> <td><TT>constexpr</TT> in <I>condition</I>s</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr class="open" id="949"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#949">949</a></td> @@ -11269,7 +11269,7 @@ and <I>POD class</I></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1909">1909</a></td> <td>DR</td> <td>Member class template with the same name as the class</td> - <td class="none" align="center">Unknown</td> + <td class="full" align="center">Yes</td> </tr> <tr class="open" id="1910"> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1910">1910</a></td> |