Index: cfe/trunk/include/clang/AST/DeclBase.h =================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h +++ cfe/trunk/include/clang/AST/DeclBase.h @@ -616,6 +616,14 @@ getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple()) const; + /// \brief Retrieve the version of the target platform in which this + /// declaration was introduced. + /// + /// \returns An empty version tuple if this declaration has no 'introduced' + /// availability attributes, or the version tuple that's specified in the + /// attribute otherwise. + VersionTuple getVersionIntroduced() const; + /// \brief Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -1180,6 +1180,10 @@ def err_objc_kindof_wrong_position : Error< "'__kindof' type specifier must precede the declarator">; +def err_objc_method_unsupported_param_ret_type : Error< + "%0 %select{parameter|return}1 type is unsupported; " + "support for vector types for this target is introduced in %2">; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; Index: cfe/trunk/lib/AST/DeclBase.cpp =================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp +++ cfe/trunk/lib/AST/DeclBase.cpp @@ -415,6 +415,19 @@ return nullptr; } +StringRef getRealizedPlatform(const AvailabilityAttr *A, + const ASTContext &Context) { + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef RealizedPlatform = A->getPlatform()->getName(); + if (!Context.getLangOpts().AppExt) + return RealizedPlatform; + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + return RealizedPlatform.slice(0, suffix); + return RealizedPlatform; +} + /// \brief Determine the availability of the given declaration based on /// the target platform. /// @@ -434,20 +447,11 @@ if (EnclosingVersion.empty()) return AR_Available; - // Check if this is an App Extension "platform", and if so chop off - // the suffix for matching with the actual platform. StringRef ActualPlatform = A->getPlatform()->getName(); - StringRef RealizedPlatform = ActualPlatform; - if (Context.getLangOpts().AppExt) { - size_t suffix = RealizedPlatform.rfind("_app_extension"); - if (suffix != StringRef::npos) - RealizedPlatform = RealizedPlatform.slice(0, suffix); - } - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); // Match the platform name. - if (RealizedPlatform != TargetPlatform) + if (getRealizedPlatform(A, Context) != TargetPlatform) return AR_Available; StringRef PrettyPlatformName @@ -567,6 +571,20 @@ return Result; } +VersionTuple Decl::getVersionIntroduced() const { + const ASTContext &Context = getASTContext(); + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + for (const auto *A : attrs()) { + if (const auto *Availability = dyn_cast(A)) { + if (getRealizedPlatform(Availability, Context) != TargetPlatform) + continue; + if (!Availability->getIntroduced().empty()) + return Availability->getIntroduced(); + } + } + return VersionTuple(); +} + bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; Index: cfe/trunk/lib/Sema/SemaDeclObjC.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp @@ -4313,6 +4313,51 @@ } } +/// Verify that the method parameters/return value have types that are supported +/// by the x86 target. +static void checkObjCMethodX86VectorTypes(Sema &SemaRef, + const ObjCMethodDecl *Method) { + assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() == + llvm::Triple::x86 && + "x86-specific check invoked for a different target"); + SourceLocation Loc; + QualType T; + for (const ParmVarDecl *P : Method->parameters()) { + if (P->getType()->isVectorType()) { + Loc = P->getLocStart(); + T = P->getType(); + break; + } + } + if (Loc.isInvalid()) { + if (Method->getReturnType()->isVectorType()) { + Loc = Method->getReturnTypeSourceRange().getBegin(); + T = Method->getReturnType(); + } else + return; + } + + // Vector parameters/return values are not supported by objc_msgSend on x86 in + // iOS < 9 and macOS < 10.11. + const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple(); + VersionTuple AcceptedInVersion; + if (Triple.getOS() == llvm::Triple::IOS) + AcceptedInVersion = VersionTuple(/*Major=*/9); + else if (Triple.isMacOSX()) + AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11); + else + return; + VersionTuple MethodVersion = Method->getVersionIntroduced(); + if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >= + AcceptedInVersion && + (MethodVersion.empty() || MethodVersion >= AcceptedInVersion)) + return; + SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type) + << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1 + : /*parameter*/ 0) + << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, @@ -4534,6 +4579,10 @@ ObjCMethod->SetRelatedResultType(); } + if (MethodDefinition && + Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) + checkObjCMethodX86VectorTypes(*this, ObjCMethod); + ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; Index: cfe/trunk/test/SemaObjC/x86-method-vector-values.m =================================================================== --- cfe/trunk/test/SemaObjC/x86-method-vector-values.m +++ cfe/trunk/test/SemaObjC/x86-method-vector-values.m @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.10 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.4 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-darwin14 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -triple=i686-apple-ios8 -Wno-objc-root-class %s + +// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-macosx10.11 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-darwin15 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DIOS -triple=i686-apple-ios9 -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-watchos -Wno-objc-root-class %s +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-tvos -Wno-objc-root-class %s + +// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=x86_64-apple-macosx10.10 -Wno-objc-root-class %s + +// rdar://21662309 + +typedef __attribute__((__ext_vector_type__(3))) float float3; + +typedef float __m128 __attribute__((__vector_size__(16))); + +struct Aggregate { __m128 v; }; +struct AggregateFloat { float v; }; + +#define AVAILABLE_MACOS_10_10 __attribute__((availability(macos, introduced = 10.10))) +#define AVAILABLE_MACOS_10_11 __attribute__((availability(macos, introduced = 10.11))) + +#define AVAILABLE_IOS_8 __attribute__((availability(ios, introduced = 8.0))) +#define AVAILABLE_IOS_9 __attribute__((availability(ios, introduced = 9.0))) + +@interface VectorMethods + +-(void)takeVector:(float3)v; // there should be no diagnostic at declaration +-(void)takeM128:(__m128)v; + +@end + +@implementation VectorMethods + +#ifndef ALLOW + +-(void)takeVector:(float3)v { +#ifdef MAC + // expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in macOS 10.11}} +#else + // expected-error@-4 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in iOS 9}} +#endif +} + +-(float3)retVector { // expected-error {{'float3' (vector of 3 'float' values) return type is unsupported}} +} + +-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +} + +- (__m128)retM128 { // expected-error {{'__m128' (vector of 4 'float' values) return type is unsupported}} +} + +- (void)takeM128:(__m128)v { // expected-error {{'__m128' (vector of 4 'float' values) parameter type is unsupported}} +} + +#else + +-(void)takeVector:(float3)v { +} + +-(float3)retVector { + return 0; +} + +- (__m128)retM128 { + __m128 value; + return value; +} + +- (void)takeM128:(__m128)v { +} + +-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { +#ifdef MAC +// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +#endif +} + +- (__m128)retM128_2 AVAILABLE_MACOS_10_10 { +#ifdef MAC +// expected-error@-2 {{'__m128' (vector of 4 'float' values) return type is unsupported}} +#endif + __m128 value; + return value; +} + +-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // no error +} + +-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { +#ifdef IOS + // expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}} +#endif +} + +-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // no error +} + +#ifdef OTHER +// expected-no-diagnostics +#endif + +#endif + +-(void)doStuff:(int)m { // no error +} + +-(struct Aggregate)takesAndRetVectorInAggregate:(struct Aggregate)f { // no error + struct Aggregate result; + return result; +} + +-(struct AggregateFloat)takesAndRetFloatInAggregate:(struct AggregateFloat)f { // no error + struct AggregateFloat result; + return result; +} + + +@end