arphaman created this revision.
arphaman added reviewers: erik.pilkington, aaron.ballman.
Herald added subscribers: ributzka, jkorous.
Herald added a project: clang.
arphaman requested review of this revision.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D92355

Files:
  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/SemaObjC/attr-swift_name.m

Index: clang/test/SemaObjC/attr-swift_name.m
===================================================================
--- clang/test/SemaObjC/attr-swift_name.m
+++ 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;
@@ -172,3 +173,28 @@
 // expected-error@+1 {{'swift_name' and 'swift_name' attributes are not compatible}}
 void g(int i) SWIFT_NAME("function(_:)") {
 }
+
+typedef int (^CallbackTy)(void);
+
+@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@+1 {{too many parameters in '__swift_async_name__' attribute (expected 1; got 2)}}
+- (void)doSomethingY:(int)x withCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething(x:y:)");
+
+// expected-warning@+1 {{too few parameters in '__swift_async_name__' attribute (expected 1; got 0)}}
+- (void)doSomethingZ:(int)x withCallback:(CallbackTy)callback SWIFT_ASYNC_NAME("doSomething()");
+
+// expected-warning@+1 {{'__swift_async_name__' attribute cannot be applied to a method with no parameters}}
+- (void)doSomethingNone SWIFT_ASYNC_NAME("doSomething()");
+
+@end
+
+// expected-warning@+1 {{'__swift_async_name__' attribute cannot be applied to a function with no parameters}}
+void asyncNoParams(void) SWIFT_ASYNC_NAME("asyncNoParams()");
+
+// expected-warning@+1 {{'__swift_async_name__' attribute cannot be applied to this declaration}}
+SWIFT_ASYNC_NAME("NoAsync")
+@protocol NoAsync @end
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5922,7 +5922,7 @@
 }
 
 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 @@
       }
     }
 
+    // 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) ? 1 : 0);
+        return false;
+      }
+      ParamCount -= 1;
+    }
+
     unsigned SwiftParamCount;
     bool IsSingleParamInit;
     if (!validateSwiftFunctionName(*this, AL, Loc, Name,
@@ -5976,10 +5986,11 @@
           << 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('.');
@@ -6004,16 +6015,20 @@
   return true;
 }
 
-static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
+static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL,
+                            bool IsAsync = false) {
   StringRef Name;
   SourceLocation Loc;
   if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
     return;
 
-  if (!S.DiagnoseSwiftName(D, Name, Loc, AL))
+  if (!S.DiagnoseSwiftName(D, Name, Loc, AL, IsAsync))
     return;
 
-  D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
+  D->addAttr(IsAsync ? (Attr *)::new (S.Context)
+                           SwiftAsyncNameAttr(S.Context, AL, Name)
+                     : (Attr *)::new (S.Context)
+                           SwiftNameAttr(S.Context, AL, Name));
 }
 
 static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -7951,6 +7966,9 @@
     break;
 
   // Swift attributes.
+  case ParsedAttr::AT_SwiftAsyncName:
+    handleSwiftName(S, D, AL, /*IsAsync=*/true);
+    break;
   case ParsedAttr::AT_SwiftAttr:
     handleSwiftAttrAttr(S, D, AL);
     break;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1977,7 +1977,7 @@
   ///
   /// \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.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4030,6 +4030,10 @@
 def warn_attr_swift_name_num_params
   : Warning<"too %select{few|many}0 parameters in %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<
   "%0 attribute can only be applied to a %select{function|method}1 with an "
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3628,6 +3628,27 @@
   }];
 }
 
+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 of 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";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2149,6 +2149,12 @@
   let ASTNode = 0;
 }
 
+def SwiftAsyncName : InheritableAttr {
+  let Spellings = [GNU<"swift_async_name">];
+  let Args = [StringArgument<"Name">];
+  let Documentation = [SwiftAsyncNameDocs];
+}
+
 def SwiftAttr : InheritableAttr {
   let Spellings = [Clang<"swift_attr">];
   let Args = [StringArgument<"Attribute">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to