arphaman created this revision.
arphaman added reviewers: gparker42, mehdi_amini, erik.pilkington.
arphaman added a subscriber: cfe-commits.
arphaman set the repository for this revision to rL LLVM.
This patch adds a new error that disallows methods that have parameters/return 
values with a vector type on certain older X86 targets. This is diagnostic is 
needed because objc_msgSend doesn't support SIMD vector registers/return values 
on X86 in iOS < 9 and OS X < 10.11.


Repository:
  rL LLVM

https://reviews.llvm.org/D28670

Files:
  include/clang/AST/DeclBase.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/DeclBase.cpp
  lib/Sema/SemaDeclObjC.cpp
  test/SemaObjC/x86-method-vector-values.m

Index: test/SemaObjC/x86-method-vector-values.m
===================================================================
--- /dev/null
+++ test/SemaObjC/x86-method-vector-values.m
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -verify -triple=i686-apple-macosx10.10 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -triple=i686-apple-macosx10.4 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -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;
+
+#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
+
+@end
+
+@implementation VectorMethods
+
+#ifndef ALLOW
+
+-(void)takeVector:(float3)v { // expected-error {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+}
+
+-(float3)retVector { // expected-error {{'float3' (vector of 3 'float' values) return value is unsupported for this target}}
+}
+
+-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { // expected-error {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+}
+
+-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // expected-error {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+}
+
+-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { // expected-error {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+}
+
+-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // expected-error {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+}
+
+#else
+
+-(void)takeVector:(float3)v {
+}
+
+-(float3)retVector {
+  return 0;
+}
+
+-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 {
+#ifdef MAC
+// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter is unsupported for this target}}
+#endif
+}
+
+-(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 is unsupported for this target}}
+#endif
+}
+
+-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // no error
+}
+
+#ifdef OTHER
+// expected-no-diagnostics
+#endif
+
+#endif
+
+-(void)doStuff:(int)m { // no error
+}
+
+@end
Index: lib/Sema/SemaDeclObjC.cpp
===================================================================
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -4302,6 +4302,47 @@
   }
 }
 
+/// Verify that the method parameters/return value have types that are supported
+/// by the x86 target.
+static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
+                                          const ObjCMethodDecl *Method) {
+  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);
+}
+
 Decl *Sema::ActOnMethodDeclaration(
     Scope *S,
     SourceLocation MethodLoc, SourceLocation EndLoc,
@@ -4521,6 +4562,10 @@
       ObjCMethod->SetRelatedResultType();
   }
 
+  if (MethodDefinition &&
+      Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+    checkObjCMethodX86VectorTypes(*this, ObjCMethod);
+
   ActOnDocumentableDecl(ObjCMethod);
 
   return ObjCMethod;
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ 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<AvailabilityAttr>(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: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1153,6 +1153,9 @@
 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 value}1 is unsupported for this target">;
+
 // C++ declarations
 def err_static_assert_expression_is_not_constant : Error<
   "static_assert expression is not an integral constant expression">;
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ 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,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to