[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
This commit is contained in:
parent
03dcd57ecf
commit
eddd1d192b
|
@ -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">];
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -1977,7 +1977,7 @@ public:
|
|||
///
|
||||
/// \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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ __attribute__((__swift_name__("IClass")))
|
|||
// 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 @@ 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)}}
|
||||
// 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 @@ 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)}}
|
||||
// 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 @@ void g(int i) SWIFT_NAME("function(int:)");
|
|||
// 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 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
|
||||
|
|
|
@ -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()");
|
||||
};
|
Loading…
Reference in New Issue