mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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).
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
23
test/SIL/Parser/undef_objc.sil
Normal file
23
test/SIL/Parser/undef_objc.sil
Normal 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
|
||||
}
|
||||
@@ -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{{.*}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)() -> ()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
1
test/stmt/Inputs/Foundation-with-NSError.swift
Normal file
1
test/stmt/Inputs/Foundation-with-NSError.swift
Normal file
@@ -0,0 +1 @@
|
||||
public class NSError: Error {}
|
||||
19
test/stmt/errors_nonobjc.swift
Normal file
19
test/stmt/errors_nonobjc.swift
Normal 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 {
|
||||
}
|
||||
}
|
||||
14
test/stmt/errors_objc.swift
Normal file
14
test/stmt/errors_objc.swift
Normal 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 {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user