[llvm-branch-commits] [clang] eddd1d1 - [clang] add a `swift_async_name` attribute
Alex Lorenz via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Dec 4 16:00:52 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 llvm-branch-commits
mailing list