@@ -478,13 +478,8 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
478
478
CheckedCastMode mode) {
479
479
// If ObjC interop is enabled, casting a metatype to AnyObject succeeds
480
480
// if the metatype is for a class.
481
-
482
- auto triviallyFail = [&]() -> llvm::Value* {
483
- return llvm::ConstantPointerNull::get (IGF.IGM .ObjCPtrTy );
484
- };
485
-
486
481
if (!IGF.IGM .ObjCInterop )
487
- return triviallyFail () ;
482
+ return nullptr ;
488
483
489
484
switch (type->getRepresentation ()) {
490
485
case MetatypeRepresentation::ObjC:
@@ -496,7 +491,7 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
496
491
// TODO: Final class metatypes could in principle be thin.
497
492
assert (!type.getInstanceType ()->mayHaveSuperclass ()
498
493
&& " classes should not have thin metatypes (yet)" );
499
- return triviallyFail () ;
494
+ return nullptr ;
500
495
501
496
case MetatypeRepresentation::Thick: {
502
497
auto instanceTy = type.getInstanceType ();
@@ -508,10 +503,10 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
508
503
return IGF.Builder .CreateBitCast (heapMetadata, IGF.IGM .ObjCPtrTy );
509
504
}
510
505
511
- // Is the type obviously not a class?
512
- if (!isa<ArchetypeType>(instanceTy)
513
- && !isa<ExistentialMetatypeType>(type))
514
- return triviallyFail ();
506
+ // If it's not a class, we can't handle it here
507
+ if (!isa<ArchetypeType>(instanceTy) && !isa<ExistentialMetatypeType>(type)) {
508
+ return nullptr ;
509
+ }
515
510
516
511
// Ask the runtime whether this is class metadata.
517
512
llvm::Constant *castFn;
@@ -966,10 +961,43 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
966
961
// Otherwise, this is a metatype-to-object cast.
967
962
assert (targetLoweredType.isAnyClassReferenceType ());
968
963
969
- // Convert the metatype value to AnyObject.
964
+ // Can we convert the metatype value to AnyObject using Obj-C machinery?
970
965
llvm::Value *object =
971
966
emitMetatypeToAnyObjectDowncast (IGF, metatypeVal, sourceMetatype, mode);
972
967
968
+ if (object == nullptr ) {
969
+ // Obj-C cast routine failed, use swift_dynamicCast instead
970
+
971
+ if (sourceMetatype->getRepresentation () == MetatypeRepresentation::Thin
972
+ || metatypeVal == nullptr ) {
973
+ // Earlier stages *should* never generate a checked cast with a thin metatype argument.
974
+ // TODO: Move this assertion up to apply to all checked cast operations.
975
+ // In assert builds, enforce this by failing here:
976
+ assert (false && " Invalid SIL: General checked_cast_br cannot have thin argument" );
977
+ // In non-assert builds, stay compatible with previous behavior by emitting a null load.
978
+ object = llvm::ConstantPointerNull::get (IGF.IGM .ObjCPtrTy );
979
+ } else {
980
+ Address src = IGF.createAlloca (metatypeVal->getType (),
981
+ IGF.IGM .getPointerAlignment (),
982
+ " castSrc" );
983
+ IGF.Builder .CreateStore (metatypeVal, src);
984
+ llvm::PointerType *destPtrType = IGF.IGM .getStoragePointerType (targetLoweredType);
985
+ Address dest = IGF.createAlloca (destPtrType,
986
+ IGF.IGM .getPointerAlignment (),
987
+ " castDest" );
988
+ IGF.Builder .CreateStore (llvm::ConstantPointerNull::get (destPtrType), dest);
989
+ llvm::Value *success = emitCheckedCast (IGF,
990
+ src, sourceFormalType,
991
+ dest, targetFormalType,
992
+ CastConsumptionKind::TakeAlways,
993
+ mode);
994
+ llvm::Value *successResult = IGF.Builder .CreateLoad (dest);
995
+ llvm::Value *failureResult = llvm::ConstantPointerNull::get (destPtrType);
996
+ llvm::Value *result = IGF.Builder .CreateSelect (success, successResult, failureResult);
997
+ object = std::move (result);
998
+ }
999
+ }
1000
+
973
1001
sourceFormalType = IGF.IGM .Context .getAnyObjectType ();
974
1002
sourceLoweredType = SILType::getPrimitiveObjectType (sourceFormalType);
975
1003
0 commit comments