Skip to content

Commit 01a90cc

Browse files
committed
Support nil completions in @objcImpl async methods
An async @objc method only checks if its completion handler parameter is null if ClangImporter forces it to. This is fine for @objc with a generated header, because the generated header always declares the parameter _Nonnull, but clients ignore that annotation and pass nil anyway often enough that for @objc @implementation, we ought to be defensive. We can achieve this by simply making the completion handler’s type Optional—SILGen already looks for this and knows what to do when it sees it. Fixes rdar://130527373.
1 parent aab28ee commit 01a90cc

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Diff for: lib/Sema/TypeCheckDeclObjC.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,10 @@ bool swift::isRepresentableInObjC(
869869
ASTExtInfoBuilder(FunctionTypeRepresentation::Block, false, Type())
870870
.build());
871871

872+
// @objcImpl member implementations need to allow a nil completion handler.
873+
if (AFD->isObjCMemberImplementation())
874+
completionHandlerType = OptionalType::get(completionHandlerType);
875+
872876
asyncConvention = ForeignAsyncConvention(
873877
completionHandlerType->getCanonicalType(), completionHandlerParamIndex,
874878
completionHandlerErrorParamIndex,

Diff for: test/IRGen/Inputs/objc_implementation.h

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
- (void)mainMethod:(int)param;
1010

11+
- (void)asyncMethodWithCompletionHandler:(void (^ _Nullable)(void))completion;
12+
1113
@end
1214

1315
@interface ImplClass () <NSMutableCopying>

Diff for: test/IRGen/objc_implementation.swift

+30-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323

2424
// Class
2525
// CHECK: [[selector_data__cxx_destruct:@[^, ]+]] = private global [14 x i8] c".cxx_destruct\00", section "__TEXT,__objc_methname,cstring_literals", align 1
26-
// CHECK-LABEL: @_INSTANCE_METHODS_ImplClass = internal constant { i32, i32, [9 x { ptr, ptr, ptr }] } { i32 24, i32 9, [9 x { ptr, ptr, ptr }] [
26+
// CHECK-LABEL: @_INSTANCE_METHODS_ImplClass = internal constant { i32, i32, [10 x { ptr, ptr, ptr }] } { i32 24, i32 10, [10 x { ptr, ptr, ptr }] [
2727
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" }
2828
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(implProperty)", ptr @".str.7.i16@0:8", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" }
2929
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(setImplProperty:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" }
3030
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(mainMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }
31+
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(asyncMethodWithCompletionHandler:)", ptr @".str.16.v24@0:8@?<v@?>16", ptr @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaFTo{{(\.ptrauth)?}}" }
3132
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(extensionMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VFTo{{(\.ptrauth)?}}" }
3233
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(copyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }
3334
// CHECK-SAME: { ptr, ptr, ptr } { ptr @"\01L_selector_data(mutableCopyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }
@@ -61,6 +62,7 @@
6162
final var implProperty2: NSObject?
6263

6364
@objc func mainMethod(_: Int32) { print(implProperty) }
65+
@objc func asyncMethod() async {}
6466
@objc func extensionMethod(_: Int32) {}
6567

6668
@objc(copyWithZone:)
@@ -130,7 +132,6 @@
130132

131133
// Swift metadata
132134
// CHECK: @"$s19objc_implementationMXM" = linkonce_odr hidden constant <{ i32, i32, i32 }> <{ i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.19.objc_implementation to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32 }>, ptr @"$s19objc_implementationMXM", i32 0, i32 2) to i64)) to i32) }>, section "__TEXT,__constg_swiftt", align 4
133-
// CHECK: @"symbolic So9ImplClassC" = linkonce_odr hidden constant <{ [13 x i8], i8 }> <{ [13 x i8] c"So9ImplClassC", i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
134135
// CHECK: @"$s19objc_implementation13SwiftSubclassCMn" = constant <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }> <{ i32 80, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementationMXM" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.13.SwiftSubclass to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMa" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 3) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMF" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 4) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic So9ImplClassC" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 5) to i64)) to i32), i32 3, i32 10, i32 0, i32 0, i32 10 }>, section "__TEXT,__constg_swiftt", align 4
135136
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ ptr, ptr, ptr, i64, ptr, ptr, ptr, i64, i32, i32, i32, i16, i16, i32, i32, ptr, ptr }> <{ ptr null, ptr @"$s19objc_implementation13SwiftSubclassCfD", ptr @"$sBOWV", i64 ptrtoint (ptr @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), ptr @"OBJC_CLASS_$_ImplClass", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 2), i32 0, i32 0, i32 24, i16 7, i16 0, i32 104, i32 24, ptr @"$s19objc_implementation13SwiftSubclassCMn", ptr null }>, section "__DATA,__objc_data, regular", align 8
136137
// CHECK: @"symbolic _____ 19objc_implementation13SwiftSubclassC" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMn" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i8, i32, i8 }>, ptr @"symbolic _____ 19objc_implementation13SwiftSubclassC", i32 0, i32 1) to i64)) to i32), i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
@@ -237,6 +238,33 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
237238
// ObjC calling convention -[ImplClass mainMethod:]
238239
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo"
239240

241+
// Swift calling convention -[ImplClass asyncMethodWithCompletion:]
242+
// CHECK-LABEL: define hidden swifttailcc void @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaF"
243+
244+
// ObjC calling convention -[ImplClass asyncMethodWithCompletion:]
245+
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaFTo"
246+
// CHECK: call swiftcc void @"$ss29_runTaskForBridgedAsyncMethodyyyyYaYbcnF"(ptr @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaFyyYacfU_To{{[^"]*}}"
247+
248+
// ObjC calling convention -[ImplClass asyncMethodWithCompletion:] (start of helper closure)
249+
// CHECK-LABEL: define linkonce_odr hidden swifttailcc void @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaFyyYacfU_To"
250+
// CHECK: musttail call swifttailcc void @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaF"
251+
252+
// ObjC calling convention -[ImplClass asyncMethodWithCompletion:] (end of helper closure)
253+
// CHECK-LABEL: define internal swifttailcc void @"$sSo9ImplClassC19objc_implementationE11asyncMethodyyYaFyyYacfU_ToTQ0_"
254+
255+
// Make sure this function incorporates a nil check
256+
// CHECK: [[IS_COMPLETION_NULL:%[0-9]+]] = icmp eq i64 {{%\.reload[0-9+]}}, 0
257+
// CHECK: br i1 [[IS_COMPLETION_NULL]], label %[[FINISH:[^,]+]], label %[[RUN_COMPLETION:[^,]+]]
258+
// CHECK: [[RUN_COMPLETION]]:
259+
260+
// The actual call to the block
261+
// CHECK: call void {{%[0-9]+}}
262+
263+
// Final control flow for the nil check
264+
// CHECK: br label %[[FINISH]]
265+
// CHECK: [[FINISH]]:
266+
// CHECK: ret void
267+
240268
// Swift calling convention -[ImplClass extensionMethod:]
241269
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VF"
242270

0 commit comments

Comments
 (0)