diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2149,6 +2149,13 @@ 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 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/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 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 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4028,7 +4028,12 @@ : Warning<"%0 attribute for 'subscript' getter cannot have a 'newValue:' parameter">, InGroup; 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; +def warn_attr_swift_name_decl_missing_params + : Warning<"%0 attribute cannot be applied to a %select{function|method}1 " + "with no parameters">, InGroup; 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 --- a/clang/include/clang/Sema/Sema.h +++ b/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. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/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(D) || isa(D)) { ArrayRef 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(D); + return false; + } + ParamCount -= 1; + } + unsigned SwiftParamCount; bool IsSingleParamInit; if (!validateSwiftFunctionName(*this, AL, Loc, Name, @@ -5976,10 +5986,11 @@ << SwiftParamCount; return false; } - } else if (isa(D) || isa(D) || - isa(D) || isa(D) || - isa(D) || isa(D) || isa(D) || - isa(D) || isa(D)) { + } else if ((isa(D) || isa(D) || + isa(D) || isa(D) || + isa(D) || isa(D) || isa(D) || + isa(D) || isa(D)) && + !IsAsync) { StringRef ContextName, BaseName; std::tie(ContextName, BaseName) = Name.split('.'); @@ -6010,12 +6021,24 @@ 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 @@ 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 --- 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 --- 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 @@ // 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)}} +// expected-warning@-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@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2}} +// expected-warning@-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@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} +// expected-warning@-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@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} +// expected-warning@-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@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 2)}} +// expected-warning@-1 {{too many parameters in the signature specified by the '__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)}} +// expected-warning@-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@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}} +// expected-warning@-1 {{too many parameters in the signature specified by the '__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}} @@ -82,10 +83,10 @@ // 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)}} +// expected-warning@-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@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2)}} +// expected-warning@-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 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)}} +// expected-warning@-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 @@ // 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

+ +- (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 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@+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@+1 {{'__swift_async_name__' attribute cannot be applied to a method with no parameters}} +- (void)doSomethingNone SWIFT_ASYNC_NAME("doSomething()"); + +// expected-error@+1 {{'__swift_async_name__' attribute takes one argument}} +- (void)brokenAttr __attribute__((__swift_async_name__("brokenAttr", 2))); + +@end + +void asyncFunc(CallbackTy callback) SWIFT_ASYNC_NAME("asyncFunc()"); + +// expected-warning@+1 {{'__swift_async_name__' attribute cannot be applied to a function with no parameters}} +void asyncNoParams(void) SWIFT_ASYNC_NAME("asyncNoParams()"); + +// expected-error@+1 {{'__swift_async_name__' attribute only applies to Objective-C methods and functions}} +SWIFT_ASYNC_NAME("NoAsync") +@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 --- /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@+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()"); +};