[clang] eddd1d1 - [clang] add a `swift_async_name` attribute

Alex Lorenz via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 4 15:56:18 PST 2020


Author: Alex Lorenz
Date: 2020-12-04T15:55:29-08:00
New Revision: eddd1d192bcaf11e449b34a3a569b85eb390e4f2

URL: https://github.com/llvm/llvm-project/commit/eddd1d192bcaf11e449b34a3a569b85eb390e4f2
DIFF: https://github.com/llvm/llvm-project/commit/eddd1d192bcaf11e449b34a3a569b85eb390e4f2.diff

LOG: [clang] add a `swift_async_name` attribute

The swift_async_name attribute provides a name for a function/method that can be used
to call the async overload of this method from Swift. This name specified in this attribute
assumes that the last parameter in the function/method its applied to is removed when
Swift invokes it, as the the Swift's await/async transformation implicitly constructs the callback.

Differential Revision: https://reviews.llvm.org/D92355

Added: 
    clang/test/SemaObjCXX/attr-swift_name-cxx.mm

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Misc/pragma-attribute-supported-attributes-list.test
    clang/test/SemaObjC/attr-swift_name.m

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 3beef7b89243..0212b60a2afe 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2149,6 +2149,13 @@ def Regparm : TypeAttr {
   let ASTNode = 0;
 }
 
+def SwiftAsyncName : InheritableAttr {
+  let Spellings = [GNU<"swift_async_name">];
+  let Args = [StringArgument<"Name">];
+  let Subjects = SubjectList<[ObjCMethod, Function], ErrorDiag>;
+  let Documentation = [SwiftAsyncNameDocs];
+}
+
 def SwiftAttr : InheritableAttr {
   let Spellings = [GNU<"swift_attr">];
   let Args = [StringArgument<"Attribute">];

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 673c9553c83d..bf985986e21b 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3628,6 +3628,27 @@ Swift.
   }];
 }
 
+def SwiftAsyncNameDocs : Documentation {
+  let Category = SwiftDocs;
+  let Heading = "swift_async_name";
+  let Content = [{
+The ``swift_async_name`` attribute provides the name of the ``async`` overload for
+the given 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 or
+method. The name may be a compound Swift name. The function or method with such
+an attribute must have more than zero parameters, as its last parameter is
+assumed to be a callback that's eliminated in the Swift ``async`` name.
+
+  .. code-block:: objc
+
+    @interface URL
+    + (void) loadContentsFrom:(URL *)url callback:(void (^)(NSData *))data __attribute__((__swift_async_name__("URL.loadContentsFrom(_:)")))
+    @end
+  }];
+}
+
 def SwiftAttrDocs : Documentation {
   let Category = SwiftDocs;
   let Heading = "swift_attr";

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f51ef849b932..21660965abf7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4028,7 +4028,12 @@ 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)">,
+  : Warning<"too %select{few|many}0 parameters in the signature specified by "
+            "the %1 attribute (expected %2; got %3)">,
+    InGroup<SwiftNameAttribute>;
+def warn_attr_swift_name_decl_missing_params
+  : Warning<"%0 attribute cannot be applied to a %select{function|method}1 "
+            "with no parameters">,
     InGroup<SwiftNameAttribute>;
 
 def err_attr_swift_error_no_error_parameter : Error<

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b3ede504542f..980be69cb1a5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1977,7 +1977,7 @@ class Sema final {
   ///
   /// \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);
+                         const ParsedAttr &AL, bool IsAsync);
 
   /// 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.

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index e0aa6d1f119c..a3153979deff 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5922,7 +5922,7 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
 }
 
 bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
-                             const ParsedAttr &AL) {
+                             const ParsedAttr &AL, bool IsAsync) {
   if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
     ArrayRef<ParmVarDecl*> Params;
     unsigned ParamCount;
@@ -5943,6 +5943,16 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
       }
     }
 
+    // The async name drops the last callback parameter.
+    if (IsAsync) {
+      if (ParamCount == 0) {
+        Diag(Loc, diag::warn_attr_swift_name_decl_missing_params)
+            << AL << isa<ObjCMethodDecl>(D);
+        return false;
+      }
+      ParamCount -= 1;
+    }
+
     unsigned SwiftParamCount;
     bool IsSingleParamInit;
     if (!validateSwiftFunctionName(*this, AL, Loc, Name,
@@ -5976,10 +5986,11 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
           << 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)) {
+  } 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)) &&
+             !IsAsync) {
     StringRef ContextName, BaseName;
 
     std::tie(ContextName, BaseName) = Name.split('.');
@@ -6010,12 +6021,24 @@ static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
     return;
 
-  if (!S.DiagnoseSwiftName(D, Name, Loc, AL))
+  if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false))
     return;
 
   D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
 }
 
+static void handleSwiftAsyncName(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, /*IsAsync=*/true))
+    return;
+
+  D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name));
+}
+
 static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
   // Make sure that there is an identifier as the annotation's single argument.
   if (!checkAttributeNumArgs(S, AL, 1))
@@ -7951,6 +7974,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
     break;
 
   // Swift attributes.
+  case ParsedAttr::AT_SwiftAsyncName:
+    handleSwiftAsyncName(S, D, AL);
+    break;
   case ParsedAttr::AT_SwiftAttr:
     handleSwiftAttrAttr(S, D, AL);
     break;

diff  --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index f67e2eee5818..96cabfc195b3 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -147,6 +147,7 @@
 // CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
 // CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
 // CHECK-NEXT: SpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: SwiftAsyncName (SubjectMatchRule_objc_method, SubjectMatchRule_function)
 // CHECK-NEXT: SwiftBridgedTypedef (SubjectMatchRule_type_alias)
 // CHECK-NEXT: SwiftContext (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: SwiftError (SubjectMatchRule_function, SubjectMatchRule_objc_method)

diff  --git a/clang/test/SemaObjC/attr-swift_name.m b/clang/test/SemaObjC/attr-swift_name.m
index d0168426b70e..6872b04cd5e9 100644
--- a/clang/test/SemaObjC/attr-swift_name.m
+++ b/clang/test/SemaObjC/attr-swift_name.m
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc -fblocks %s
 
 #define SWIFT_NAME(name) __attribute__((__swift_name__(name)))
+#define SWIFT_ASYNC_NAME(name) __attribute__((__swift_async_name__(name)))
 
 typedef struct {
   float x, y, z;
@@ -27,31 +28,31 @@ + (I *)iWithOtheValue:(int)value SWIFT_NAME("init");
 // expected-warning at -1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
 
 + (I *)iWithAnotherValue:(int)value SWIFT_NAME("i()");
-// expected-warning at -1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+// expected-warning at -1 {{too few parameters in the signature specified by the '__swift_name__' attribute (expected 1; got 0)}}
 
 + (I *)iWithYetAnotherValue:(int)value SWIFT_NAME("i(value:extra:)");
-// expected-warning at -1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2}}
+// expected-warning at -1 {{too many parameters in the signature specified by the '__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 at -1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+// expected-warning at -1 {{too few parameters in the signature specified by the '__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 at -1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+// expected-warning at -1 {{too few parameters in the signature specified by the '__swift_name__' attribute (expected 1; got 0)}}
 
 + (instancetype)specialI SWIFT_NAME("init(options:)");
 + (instancetype)specialJ SWIFT_NAME("init(options:extra:)");
-// expected-warning at -1 {{too many parameters in '__swift_name__' attribute (expected 0; got 2)}}
+// expected-warning at -1 {{too many parameters in the signature specified by the '__swift_name__' attribute (expected 0; got 2)}}
 + (instancetype)specialK SWIFT_NAME("init(_:)");
-// expected-warning at -1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}}
+// expected-warning at -1 {{too many parameters in the signature specified by the '__swift_name__' attribute (expected 0; got 1)}}
 + (instancetype)specialL SWIFT_NAME("i(options:)");
-// expected-warning at -1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}}
+// expected-warning at -1 {{too many parameters in the signature specified by the '__swift_name__' attribute (expected 0; got 1)}}
 
 + (instancetype)trailingParen SWIFT_NAME("foo(");
 // expected-warning at -1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}}
@@ -82,10 +83,10 @@ struct SWIFT_NAME("TStruct") SStruct {
 // expected-warning at -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 at -1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}}
+// expected-warning at -1 {{too few parameters in the signature specified by the '__swift_name__' attribute (expected 1; got 0)}}
 
 void f2(int i) SWIFT_NAME("f_2(a:b:)");
-// expected-warning at -1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2)}}
+// expected-warning at -1 {{too many parameters in the signature specified by the '__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(_:)");
@@ -95,7 +96,7 @@ struct SWIFT_NAME("TStruct") SStruct {
 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 at -1 {{too few parameters in '__swift_name__' attribute (expected 2; got 1)}}
+// expected-warning at -1 {{too few parameters in the signature specified by the '__swift_name__' attribute (expected 2; got 1)}}
 
 extern struct Point3D identityPoint SWIFT_NAME("Point3D.identity");
 
@@ -172,3 +173,33 @@ struct SWIFT_NAME("TStruct") SStruct {
 // expected-error at +1 {{'swift_name' and 'swift_name' attributes are not compatible}}
 void g(int i) SWIFT_NAME("function(_:)") {
 }
+
+typedef int (^CallbackTy)(void);
+
+ at interface AsyncI<P>
+
+- (void)doSomethingWithCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething()");
+- (void)doSomethingX:(int)x withCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething(x:)");
+
+// expected-warning at +1 {{too many parameters in the signature specified by the '__swift_async_name__' attribute (expected 1; got 2)}}
+- (void)doSomethingY:(int)x withCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething(x:y:)");
+
+// expected-warning at +1 {{too few parameters in the signature specified by the '__swift_async_name__' attribute (expected 1; got 0)}}
+- (void)doSomethingZ:(int)x withCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething()");
+
+// expected-warning at +1 {{'__swift_async_name__' attribute cannot be applied to a method with no parameters}}
+- (void)doSomethingNone SWIFT_ASYNC_NAME("doSomething()");
+
+// expected-error at +1 {{'__swift_async_name__' attribute takes one argument}}
+- (void)brokenAttr __attribute__((__swift_async_name__("brokenAttr", 2)));
+
+ at end
+
+void asyncFunc(CallbackTy callback) SWIFT_ASYNC_NAME("asyncFunc()");
+
+// expected-warning at +1 {{'__swift_async_name__' attribute cannot be applied to a function with no parameters}}
+void asyncNoParams(void) SWIFT_ASYNC_NAME("asyncNoParams()");
+
+// expected-error at +1 {{'__swift_async_name__' attribute only applies to Objective-C methods and functions}}
+SWIFT_ASYNC_NAME("NoAsync")
+ at protocol NoAsync @end

diff  --git a/clang/test/SemaObjCXX/attr-swift_name-cxx.mm b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm
new file mode 100644
index 000000000000..658dbfff185c
--- /dev/null
+++ b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc -fblocks %s
+
+#define SWIFT_ASYNC_NAME(name) __attribute__((__swift_async_name__(name)))
+
+typedef int (^CallbackTy)(void);
+
+class CXXClass {
+public:
+  virtual void doSomethingWithCallback(CallbackTy callback) SWIFT_ASYNC_NAME("doSomething()");
+
+  // expected-warning at +1 {{too few parameters in the signature specified by the '__swift_async_name__' attribute (expected 1; got 0)}}
+  virtual void doSomethingWithCallback(int x, CallbackTy callback) SWIFT_ASYNC_NAME("doSomething()");
+};


        


More information about the cfe-commits mailing list