Skip to content

Commit 74cbe26

Browse files
Merge pull request #65636 from nate-chandler/rdar108614878
[IRGen] Check for nil in final class cast opt.
2 parents ba2c5e7 + 70cfa6a commit 74cbe26

File tree

3 files changed

+55
-11
lines changed

3 files changed

+55
-11
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,8 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
885885
}
886886
};
887887

888+
bool sourceWrappedInOptional = false;
889+
888890
if (auto sourceOptObjectType = sourceLoweredType.getOptionalObjectType()) {
889891
// Translate the value from an enum representation to a possibly-null
890892
// representation. Note that we assume that this projection is safe
@@ -898,6 +900,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
898900
value = std::move(optValue);
899901
sourceLoweredType = sourceOptObjectType;
900902
sourceFormalType = sourceFormalType.getOptionalObjectType();
903+
sourceWrappedInOptional = true;
901904

902905
// We need a null-check because the runtime function can't handle null in
903906
// some of the cases.
@@ -1021,9 +1024,12 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
10211024
return;
10221025
}
10231026

1024-
if (llvm::Value *fastResult = emitFastClassCastIfPossible(IGF, instance,
1025-
sourceFormalType, targetFormalType)) {
1026-
out.add(fastResult);
1027+
if (llvm::Value *fastResult = emitFastClassCastIfPossible(
1028+
IGF, instance, sourceFormalType, targetFormalType,
1029+
sourceWrappedInOptional, nilCheckBB, nilMergeBB)) {
1030+
Explosion fastExplosion;
1031+
fastExplosion.add(fastResult);
1032+
returnNilCheckedResult(IGF.Builder, fastExplosion);
10271033
return;
10281034
}
10291035

@@ -1039,10 +1045,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
10391045
/// It also avoids a call to the metadata accessor of the class (which calls
10401046
/// `swift_getInitializedObjCClass`). For comparing the metadata pointers it's
10411047
/// not required that the metadata is fully initialized.
1042-
llvm::Value *irgen::emitFastClassCastIfPossible(IRGenFunction &IGF,
1043-
llvm::Value *instance,
1044-
CanType sourceFormalType,
1045-
CanType targetFormalType) {
1048+
llvm::Value *irgen::emitFastClassCastIfPossible(
1049+
IRGenFunction &IGF, llvm::Value *instance, CanType sourceFormalType,
1050+
CanType targetFormalType, bool sourceWrappedInOptional,
1051+
llvm::BasicBlock *&nilCheckBB, llvm::BasicBlock *&nilMergeBB) {
10461052
if (!doesCastPreserveOwnershipForTypes(IGF.IGM.getSILModule(),
10471053
sourceFormalType, targetFormalType)) {
10481054
return nullptr;
@@ -1074,6 +1080,19 @@ llvm::Value *irgen::emitFastClassCastIfPossible(IRGenFunction &IGF,
10741080
if (toClass->checkAncestry() & forbidden)
10751081
return nullptr;
10761082

1083+
// If the source was originally wrapped in an Optional, check it for nil now.
1084+
if (sourceWrappedInOptional) {
1085+
auto isNotNil = IGF.Builder.CreateICmpNE(
1086+
instance, llvm::ConstantPointerNull::get(
1087+
cast<llvm::PointerType>(instance->getType())));
1088+
auto *isNotNilContBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
1089+
nilMergeBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
1090+
nilCheckBB = IGF.Builder.GetInsertBlock();
1091+
IGF.Builder.CreateCondBr(isNotNil, isNotNilContBB, nilMergeBB);
1092+
1093+
IGF.Builder.emitBlock(isNotNilContBB);
1094+
}
1095+
10771096
// Get the metadata pointer of the destination class type.
10781097
llvm::Value *destMetadata = IGF.IGM.getAddrOfTypeMetadata(targetFormalType);
10791098
if (IGF.IGM.IRGen.Opts.LazyInitializeClassMetadata) {

lib/IRGen/GenCast.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
namespace llvm {
2323
class Value;
24+
class BasicBlock;
2425
}
2526

2627
namespace swift {
@@ -56,10 +57,10 @@ namespace irgen {
5657
GenericSignature fnSig,
5758
Explosion &out);
5859

59-
llvm::Value *emitFastClassCastIfPossible(IRGenFunction &IGF,
60-
llvm::Value *instance,
61-
CanType sourceFormalType,
62-
CanType targetFormalType);
60+
llvm::Value *emitFastClassCastIfPossible(
61+
IRGenFunction &IGF, llvm::Value *instance, CanType sourceFormalType,
62+
CanType targetFormalType, bool sourceWrappedInOptional,
63+
llvm::BasicBlock *&nilCheckBB, llvm::BasicBlock *&nilMergeBB);
6364

6465
/// Convert a class object to the given destination type,
6566
/// using a runtime-checked cast.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-run-simple-swift | %FileCheck %s
2+
// REQUIRES: executable_test
3+
4+
final class C {}
5+
6+
struct S {
7+
@inline(never)
8+
func g1<T>(_ componentType: T.Type) -> T? {
9+
return nil
10+
}
11+
@inline(never)
12+
func g2<T>(_ type: T.Type) -> T? {
13+
g1(T.self) as? T
14+
}
15+
}
16+
17+
func run() -> C? {
18+
var e = S()
19+
let r = e.g2(C.self)
20+
return r
21+
}
22+
23+
// CHECK: nil
24+
print(run())

0 commit comments

Comments
 (0)