SIL: Casts that may be to NSError must use indirect cast instructions.

checked_cast_br promises to maintain RC identity, but a cast from an ErrorType-conforming class to NSError may change the RC identity by bridging. Make sure that potential class-to-NSError casts go through the indirect cast entry points for now. The runtime implementation still needs to be fixed to handle the class-to-NSError case, but this is part of rdar://problem/21116814.

Swift SVN r29089
This commit is contained in:
Joe Groff
2015-05-27 22:50:37 +00:00
parent d4448b5c6d
commit 9c0695875e
11 changed files with 86 additions and 34 deletions

View File

@@ -13,8 +13,8 @@
#include "swift/AST/Types.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/DynamicCasts.h"
#include "swift/SIL/TypeLowering.h"
using namespace swift;
using namespace Lowering;
@@ -807,13 +807,41 @@ bool swift::emitSuccessfulIndirectUnconditionalCast(SILBuilder &B, Module *M,
/// things handleable by the scalar checked casts --- and that's not
/// totally unreasonable --- you will need to make the scalar checked
/// casts take a cast consumption kind.
bool swift::canUseScalarCheckedCastInstructions(CanType sourceType,
bool swift::canUseScalarCheckedCastInstructions(SILModule &M,
CanType sourceType,
CanType targetType) {
// Look through one level of optionality on the source.
auto objectType = sourceType;
if (auto type = objectType.getAnyOptionalObjectType())
objectType = type;
// Casting to NSError needs to go through the indirect-cast case,
// since it may conform to ErrorType and require ErrorType-to-NSError
// bridging, unless we can statically see that the source type inherits
// NSError.
// A class-constrained archetype may be bound to NSError, unless it has a
// non-NSError superclass constraint. Casts to archetypes thus must always be
// indirect.
if (auto archetype = targetType->getAs<ArchetypeType>()) {
auto super = archetype->getSuperclass();
if (super.isNull())
return false;
// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
// If NSError wasn't loaded, any base class constraint must not be NSError.
return true;
}
if (targetType == M.Types.getNSErrorType()) {
// If we statically know the target is an NSError subclass, then the cast
// can go through the scalar path (and it's trivially true so can be
// killed).
return targetType->isSuperclassOf(objectType, nullptr);
}
// Three supported cases:
// - metatype to metatype
// - metatype to object
@@ -824,7 +852,7 @@ bool swift::canUseScalarCheckedCastInstructions(CanType sourceType,
if (isa<AnyMetatypeType>(objectType) && isa<AnyMetatypeType>(targetType))
return true;
// Otherwise, we need to use the general indirect-cast functions.
return false;
}
@@ -839,7 +867,8 @@ emitIndirectConditionalCastWithScalar(SILBuilder &B, Module *M,
SILValue dest, CanType targetType,
SILBasicBlock *indirectSuccBB,
SILBasicBlock *indirectFailBB) {
assert(canUseScalarCheckedCastInstructions(sourceType, targetType));
assert(canUseScalarCheckedCastInstructions(B.getModule(),
sourceType, targetType));
// We only need a different failure block if the cast consumption
// requires us to destroy the source value.