Merge pull request #7847 from jckarter/nserror-linux-bridging-3.1
Sema/SIL: NSError has no special powers without ObjC interop.
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index e528d87..eedca48 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -1139,23 +1139,30 @@
// 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).
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index a8d48ef..a056232 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -461,6 +461,10 @@
/// 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;
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 0cd52a0..cd845dc 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -3327,6 +3327,10 @@
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.
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 31ece4c..e465f2b 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -3361,16 +3361,18 @@
// 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.
diff --git a/test/SIL/Parser/undef.sil b/test/SIL/Parser/undef.sil
index 43dbb04..a22c53f 100644
--- a/test/SIL/Parser/undef.sil
+++ b/test/SIL/Parser/undef.sil
@@ -242,14 +242,6 @@
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
diff --git a/test/SIL/Parser/undef_objc.sil b/test/SIL/Parser/undef_objc.sil
new file mode 100644
index 0000000..b4119cd
--- /dev/null
+++ b/test/SIL/Parser/undef_objc.sil
@@ -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
+}
diff --git a/test/SILGen/generic_casts.swift b/test/SILGen/generic_casts.swift
index 959d179..6269058 100644
--- a/test/SILGen/generic_casts.swift
+++ b/test/SILGen/generic_casts.swift
@@ -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 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 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{{.*}}
diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil
index b48fbb6..104fe80 100644
--- a/test/SILOptimizer/cse.sil
+++ b/test/SILOptimizer/cse.sil
@@ -720,104 +720,6 @@
%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 @@
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
diff --git a/test/SILOptimizer/cse_objc.sil b/test/SILOptimizer/cse_objc.sil
index 9e10fd7..c81d334 100644
--- a/test/SILOptimizer/cse_objc.sil
+++ b/test/SILOptimizer/cse_objc.sil
@@ -154,6 +154,118 @@
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)() -> ()
diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil
index ccb32a2..aa8d6fb 100644
--- a/test/SILOptimizer/sil_combine.sil
+++ b/test/SILOptimizer/sil_combine.sil
@@ -1969,34 +1969,6 @@
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
diff --git a/test/SILOptimizer/sil_combine_objc.sil b/test/SILOptimizer/sil_combine_objc.sil
index e631e6d..ed1e877 100644
--- a/test/SILOptimizer/sil_combine_objc.sil
+++ b/test/SILOptimizer/sil_combine_objc.sil
@@ -151,3 +151,39 @@
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
+}
+
diff --git a/test/stmt/Inputs/Foundation-with-NSError.swift b/test/stmt/Inputs/Foundation-with-NSError.swift
new file mode 100644
index 0000000..0005b24
--- /dev/null
+++ b/test/stmt/Inputs/Foundation-with-NSError.swift
@@ -0,0 +1 @@
+public class NSError: Error {}
diff --git a/test/stmt/errors_nonobjc.swift b/test/stmt/errors_nonobjc.swift
new file mode 100644
index 0000000..2c3369d
--- /dev/null
+++ b/test/stmt/errors_nonobjc.swift
@@ -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 {
+ }
+}
diff --git a/test/stmt/errors_objc.swift b/test/stmt/errors_objc.swift
new file mode 100644
index 0000000..42caa10
--- /dev/null
+++ b/test/stmt/errors_objc.swift
@@ -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 {
+ }
+}
diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp
index 1a588dc..915e29d 100644
--- a/tools/sil-opt/SILOpt.cpp
+++ b/tools/sil-opt/SILOpt.cpp
@@ -234,6 +234,8 @@
Invocation.getLangOptions().DisableAvailabilityChecking = true;
Invocation.getLangOptions().EnableAccessControl = false;
Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false;
+ Invocation.getLangOptions().EnableObjCInterop =
+ llvm::Triple(Target).isOSDarwin();
Invocation.getLangOptions().ASTVerifierProcessCount =
ASTVerifierProcessCount;