Sema/SIL: NSError has no special powers without ObjC interop.

In particular, it doesn't "toll-free bridge" to the Error existential on non-ObjC-interop platforms, and we would miscompile as if it could. This should fix SR-585.
This commit is contained in:
Joe Groff
2017-02-24 18:41:11 -08:00
parent 55fe16b1bd
commit d998692b60
15 changed files with 262 additions and 182 deletions

View File

@@ -1139,23 +1139,30 @@ bool swift::canUseScalarCheckedCastInstructions(SILModule &M,
// 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;
// Only ever permit this if the source type is a reference type.
if (!objectType.isAnyClassReferenceType())
return false;
if (M.getASTContext().LangOpts.EnableObjCInterop) {
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;
// 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;
} else {
// If ObjC bridging isn't enabled, we can do a scalar cast from any
// reference type to any class-constrained archetype.
return archetype->requiresClass();
}
}
if (targetType == M.Types.getNSErrorType()) {
if (M.getASTContext().LangOpts.EnableObjCInterop
&& targetType == M.Types.getNSErrorType()) {
// If we statically know the source is an NSError subclass, then the cast
// can go through the scalar path (and it's trivially true so can be
// killed).

View File

@@ -460,6 +460,10 @@ SILType SILType::unwrapAnyOptionalType() const {
/// Error existentials.
static bool isBridgedErrorClass(SILModule &M,
Type t) {
// There's no bridging if ObjC interop is disabled.
if (!M.getASTContext().LangOpts.EnableObjCInterop)
return false;
if (!t)
return false;

View File

@@ -3351,6 +3351,10 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
Type type2,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
// There's no bridging without ObjC interop.
if (!TC.Context.LangOpts.EnableObjCInterop)
return SolutionKind::Error;
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
/// Form an unresolved result.

View File

@@ -3365,16 +3365,18 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
// We can conditionally cast from NSError to an Error-conforming
// type. This is handled in the runtime, so it doesn't need a special cast
// kind.
if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
if (conformsToProtocol(toType, errorTypeProto, dc,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::Used)))
if (auto NSErrorTy = getNSErrorType(dc))
if (isSubtypeOf(fromType, NSErrorTy, dc)
// Don't mask "always true" warnings if NSError is cast to
// Error itself.
&& !isSubtypeOf(fromType, toType, dc))
return CheckedCastKind::ValueCast;
if (Context.LangOpts.EnableObjCInterop) {
if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
if (conformsToProtocol(toType, errorTypeProto, dc,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::Used)))
if (auto NSErrorTy = getNSErrorType(dc))
if (isSubtypeOf(fromType, NSErrorTy, dc)
// Don't mask "always true" warnings if NSError is cast to
// Error itself.
&& !isSubtypeOf(fromType, toType, dc))
return CheckedCastKind::ValueCast;
}
}
// The runtime doesn't support casts to CF types and always lets them succeed.

View File

@@ -244,14 +244,6 @@ bb0:
bridge_object_to_word undef : $Builtin.BridgeObject to $Builtin.Word
// CHECK: thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
// CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
// CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
// CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
// CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
// CHECK: is_nonnull undef : $C
is_nonnull undef : $C

View File

@@ -0,0 +1,23 @@
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil %s | %target-sil-opt -assume-parsing-unqualified-ownership-sil | %FileCheck %s
// REQUIRES: objc_interop
sil_stage raw
import Builtin
import Swift
protocol P { }
class C { }
sil @general_test : $() -> () {
bb0:
// CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
// CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
// CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
// CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
unreachable
}

View File

@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
protocol ClassBound : class {}
protocol NotClassBound {}
@@ -57,16 +57,21 @@ func opaque_archetype_is_class_archetype
func class_archetype_to_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T) -> U {
return t as! U
// CHECK: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: return [[DOWNCAST]] : $U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK-objc: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
// CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK-objc: return [[DOWNCAST]] : $U
// CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $T to $U
}
// CHECK-LABEL: sil hidden @_TF13generic_casts34class_archetype_is_class_archetype{{.*}}
func class_archetype_is_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
return t is U
// CHECK: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK-objc: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
// CHECK-native: checked_cast_br {{.*}} : $T to $U
}
// CHECK-LABEL: sil hidden @_TF13generic_casts38opaque_archetype_to_addr_only_concrete{{.*}}
@@ -156,16 +161,19 @@ func opaque_existential_is_class_archetype
func class_existential_to_class_archetype
<T:ClassBound>(_ p:ClassBound) -> T {
return p as! T
// CHECK: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: return [[DOWNCAST]] : $T
// CHECK-objc: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
// CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK-objc: return [[DOWNCAST]] : $T
// CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $ClassBound to $T
}
// CHECK-LABEL: sil hidden @_TF13generic_casts36class_existential_is_class_archetype{{.*}}
func class_existential_is_class_archetype
<T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
return p is T
// CHECK: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
// CHECK-objc: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
// CHECK-native: checked_cast_br {{.*}} : $ClassBound to $T
}
// CHECK-LABEL: sil hidden @_TF13generic_casts40opaque_existential_to_addr_only_concrete{{.*}}

View File

@@ -720,104 +720,6 @@ bb2:
%33 = return %32 : $()
}
// CHECK-LABEL: sil @cse_value_metatype
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_value_metatype : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}
@objc(XX) protocol XX {
}
// CHECK-LABEL: sil @cse_existential_metatype
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_existential_metatype : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @nocse_existential_metatype_addr
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: return
sil @nocse_existential_metatype_addr : $@convention(thin) (@owned B, @owned B) -> (@thick Any.Type, @thick Any.Type) {
bb0(%0 : $B, %1 : $B):
%2 = alloc_stack $Any
%3 = init_existential_addr %2 : $*Any, $B
store %0 to %3 : $*B
%5 = existential_metatype $@thick Any.Type, %2 : $*Any
store %1 to %3 : $*B
%7 = existential_metatype $@thick Any.Type, %2 : $*Any
strong_release %1 : $B
strong_release %0 : $B
%99 = tuple (%5 : $@thick Any.Type, %7 : $@thick Any.Type)
dealloc_stack %2 : $*Any
return %99 : $(@thick Any.Type, @thick Any.Type)
}
// CHECK-LABEL: sil @cse_objc_metatype_to_object
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK-NOT: objc_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_metatype_to_object : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @cse_objc_existential_metatype_to_object
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK-NOT: objc_existential_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_existential_metatype_to_object : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @cse_raw_pointer_to_ref
// CHECK: raw_pointer_to_ref
// CHECK-NOT: raw_pointer_to_ref
@@ -937,24 +839,6 @@ bb0(%0 : $Enum1):
return %3: $(Builtin.Int1, Builtin.Int1)
}
@objc
class XXX {
}
// CHECK-LABEL: sil @cse_objc_to_thick_metatype
// CHECK: objc_to_thick_metatype
// CHECK-NOT: objc_to_thick_metatype
// CHECK: tuple
// CHECK: return
sil @cse_objc_to_thick_metatype : $@convention(thin) (@objc_metatype XXX.Type) -> (@thick XXX.Type, @thick XXX.Type) {
bb0(%0 : $@objc_metatype XXX.Type):
%1 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%2 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%3 = tuple (%1: $@thick XXX.Type, %2: $@thick XXX.Type)
return %3: $(@thick XXX.Type, @thick XXX.Type)
}
// CHECK-LABEL: sil @cse_bridge_object_to_ref
// CHECK: bridge_object_to_ref
// CHECK-NOT: bridge_object_to_ref

View File

@@ -154,6 +154,118 @@ bb3:
return %13 : $()
}
// CHECK-LABEL: sil @cse_value_metatype
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_value_metatype : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @cse_existential_metatype
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_existential_metatype : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}
class B {}
// CHECK-LABEL: sil @nocse_existential_metatype_addr
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: return
sil @nocse_existential_metatype_addr : $@convention(thin) (@owned B, @owned B) -> (@thick Any.Type, @thick Any.Type) {
bb0(%0 : $B, %1 : $B):
%2 = alloc_stack $Any
%3 = init_existential_addr %2 : $*Any, $B
store %0 to %3 : $*B
%5 = existential_metatype $@thick Any.Type, %2 : $*Any
store %1 to %3 : $*B
%7 = existential_metatype $@thick Any.Type, %2 : $*Any
strong_release %1 : $B
strong_release %0 : $B
%99 = tuple (%5 : $@thick Any.Type, %7 : $@thick Any.Type)
dealloc_stack %2 : $*Any
return %99 : $(@thick Any.Type, @thick Any.Type)
}
// CHECK-LABEL: sil @cse_objc_metatype_to_object
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK-NOT: objc_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_metatype_to_object : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @cse_objc_existential_metatype_to_object
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK-NOT: objc_existential_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_existential_metatype_to_object : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}
@objc
class XXX {
}
// CHECK-LABEL: sil @cse_objc_to_thick_metatype
// CHECK: objc_to_thick_metatype
// CHECK-NOT: objc_to_thick_metatype
// CHECK: tuple
// CHECK: return
sil @cse_objc_to_thick_metatype : $@convention(thin) (@objc_metatype XXX.Type) -> (@thick XXX.Type, @thick XXX.Type) {
bb0(%0 : $@objc_metatype XXX.Type):
%1 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%2 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%3 = tuple (%1: $@thick XXX.Type, %2: $@thick XXX.Type)
return %3: $(@thick XXX.Type, @thick XXX.Type)
}
sil_vtable Bar {
#Bar.init!initializer.1: _TFC4test3BarcfMS0_FT_S0_ // test.Bar.init (test.Bar.Type)() -> test.Bar
#Bar.walk!1: _TFC4test3Bar4walkfS0_FT_T_ // test.Bar.walk (test.Bar)() -> ()

View File

@@ -1969,34 +1969,6 @@ class XXImpl : XX {
init()
}
// CHECK-LABEL: sil @remove_release_objc_metatype_to_object
// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
sil @remove_release_objc_metatype_to_object : $@convention(thin) () -> () {
bb0:
%0 = metatype $@thick XXImpl.Type // user: %1
%1 = thick_to_objc_metatype %0 : $@thick XXImpl.Type to $@objc_metatype XXImpl.Type // user: %2
%2 = objc_metatype_to_object %1 : $@objc_metatype XXImpl.Type to $AnyObject // users: %3, %4
debug_value %2 : $AnyObject // id: %3
strong_release %2 : $AnyObject // id: %4
%5 = tuple () // user: %6
return %5 : $() // id: %6
}
// CHECK-LABEL: sil @remove_release_objc_existential_metatype_to_object
// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
sil @remove_release_objc_existential_metatype_to_object: $@convention(thin) (@owned XX) -> () {
bb0(%0 : $XX):
debug_value %0 : $XX // id: %1
%2 = existential_metatype $@thick XX.Type, %0 : $XX // user: %3
%3 = thick_to_objc_metatype %2 : $@thick XX.Type to $@objc_metatype XX.Type // user: %4
%4 = objc_existential_metatype_to_object %3 : $@objc_metatype XX.Type to $AnyObject // users: %5, %6
debug_value %4 : $AnyObject, let, name "obj1" // id: %5
strong_release %4 : $AnyObject // id: %6
strong_release %0 : $XX // id: %7
%8 = tuple () // user: %9
return %8 : $() // id: %9
}
// CHECK-LABEL: sil @unowned_round_trips : $@convention(thin) (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) -> (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) {
// CHECK: bb0(
// CHECK-NEXT: tuple

View File

@@ -151,3 +151,39 @@ bb0(%0 : $C):
return %4 : $Int
}
@objc(XX) protocol XX {
}
class XXImpl : XX {
@objc deinit
init()
}
// CHECK-LABEL: sil @remove_release_objc_metatype_to_object
// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
sil @remove_release_objc_metatype_to_object : $@convention(thin) () -> () {
bb0:
%0 = metatype $@thick XXImpl.Type // user: %1
%1 = thick_to_objc_metatype %0 : $@thick XXImpl.Type to $@objc_metatype XXImpl.Type // user: %2
%2 = objc_metatype_to_object %1 : $@objc_metatype XXImpl.Type to $AnyObject // users: %3, %4
debug_value %2 : $AnyObject // id: %3
strong_release %2 : $AnyObject // id: %4
%5 = tuple () // user: %6
return %5 : $() // id: %6
}
// CHECK-LABEL: sil @remove_release_objc_existential_metatype_to_object
// CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject
sil @remove_release_objc_existential_metatype_to_object: $@convention(thin) (@owned XX) -> () {
bb0(%0 : $XX):
debug_value %0 : $XX // id: %1
%2 = existential_metatype $@thick XX.Type, %0 : $XX // user: %3
%3 = thick_to_objc_metatype %2 : $@thick XX.Type to $@objc_metatype XX.Type // user: %4
%4 = objc_existential_metatype_to_object %3 : $@objc_metatype XX.Type to $AnyObject // users: %5, %6
debug_value %4 : $AnyObject, let, name "obj1" // id: %5
strong_release %4 : $AnyObject // id: %6
strong_release %0 : $XX // id: %7
%8 = tuple () // user: %9
return %8 : $() // id: %9
}

View File

@@ -0,0 +1 @@
public class NSError: Error {}

View File

@@ -0,0 +1,19 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %target-swift-frontend -emit-module -module-name Foundation -o %t/Foundation.swiftmodule %S/Inputs/Foundation-with-NSError.swift
// RUN: %target-swift-frontend -I %t -typecheck -verify %s
// UNSUPPORTED: objc_interop
import Foundation
// Catching `as NSError` ought *not* to be exhaustive when ObjC interop is
// disabled. It's just another error type.
func bar() throws {}
func foo() {
do {
try bar() // expected-error{{enclosing catch is not exhaustive}}
} catch _ as NSError {
}
}

View File

@@ -0,0 +1,14 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s
// REQUIRES: objc_interop
import Foundation
// Catching `as NSError` ought to be exhaustive when ObjC interop is enabled.
func bar() throws {}
func foo() {
do {
try bar()
} catch _ as NSError {
}
}

View File

@@ -240,6 +240,8 @@ int main(int argc, char **argv) {
Invocation.getLangOptions().DisableAvailabilityChecking = true;
Invocation.getLangOptions().EnableAccessControl = false;
Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false;
Invocation.getLangOptions().EnableObjCInterop =
llvm::Triple(Target).isOSDarwin();
Invocation.getLangOptions().ASTVerifierProcessCount =
ASTVerifierProcessCount;