Skip to content

Commit 825d11a

Browse files
authored
Merge pull request #60401 from kavon/5.7-fix-97646309
[5.7🍒] Fix crash when emitting force-unwrap-and-call expression for optional ObjC methods
2 parents e237b4b + 726775f commit 825d11a

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,39 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
15921592
return std::move(*applyCallee);
15931593
}
15941594

1595+
/// \returns true if the conversion is from an async function to
1596+
/// the same type but with a global actor added. For example this:
1597+
/// () async -> () ==> @MainActor () async -> ()
1598+
/// will return true. In all other cases, returns false.
1599+
static bool addsGlobalActorToAsyncFn(FunctionConversionExpr *fce) {
1600+
CanType oldTy = fce->getSubExpr()->getType()->getCanonicalType();
1601+
CanType newTy = fce->getType()->getCanonicalType();
1602+
1603+
if (auto oldFnTy = dyn_cast<AnyFunctionType>(oldTy)) {
1604+
if (auto newFnTy = dyn_cast<AnyFunctionType>(newTy)) {
1605+
// old type MUST be async
1606+
if (!oldFnTy->hasEffect(EffectKind::Async))
1607+
return false;
1608+
1609+
// old type MUST NOT have a global actor
1610+
if (oldFnTy->hasGlobalActor())
1611+
return false;
1612+
1613+
// new type MUST have a global actor
1614+
if (!newFnTy->hasGlobalActor())
1615+
return false;
1616+
1617+
// see if adding the global actor to the old type yields the new type.
1618+
auto globalActor = newFnTy->getGlobalActor();
1619+
auto addedActor = oldFnTy->getExtInfo().withGlobalActor(globalActor);
1620+
1621+
return oldFnTy->withExtInfo(addedActor) == newFnTy;
1622+
}
1623+
}
1624+
1625+
return false;
1626+
}
1627+
15951628
/// Ignore parentheses and implicit conversions.
15961629
static Expr *ignoreParensAndImpConversions(Expr *expr) {
15971630
while (true) {
@@ -1605,7 +1638,16 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
16051638
// works given that we check the result for certain forms.
16061639
if (auto eval = dyn_cast<OptionalEvaluationExpr>(expr)) {
16071640
if (auto inject = dyn_cast<InjectIntoOptionalExpr>(eval->getSubExpr())) {
1608-
if (auto bind = dyn_cast<BindOptionalExpr>(inject->getSubExpr())) {
1641+
1642+
auto nextSubExpr = inject->getSubExpr();
1643+
1644+
// skip over a specific, known no-op function conversion, if it exists
1645+
if (auto funcConv = dyn_cast<FunctionConversionExpr>(nextSubExpr)) {
1646+
if (addsGlobalActorToAsyncFn(funcConv))
1647+
nextSubExpr = funcConv->getSubExpr();
1648+
}
1649+
1650+
if (auto bind = dyn_cast<BindOptionalExpr>(nextSubExpr)) {
16091651
if (bind->getDepth() == 0)
16101652
return bind->getSubExpr();
16111653
}

test/ClangImporter/objc_async.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,11 @@ extension SomeWrapper: Sendable where T: Sendable {}
393393
}
394394
}
395395
}
396+
397+
// rdar://97646309 -- lookup and direct call of an optional global-actor constrained method would crash in SILGen
398+
@available(SwiftStdlib 5.5, *)
399+
extension CoffeeDelegate {
400+
@MainActor func test() async -> (NSObject?, NSObject, NSObject) {
401+
return await self.icedMochaServiceGenerateMocha!(NSObject())
402+
}
403+
}

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,4 +319,12 @@ SENDABLE id StructWithSendableContentsGetSendableComputed(struct StructWithSenda
319319
+ (void)getAsCustomer:(void(^_Nonnull)(NSObject *device))completion;
320320
@end
321321

322+
323+
// rdar://97646309
324+
UI_ACTOR
325+
@protocol CoffeeDelegate <NSObject>
326+
@optional
327+
- (void)icedMochaService:(NSObject *)mochaService generateMochaWithCompletion:(void (^)(NSObject *_Nullable ingredient1, NSObject *ingredient2, NSObject *ingredient3))completionHandler;
328+
@end
329+
322330
#pragma clang assume_nonnull end

test/SILGen/dynamic_lookup.swift

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
// RUN: %target-swift-emit-silgen -module-name dynamic_lookup -enable-objc-interop -parse-as-library -disable-objc-attr-requires-foundation-module %s | %FileCheck %s
2-
// RUN: %target-swift-emit-silgen -module-name dynamic_lookup -enable-objc-interop -parse-as-library -disable-objc-attr-requires-foundation-module %s | %FileCheck %s --check-prefix=GUARANTEED
1+
// RUN: %target-swift-emit-silgen -module-name dynamic_lookup -enable-objc-interop -parse-as-library -disable-objc-attr-requires-foundation-module -disable-availability-checking %s | %FileCheck %s
2+
// RUN: %target-swift-emit-silgen -module-name dynamic_lookup -enable-objc-interop -parse-as-library -disable-objc-attr-requires-foundation-module -disable-availability-checking %s | %FileCheck %s --check-prefix=GUARANTEED
3+
4+
// REQUIRES: objc_interop
5+
// REQUIRES: concurrency
36

47
class X {
58
@objc func f() { }
@@ -405,3 +408,25 @@ func testAnyObjectWithDefault(_ x: AnyObject) {
405408
// CHECK: apply [[METHOD]]([[DEFARG]], [[OPENEDX]])
406409
x.hasDefaultParam()
407410
}
411+
412+
413+
// rdar://97646309 -- lookup and direct call of an optional global-actor constrained method would crash in SILGen
414+
@MainActor
415+
@objc protocol OptionalMemberLookups {
416+
@objc optional func generateMaybe() async
417+
}
418+
419+
extension OptionalMemberLookups {
420+
// CHECK-LABEL: sil hidden [ossa] @$s14dynamic_lookup21OptionalMemberLookupsPAAE19testForceDirectCallyyYaF
421+
// CHECK: [[SELF:%[0-9]+]] = copy_value {{.*}} : $Self
422+
// CHECK: [[METH:%[0-9]+]] = objc_method {{.*}} : $Self, #OptionalMemberLookups.generateMaybe!foreign : <Self where Self : OptionalMemberLookups> (Self) -> () async -> (), $@convention(objc_method) (@convention(block) () -> (), Self) -> ()
423+
// CHECK: = function_ref @$sIeyB_yt14dynamic_lookup21OptionalMemberLookupsRzlTz_ : $@convention(c) @pseudogeneric <τ_0_0 where τ_0_0 : OptionalMemberLookups> (@inout_aliasable @block_storage UnsafeContinuation<(), Never>) -> ()
424+
// CHECK: [[BLOCK:%[0-9]+]] = init_block_storage_header {{.*}} : $*@block_storage UnsafeContinuation<(), Never>
425+
// CHECK: = apply [[METH]]([[BLOCK]], [[SELF]]) : $@convention(objc_method) (@convention(block) () -> (), Self) -> ()
426+
// CHECK: await_async_continuation {{.*}} : $Builtin.RawUnsafeContinuation, resume bb1
427+
// CHECK: hop_to_executor {{.*}} : $MainActor
428+
// CHECK: } // end sil function '$s14dynamic_lookup21OptionalMemberLookupsPAAE19testForceDirectCallyyYaF'
429+
func testForceDirectCall() async -> Void {
430+
await self.generateMaybe!()
431+
}
432+
}

0 commit comments

Comments
 (0)