Sema: introduce `__attribute__((__swift_name__))`
authorSaleem Abdulrasool <compnerd@compnerd.org>
Thu, 10 Sep 2020 21:15:37 +0000 (21:15 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Tue, 22 Sep 2020 15:32:23 +0000 (15:32 +0000)
This introduces the new `swift_name` attribute that allows annotating
APIs with an alternate spelling for Swift.  This is used as part of the
importing mechanism to allow interfaces to be imported with a new name
into Swift.  It takes a parameter which is the Swift function name.
This parameter is validated to check if it matches the possible
transformed signature in Swift.

This is based on the work of the original changes in
https://github.com/llvm/llvm-project-staging/commit/8afaf3aad2af43cfedca7a24cd817848c4e95c0c

Differential Revision: https://reviews.llvm.org/D87534
Reviewed By: Aaron Ballman, Dmitri Gribenko

clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/SemaObjC/attr-swift_name.m [new file with mode: 0644]

index c2073e6..e8ac819 100644 (file)
@@ -2162,6 +2162,12 @@ def SwiftError : InheritableAttr {
   let Documentation = [SwiftErrorDocs];
 }
 
+def SwiftName : InheritableAttr {
+  let Spellings = [GNU<"swift_name">];
+  let Args = [StringArgument<"Name">];
+  let Documentation = [SwiftNameDocs];
+}
+
 def NoDeref : TypeAttr {
   let Spellings = [Clang<"noderef">];
   let Documentation = [NoDerefDocs];
index aab337a..9c11921 100644 (file)
@@ -3572,6 +3572,30 @@ The return type is left unmodified.
   }];
 }
 
+def SwiftNameDocs : Documentation {
+  let Category = SwiftDocs;
+  let Heading = "swift_name";
+  let Content = [{
+The ``swift_name`` attribute provides the name of the declaration in Swift. If
+this attribute is absent, the name is transformed according to the algorithm
+built into the Swift compiler.
+
+The argument is a string literal that contains the Swift name of the function,
+variable, or type. When renaming a function, the name may be a compound Swift
+name.  For a type, enum constant, property, or variable declaration, the name
+must be a simple or qualified identifier.
+
+  .. code-block:: c
+
+    @interface URL
+    - (void) initWithString:(NSString *)s __attribute__((__swift_name__("URL.init(_:)")))
+    @end
+
+    void __attribute__((__swift_name__("squareRoot()"))) sqrt(double v) {
+    }
+  }];
+}
+
 def OMPDeclareSimdDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "#pragma omp declare simd";
index d826e26..a2f5aea 100644 (file)
@@ -557,6 +557,7 @@ def StringCompare : DiagGroup<"string-compare">;
 def StringPlusInt : DiagGroup<"string-plus-int">;
 def StringPlusChar : DiagGroup<"string-plus-char">;
 def StrncatSize : DiagGroup<"strncat-size">;
+def SwiftNameAttribute : DiagGroup<"swift-name-attribute">;
 def IntInBoolContext : DiagGroup<"int-in-bool-context">;
 def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">;
 def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
index 053aae7..0cb817d 100644 (file)
@@ -3974,6 +3974,46 @@ def err_objc_bridged_related_known_method : Error<
 def err_objc_attr_protocol_requires_definition : Error<
   "attribute %0 can only be applied to @protocol definitions, not forward declarations">;
 
+// Swift attributes.
+def warn_attr_swift_name_function
+  : Warning<"%0 attribute argument must be a string literal specifying a Swift function name">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_invalid_identifier
+  : Warning<"%0 attribute has invalid identifier for the %select{base|context|parameter}1 name">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_decl_kind
+  : Warning<"%0 attribute cannot be applied to this declaration">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_invalid_parameter
+  : Warning<"%0 attribute for 'subscript' must %select{be a getter or setter|"
+        "have at least one parameter|"
+        "have a 'self:' parameter}1">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_missing_parameters
+  : Warning<"%0 attribute is missing parameter label clause">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_setter_parameters
+  : Warning<"%0 attribute for setter must have one parameter for new value">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_multiple_selfs
+  : Warning<"%0 attribute cannot specify more than one 'self:' parameter">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_getter_parameters
+  : Warning<"%0 attribute for getter must not have any parameters besides 'self:'">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_setter_no_newValue
+  : Warning<"%0 attribute for 'subscript' setter must have a 'newValue:' parameter">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_setter_multiple_newValues
+  : Warning<"%0 attribute for 'subscript' setter cannot have multiple 'newValue:' parameters">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_subscript_getter_newValue
+  : Warning<"%0 attribute for 'subscript' getter cannot have a 'newValue:' parameter">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_num_params
+  : Warning<"too %select{few|many}0 parameters in %1 attribute (expected %2; got %3)">,
+    InGroup<SwiftNameAttribute>;
+
 def err_attr_swift_error_no_error_parameter : Error<
   "%0 attribute can only be applied to a %select{function|method}1 with an "
   "error parameter">;
index 5ca1634..10b8e78 100644 (file)
@@ -1834,6 +1834,16 @@ public:
     }
   };
 
+  /// Do a check to make sure \p Name looks like a legal argument for the
+  /// swift_name attribute applied to decl \p D.  Raise a diagnostic if the name
+  /// is invalid for the given declaration.
+  ///
+  /// \p AL is used to provide caret diagnostics in case of a malformed name.
+  ///
+  /// \returns true if the name is a valid swift name for \p D, false otherwise.
+  bool DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
+                         const ParsedAttr &AL);
+
   /// A derivative of BoundTypeDiagnoser for which the diagnostic's type
   /// parameter is preceded by a 0/1 enum that is 1 if the type is sizeless.
   /// For example, a diagnostic with no other parameters would generally have
@@ -3059,6 +3069,8 @@ public:
   SpeculativeLoadHardeningAttr *
   mergeSpeculativeLoadHardeningAttr(Decl *D,
                                     const SpeculativeLoadHardeningAttr &AL);
+  SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
+                                    StringRef Name, bool Override);
   OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D,
                                           const AttributeCommonInfo &CI);
   InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
index 2d09138..434f13e 100644 (file)
@@ -2592,6 +2592,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
     return false;
   } else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
     NewAttr = S.mergeMinSizeAttr(D, *MA);
+  else if (const auto *SNA = dyn_cast<SwiftNameAttr>(Attr))
+    NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName(),
+                                   AMK == Sema::AMK_Override);
   else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
     NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
   else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
index 5efc989..6edeb79 100644 (file)
@@ -4277,6 +4277,25 @@ NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
   return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL);
 }
 
+SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
+                                        StringRef Name, bool Override) {
+  if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) {
+    if (Override) {
+      // FIXME: warn about incompatible override
+      return nullptr;
+    }
+
+    if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) {
+      Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible)
+          << PrevSNA << &SNA;
+      Diag(SNA.getLoc(), diag::note_conflicting_attribute);
+    }
+
+    D->dropAttr<SwiftNameAttr>();
+  }
+  return ::new (Context) SwiftNameAttr(Context, SNA, Name);
+}
+
 OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
                                               const AttributeCommonInfo &CI) {
   if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -5636,6 +5655,293 @@ static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention));
 }
 
+// For a function, this will validate a compound Swift name, e.g.
+// <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>, and
+// the function will output the number of parameter names, and whether this is a
+// single-arg initializer.
+//
+// For a type, enum constant, property, or variable declaration, this will
+// validate either a simple identifier, or a qualified
+// <code>context.identifier</code> name.
+static bool
+validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
+                          StringRef Name, unsigned &SwiftParamCount,
+                          bool &IsSingleParamInit) {
+  SwiftParamCount = 0;
+  IsSingleParamInit = false;
+
+  // Check whether this will be mapped to a getter or setter of a property.
+  bool IsGetter = false, IsSetter = false;
+  if (Name.startswith("getter:")) {
+    IsGetter = true;
+    Name = Name.substr(7);
+  } else if (Name.startswith("setter:")) {
+    IsSetter = true;
+    Name = Name.substr(7);
+  }
+
+  if (Name.back() != ')') {
+    S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
+    return false;
+  }
+
+  bool IsMember = false;
+  StringRef ContextName, BaseName, Parameters;
+
+  std::tie(BaseName, Parameters) = Name.split('(');
+
+  // Split at the first '.', if it exists, which separates the context name
+  // from the base name.
+  std::tie(ContextName, BaseName) = BaseName.split('.');
+  if (BaseName.empty()) {
+    BaseName = ContextName;
+    ContextName = StringRef();
+  } else if (ContextName.empty() || !isValidIdentifier(ContextName)) {
+    S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
+        << AL << /*context*/ 1;
+    return false;
+  } else {
+    IsMember = true;
+  }
+
+  if (!isValidIdentifier(BaseName) || BaseName == "_") {
+    S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
+        << AL << /*basename*/ 0;
+    return false;
+  }
+
+  bool IsSubscript = BaseName == "subscript";
+  // A subscript accessor must be a getter or setter.
+  if (IsSubscript && !IsGetter && !IsSetter) {
+    S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
+        << AL << /* getter or setter */ 0;
+    return false;
+  }
+
+  if (Parameters.empty()) {
+    S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL;
+    return false;
+  }
+
+  assert(Parameters.back() == ')' && "expected ')'");
+  Parameters = Parameters.drop_back(); // ')'
+
+  if (Parameters.empty()) {
+    // Setters and subscripts must have at least one parameter.
+    if (IsSubscript) {
+      S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
+          << AL << /* have at least one parameter */1;
+      return false;
+    }
+
+    if (IsSetter) {
+      S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL;
+      return false;
+    }
+
+    return true;
+  }
+
+  if (Parameters.back() != ':') {
+    S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
+    return false;
+  }
+
+  StringRef CurrentParam;
+  llvm::Optional<unsigned> SelfLocation;
+  unsigned NewValueCount = 0;
+  llvm::Optional<unsigned> NewValueLocation;
+  do {
+    std::tie(CurrentParam, Parameters) = Parameters.split(':');
+
+    if (!isValidIdentifier(CurrentParam)) {
+      S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier)
+          << AL << /*parameter*/2;
+      return false;
+    }
+
+    if (IsMember && CurrentParam == "self") {
+      // "self" indicates the "self" argument for a member.
+
+      // More than one "self"?
+      if (SelfLocation) {
+        S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL;
+        return false;
+      }
+
+      // The "self" location is the current parameter.
+      SelfLocation = SwiftParamCount;
+    } else if (CurrentParam == "newValue") {
+      // "newValue" indicates the "newValue" argument for a setter.
+
+      // There should only be one 'newValue', but it's only significant for
+      // subscript accessors, so don't error right away.
+      ++NewValueCount;
+
+      NewValueLocation = SwiftParamCount;
+    }
+
+    ++SwiftParamCount;
+  } while (!Parameters.empty());
+
+  // Only instance subscripts are currently supported.
+  if (IsSubscript && !SelfLocation) {
+    S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter)
+        << AL << /*have a 'self:' parameter*/2;
+    return false;
+  }
+
+  IsSingleParamInit =
+        SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_";
+
+  // Check the number of parameters for a getter/setter.
+  if (IsGetter || IsSetter) {
+    // Setters have one parameter for the new value.
+    unsigned NumExpectedParams = IsGetter ? 0 : 1;
+    unsigned ParamDiag =
+        IsGetter ? diag::warn_attr_swift_name_getter_parameters
+                 : diag::warn_attr_swift_name_setter_parameters;
+
+    // Instance methods have one parameter for "self".
+    if (SelfLocation)
+      ++NumExpectedParams;
+
+    // Subscripts may have additional parameters beyond the expected params for
+    // the index.
+    if (IsSubscript) {
+      if (SwiftParamCount < NumExpectedParams) {
+        S.Diag(Loc, ParamDiag) << AL;
+        return false;
+      }
+
+      // A subscript setter must explicitly label its newValue parameter to
+      // distinguish it from index parameters.
+      if (IsSetter) {
+        if (!NewValueLocation) {
+          S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue)
+              << AL;
+          return false;
+        }
+        if (NewValueCount > 1) {
+          S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues)
+              << AL;
+          return false;
+        }
+      } else {
+        // Subscript getters should have no 'newValue:' parameter.
+        if (NewValueLocation) {
+          S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue)
+              << AL;
+          return false;
+        }
+      }
+    } else {
+      // Property accessors must have exactly the number of expected params.
+      if (SwiftParamCount != NumExpectedParams) {
+        S.Diag(Loc, ParamDiag) << AL;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
+                             const ParsedAttr &AL) {
+  if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
+    ArrayRef<ParmVarDecl*> Params;
+    unsigned ParamCount;
+
+    if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
+      ParamCount = Method->getSelector().getNumArgs();
+      Params = Method->parameters().slice(0, ParamCount);
+    } else {
+      const auto *F = cast<FunctionDecl>(D);
+
+      ParamCount = F->getNumParams();
+      Params = F->parameters();
+
+      if (!F->hasWrittenPrototype()) {
+        Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL
+            << /* non-K&R-style functions */12;
+        return false;
+      }
+    }
+
+    unsigned SwiftParamCount;
+    bool IsSingleParamInit;
+    if (!validateSwiftFunctionName(*this, AL, Loc, Name,
+                                   SwiftParamCount, IsSingleParamInit))
+      return false;
+
+    bool ParamCountValid;
+    if (SwiftParamCount == ParamCount) {
+      ParamCountValid = true;
+    } else if (SwiftParamCount > ParamCount) {
+      ParamCountValid = IsSingleParamInit && ParamCount == 0;
+    } else {
+      // We have fewer Swift parameters than Objective-C parameters, but that
+      // might be because we've transformed some of them. Check for potential
+      // "out" parameters and err on the side of not warning.
+      unsigned MaybeOutParamCount =
+          std::count_if(Params.begin(), Params.end(),
+                        [](const ParmVarDecl *Param) -> bool {
+        QualType ParamTy = Param->getType();
+        if (ParamTy->isReferenceType() || ParamTy->isPointerType())
+          return !ParamTy->getPointeeType().isConstQualified();
+        return false;
+      });
+
+      ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount;
+    }
+
+    if (!ParamCountValid) {
+      Diag(Loc, diag::warn_attr_swift_name_num_params)
+          << (SwiftParamCount > ParamCount) << AL << ParamCount
+          << SwiftParamCount;
+      return false;
+    }
+  } else if (isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) ||
+             isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) ||
+             isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) ||
+             isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) {
+    StringRef ContextName, BaseName;
+
+    std::tie(ContextName, BaseName) = Name.split('.');
+    if (BaseName.empty()) {
+      BaseName = ContextName;
+      ContextName = StringRef();
+    } else if (!isValidIdentifier(ContextName)) {
+      Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
+          << /*context*/1;
+      return false;
+    }
+
+    if (!isValidIdentifier(BaseName)) {
+      Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL
+          << /*basename*/0;
+      return false;
+    }
+  } else {
+    Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL;
+    return false;
+  }
+  return true;
+}
+
+static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef Name;
+  SourceLocation Loc;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
+    return;
+
+  if (!S.DiagnoseSwiftName(D, Name, Loc, AL))
+    return;
+
+  D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
+}
+
 //===----------------------------------------------------------------------===//
 // Microsoft specific attribute handlers.
 //===----------------------------------------------------------------------===//
@@ -7558,6 +7864,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_SwiftError:
     handleSwiftError(S, D, AL);
     break;
+  case ParsedAttr::AT_SwiftName:
+    handleSwiftName(S, D, AL);
+    break;
   case ParsedAttr::AT_SwiftObjCMembers:
     handleSimpleAttribute<SwiftObjCMembersAttr>(S, D, AL);
     break;
diff --git a/clang/test/SemaObjC/attr-swift_name.m b/clang/test/SemaObjC/attr-swift_name.m
new file mode 100644 (file)
index 0000000..d016842
--- /dev/null
@@ -0,0 +1,174 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc %s
+
+#define SWIFT_NAME(name) __attribute__((__swift_name__(name)))
+
+typedef struct {
+  float x, y, z;
+} Point3D;
+
+__attribute__((__swift_name__("PType")))
+@protocol P
+@end
+
+__attribute__((__swift_name__("IClass")))
+@interface I<P>
+- (instancetype)init SWIFT_NAME("init()");
+- (instancetype)initWithValue:(int)value SWIFT_NAME("iWithValue(_:)");
+
++ (void)refresh SWIFT_NAME("refresh()");
+
+- (instancetype)i SWIFT_NAME("i()");
+
+- (I *)iWithValue:(int)value SWIFT_NAME("i(value:)");
+- (I *)iWithValue:(int)value value:(int)value2 SWIFT_NAME("i(value:extra:)");
+- (I *)iWithValueConvertingValue:(int)value value:(int)value2 SWIFT_NAME("i(_:extra:)");
+
++ (I *)iWithOtheValue:(int)value SWIFT_NAME("init");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
+
++ (I *)iWithAnotherValue:(int)value SWIFT_NAME("i()");
+// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+
++ (I *)iWithYetAnotherValue:(int)value SWIFT_NAME("i(value:extra:)");
+// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2}}
+
++ (I *)iAndReturnErrorCode:(int *)errorCode SWIFT_NAME("i()"); // no-warning
++ (I *)iWithValue:(int)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(value:)"); // no-warning
+
++ (I *)iFromErrorCode:(const int *)errorCode SWIFT_NAME("i()");
+// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+
++ (I *)iWithPointerA:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i()"); // no-warning
++ (I *)iWithPointerB:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(pointer:)"); // no-warning
++ (I *)iWithPointerC:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(pointer:errorCode:)"); // no-warning
+
++ (I *)iWithOtherI:(I *)other SWIFT_NAME("i()");
+// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+
++ (instancetype)specialI SWIFT_NAME("init(options:)");
++ (instancetype)specialJ SWIFT_NAME("init(options:extra:)");
+// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 2)}}
++ (instancetype)specialK SWIFT_NAME("init(_:)");
+// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}}
++ (instancetype)specialL SWIFT_NAME("i(options:)");
+// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}}
+
++ (instancetype)trailingParen SWIFT_NAME("foo(");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
++ (instancetype)trailingColon SWIFT_NAME("foo:");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
++ (instancetype)initialIgnore:(int)value SWIFT_NAME("_(value:)");
+// expected-warning@-1 {{'__swift_name__' attribute has invalid identifier for the base name}}
++ (instancetype)middleOmitted:(int)value SWIFT_NAME("i(:)");
+// expected-warning@-1 {{'__swift_name__' attribute has invalid identifier for the parameter name}}
+
+@property(strong) id someProp SWIFT_NAME("prop");
+@end
+
+enum SWIFT_NAME("E") E {
+  value1,
+  value2,
+  value3 SWIFT_NAME("three"),
+  value4 SWIFT_NAME("four()"), // expected-warning {{'__swift_name__' attribute has invalid identifier for the base name}}
+};
+
+struct SWIFT_NAME("TStruct") SStruct {
+  int i, j, k SWIFT_NAME("kay");
+};
+
+int i SWIFT_NAME("g_i");
+
+void f0(int i) SWIFT_NAME("f_0");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
+
+void f1(int i) SWIFT_NAME("f_1()");
+// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+
+void f2(int i) SWIFT_NAME("f_2(a:b:)");
+// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2)}}
+
+void f3(int x, int y) SWIFT_NAME("fWithX(_:y:)");
+void f4(int x, int *error) SWIFT_NAME("fWithX(_:)");
+
+typedef int int_t SWIFT_NAME("IntType");
+
+struct Point3D createPoint3D(float x, float y, float z) SWIFT_NAME("Point3D.init(x:y:z:)");
+struct Point3D rotatePoint3D(Point3D point, float radians) SWIFT_NAME("Point3D.rotate(self:radians:)");
+struct Point3D badRotatePoint3D(Point3D point, float radians) SWIFT_NAME("Point3D.rotate(radians:)");
+// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 2; got 1)}}
+
+extern struct Point3D identityPoint SWIFT_NAME("Point3D.identity");
+
+float Point3DGetMagnitude(Point3D point) SWIFT_NAME("getter:Point3D.magnitude(self:)");
+float Point3DGetMagnitudeAndSomethingElse(Point3D point, float f) SWIFT_NAME("getter:Point3D.magnitude(self:f:)");
+// expected-warning@-1 {{'__swift_name__' attribute for getter must not have any parameters besides 'self:'}}
+
+float Point3DGetRadius(Point3D point) SWIFT_NAME("getter:Point3D.radius(self:)");
+void Point3DSetRadius(Point3D point, float radius) SWIFT_NAME("setter:Point3D.radius(self:newValue:)");
+
+float Point3DPreGetRadius(Point3D point) SWIFT_NAME("getter:Point3D.preRadius(self:)");
+void Point3DPreSetRadius(float radius, Point3D point) SWIFT_NAME("setter:Point3D.preRadius(newValue:self:)");
+
+void Point3DSetRadiusAndSomethingElse(Point3D point, float radius, float f) SWIFT_NAME("setter:Point3D.radius(self:newValue:f:)");
+// expected-warning@-1 {{'__swift_name__' attribute for setter must have one parameter for new value}}
+
+float Point3DGetComponent(Point3D point, unsigned index) SWIFT_NAME("getter:Point3D.subscript(self:_:)");
+float Point3DSetComponent(Point3D point, unsigned index, float value) SWIFT_NAME("setter:Point3D.subscript(self:_:newValue:)");
+
+float Point3DGetMatrixComponent(Point3D point, unsigned x, unsigned y) SWIFT_NAME("getter:Point3D.subscript(self:x:y:)");
+void Point3DSetMatrixComponent(Point3D point, unsigned x, float value, unsigned y) SWIFT_NAME("setter:Point3D.subscript(self:x:newValue:y:)");
+
+float Point3DSetWithoutNewValue(Point3D point, unsigned x, unsigned y) SWIFT_NAME("setter:Point3D.subscript(self:x:y:)");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' setter must have a 'newValue:' parameter}}
+
+float Point3DSubscriptButNotGetterSetter(Point3D point, unsigned x) SWIFT_NAME("Point3D.subscript(self:_:)");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must be a getter or setter}}
+
+void Point3DSubscriptSetterTwoNewValues(Point3D point, unsigned x, float a, float b) SWIFT_NAME("setter:Point3D.subscript(self:_:newValue:newValue:)");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' setter cannot have multiple 'newValue:' parameters}}
+
+float Point3DSubscriptGetterNewValue(Point3D point, unsigned x, float a, float b) SWIFT_NAME("getter:Point3D.subscript(self:_:newValue:newValue:)");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' getter cannot have a 'newValue:' parameter}}
+
+void Point3DMethodWithNewValue(Point3D point, float newValue) SWIFT_NAME("Point3D.method(self:newValue:)");
+void Point3DMethodWithNewValues(Point3D point, float newValue, float newValueB) SWIFT_NAME("Point3D.method(self:newValue:newValue:)");
+
+float Point3DStaticSubscript(unsigned x) SWIFT_NAME("getter:Point3D.subscript(_:)");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must have a 'self:' parameter}}
+
+float Point3DStaticSubscriptNoArgs(void) SWIFT_NAME("getter:Point3D.subscript()");
+// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must have at least one parameter}}
+
+float Point3DPreGetComponent(Point3D point, unsigned index) SWIFT_NAME("getter:Point3D.subscript(self:_:)");
+
+Point3D getCurrentPoint3D(void) SWIFT_NAME("getter:currentPoint3D()");
+
+void setCurrentPoint3D(Point3D point) SWIFT_NAME("setter:currentPoint3D(newValue:)");
+
+Point3D getLastPoint3D(void) SWIFT_NAME("getter:lastPoint3D()");
+
+void setLastPoint3D(Point3D point) SWIFT_NAME("setter:lastPoint3D(newValue:)");
+
+Point3D getZeroPoint(void) SWIFT_NAME("getter:Point3D.zero()");
+void setZeroPoint(Point3D point) SWIFT_NAME("setter:Point3D.zero(newValue:)");
+Point3D getZeroPointNoPrototype() SWIFT_NAME("getter:Point3D.zeroNoPrototype()");
+// expected-warning@-1 {{'__swift_name__' attribute only applies to non-K&R-style functions}}
+
+Point3D badGetter1(int x) SWIFT_NAME("getter:bad1(_:)");
+// expected-warning@-1 {{'__swift_name__' attribute for getter must not have any parameters besides 'self:'}}
+
+void badSetter1(void) SWIFT_NAME("getter:bad1())");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
+
+Point3D badGetter2(Point3D point) SWIFT_NAME("getter:bad2(_:))");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
+
+void badSetter2(Point3D point) SWIFT_NAME("setter:bad2(self:))");
+// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
+
+void g(int i) SWIFT_NAME("function(int:)");
+// expected-note@-1 {{conflicting attribute is here}}
+
+// expected-error@+1 {{'swift_name' and 'swift_name' attributes are not compatible}}
+void g(int i) SWIFT_NAME("function(_:)") {
+}