Skip to content

Commit 105fcd9

Browse files
committed
SILGen: Bridge id to Any using a stdlib helper.
Bitcast the AnyObject result to AnyObject?, then call our new helper function, so that we can handle nils without choking. Fixes rdar://problem/27874026.
1 parent fbe164a commit 105fcd9

File tree

6 files changed

+51
-22
lines changed

6 files changed

+51
-22
lines changed

include/swift/AST/KnownDecls.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ FUNC_DECL(ConditionallyBridgeFromObjectiveCBridgeable,
6767

6868
FUNC_DECL(BridgeAnythingToObjectiveC,
6969
"_bridgeAnythingToObjectiveC")
70+
FUNC_DECL(BridgeAnyObjectToAny,
71+
"_bridgeAnyObjectToAny")
7072

7173
FUNC_DECL(ConvertToAnyHashable, "_convertToAnyHashable")
7274

lib/SILGen/SILGenBridging.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -704,20 +704,25 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen,
704704
gen.getASTContext().getProtocol(KnownProtocolKind::AnyObject)
705705
->getDeclaredType())
706706
&& "Any should bridge to AnyObject");
707-
708-
// Open the type of the reference and use it to build an Any.
709-
auto openedTy = ArchetypeType::getOpened(loweredBridgedTy);
710-
auto openedSILTy = SILType::getPrimitiveObjectType(openedTy);
707+
711708
// TODO: Ever need to handle +0 values here?
712709
assert(v.hasCleanup());
713-
auto opened = gen.B.createOpenExistentialRef(loc, v.forward(gen),
714-
openedSILTy);
715-
auto result = gen.emitTemporaryAllocation(loc, nativeTy);
716-
auto resultVal = gen.B.createInitExistentialAddr(loc, result,
717-
openedTy, openedSILTy,
718-
{});
719-
gen.B.createStore(loc, opened, resultVal);
720-
return gen.emitManagedRValueWithCleanup(result);
710+
711+
// Use a runtime call to bridge the AnyObject to Any. We do this instead of
712+
// a simple AnyObject-to-Any upcast because the ObjC API may have returned
713+
// a null object in spite of its annotation.
714+
715+
// Bitcast to Optional. This provides a barrier to the optimizer to prevent
716+
// it from attempting to eliminate null checks.
717+
auto optionalBridgedTy = OptionalType::get(loweredBridgedTy)
718+
->getCanonicalType();
719+
auto optionalV = gen.B.createUncheckedBitCast(loc, v.getValue(),
720+
SILType::getPrimitiveObjectType(optionalBridgedTy));
721+
auto optionalMV = ManagedValue(optionalV, v.getCleanup());
722+
return gen.emitApplyOfLibraryIntrinsic(loc,
723+
gen.getASTContext().getBridgeAnyObjectToAny(nullptr),
724+
{}, optionalMV, SGFContext())
725+
.getAsSingleValue(gen, loc);
721726
}
722727

723728
return v;

test/Inputs/ObjCBridging/Appliances.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@
1717
@interface APPManufacturerInfo <DataType> : NSObject
1818
@property (nonatomic,nonnull,readonly) DataType value;
1919
@end
20+
21+
@interface APPBroken : NSObject
22+
@property (nonatomic,nonnull,readonly) id thing;
23+
@end

test/Inputs/ObjCBridging/Appliances.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@ -(instancetype)init {
2626

2727
@implementation APPManufacturerInfo
2828
@end
29+
30+
@implementation APPBroken
31+
32+
- (id _Nonnull)thing {
33+
return (id _Nonnull)nil;
34+
}
35+
36+
@end

test/Interpreter/SDK/objc_bridge.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,12 @@ if let f2 = obj as? Refrigerator {
4747
print("Fridge has temperature \(f2.temperature)")
4848
}
4949

50+
// Check improper nullability auditing of `id` interfaces. `nil` should come
51+
// through as a nonnull `Any` without crashing.
52+
autoreleasepool {
53+
let broken = APPBroken()
54+
let thing = broken.thing
55+
}
56+
5057
// CHECK: DONE
5158
print("DONE")

test/SILGen/objc_bridging_any.swift

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,11 @@ class SwiftIdLover : NSObject, Anyable {
327327
// CHECK: bb0(%0 : $AnyObject, %1 : $SwiftIdLover):
328328
// CHECK-NEXT: strong_retain %0
329329
// CHECK-NEXT: strong_retain %1
330-
// CHECK-NEXT: [[OPENED:%.*]] = open_existential_ref %0
330+
// CHECK-NEXT: [[OPTIONAL:%.*]] = unchecked_ref_cast %0
331+
// CHECK-NEXT: // function_ref
332+
// CHECK-NEXT: [[BRIDGE_TO_ANY:%.*]] = function_ref [[BRIDGE_TO_ANY_FUNC:@.*]] :
331333
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Any
332-
// CHECK-NEXT: [[RESULT_VAL:%.*]] = init_existential_addr [[RESULT]]
333-
// CHECK-NEXT: store [[OPENED]] to [[RESULT_VAL]]
334+
// CHECK-NEXT: [[RESULT_VAL:%.*]] = apply [[BRIDGE_TO_ANY]]([[RESULT]], [[OPTIONAL]])
334335
// CHECK-NEXT: // function_ref
335336
// CHECK-NEXT: [[METHOD:%.*]] = function_ref @_TFC17objc_bridging_any12SwiftIdLover15methodTakingAnyfT1aP__T_
336337
// CHECK-NEXT: apply [[METHOD]]([[RESULT]], %1)
@@ -342,7 +343,7 @@ class SwiftIdLover : NSObject, Anyable {
342343
// CHECK-LABEL: sil hidden @_TFC17objc_bridging_any12SwiftIdLover23methodTakingOptionalAny
343344

344345
// CHECK-LABEL: sil hidden [thunk] @_TToFC17objc_bridging_any12SwiftIdLover23methodTakingOptionalAny
345-
// CHECK: init_existential_addr %11 : $*Any, $@opened({{.*}}) AnyObject
346+
// CHECK: function_ref [[BRIDGE_TO_ANY_FUNC]]
346347

347348
// CHECK-LABEL: sil hidden @_TFC17objc_bridging_any12SwiftIdLover26methodTakingBlockTakingAnyfFP_T_T_ : $@convention(method) (@owned @callee_owned (@in Any) -> (), @guaranteed SwiftIdLover) -> ()
348349

@@ -396,10 +397,11 @@ class SwiftIdLover : NSObject, Anyable {
396397
// CHECK-NEXT: [[FUNCTION:%.*]] = load [[BLOCK_STORAGE_ADDR]]
397398
// CHECK-NEXT: strong_retain [[FUNCTION]]
398399
// CHECK-NEXT: strong_retain %1
399-
// CHECK-NEXT: [[OPENED:%.*]] = open_existential_ref %1
400+
// CHECK-NEXT: [[OPTIONAL:%.*]] = unchecked_ref_cast %1
401+
// CHECK-NEXT: // function_ref
402+
// CHECK-NEXT: [[BRIDGE_TO_ANY:%.*]] = function_ref [[BRIDGE_TO_ANY_FUNC:@.*]] :
400403
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Any
401-
// CHECK-NEXT: [[RESULT_VAL:%.*]] = init_existential_addr [[RESULT]] : $*Any
402-
// CHECK-NEXT: store [[OPENED]] to [[RESULT_VAL]]
404+
// CHECK-NEXT: [[RESULT_VAL:%.*]] = apply [[BRIDGE_TO_ANY]]([[RESULT]], [[OPTIONAL]])
403405
// CHECK-NEXT: apply [[FUNCTION]]([[RESULT]])
404406
// CHECK-NEXT: [[VOID:%.*]] = tuple ()
405407
// CHECK-NEXT: dealloc_stack [[RESULT]]
@@ -425,10 +427,11 @@ class SwiftIdLover : NSObject, Anyable {
425427
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFdCb__aPs9AnyObject__XFo__iP__ : $@convention(thin) (@owned @convention(block) () -> @autoreleased AnyObject) -> @out Any
426428
// CHECK: bb0(%0 : $*Any, %1 : $@convention(block) () -> @autoreleased AnyObject):
427429
// CHECK-NEXT: [[BRIDGED:%.*]] = apply %1()
428-
// CHECK-NEXT: [[OPENED:%.*]] = open_existential_ref [[BRIDGED]]
430+
// CHECK-NEXT: [[OPTIONAL:%.*]] = unchecked_ref_cast [[BRIDGED]]
431+
// CHECK-NEXT: // function_ref
432+
// CHECK-NEXT: [[BRIDGE_TO_ANY:%.*]] = function_ref [[BRIDGE_TO_ANY_FUNC:@.*]] :
429433
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Any
430-
// CHECK-NEXT: [[RESULT_VAL:%.*]] = init_existential_addr [[RESULT]]
431-
// CHECK-NEXT: store [[OPENED]] to [[RESULT_VAL]]
434+
// CHECK-NEXT: [[RESULT_VAL:%.*]] = apply [[BRIDGE_TO_ANY]]([[RESULT]], [[OPTIONAL]])
432435

433436
// TODO: Should elide the copy
434437
// CHECK-NEXT: copy_addr [take] [[RESULT]] to [initialization] %0

0 commit comments

Comments
 (0)