| // RUN: %target-swift-frontend -Xllvm -sil-disable-pass="External Defs To Decls" %s -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s |
| |
| // REQUIRES: CPU=i386_or_x86_64 |
| // XFAIL: linux |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| |
| struct NotClass {} |
| |
| class A {} |
| class B: A {} |
| |
| sil_vtable A {} |
| sil_vtable B {} |
| |
| // CHECK-LABEL: define{{( protected)?}} %C5casts1B* @unchecked_addr_cast(%C5casts1A** noalias nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: bitcast %C5casts1A** %0 to %C5casts1B** |
| sil @unchecked_addr_cast : $(@in A) -> B { |
| entry(%a : $*A): |
| %b = unchecked_addr_cast %a : $*A to $*B |
| %x = load %b : $*B |
| return %x : $B |
| } |
| |
| protocol CP: class {} |
| protocol CP2: class {} |
| @objc protocol OP: class {} |
| |
| // CHECK-LABEL: define{{( protected)?}} i8* @ref_to_raw_pointer_existential(%objc_object*, i8**) {{.*}} { |
| // CHECK: [[CAST:%.*]] = bitcast %objc_object* %0 to i8* |
| // CHECK: ret i8* [[CAST]] |
| sil @ref_to_raw_pointer_existential : $@convention(thin) (@owned CP) -> Builtin.RawPointer { |
| entry(%p : $CP): |
| %r = ref_to_raw_pointer %p : $CP to $Builtin.RawPointer |
| return %r : $Builtin.RawPointer |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %objc_object* @raw_pointer_to_ref_existential(i8*) {{.*}} { |
| // CHECK: [[CAST:%.*]] = bitcast i8* %0 to %objc_object* |
| // CHECK: ret %objc_object* [[CAST]] |
| sil @raw_pointer_to_ref_existential : $@convention(thin) (@owned Builtin.RawPointer) -> AnyObject { |
| entry(%p : $Builtin.RawPointer): |
| %r = raw_pointer_to_ref %p : $Builtin.RawPointer to $AnyObject |
| return %r : $AnyObject |
| } |
| |
| sil @unchecked_ref_cast_to_existential : $@convention(thin) (@owned Builtin.NativeObject) -> @owned AnyObject { |
| entry(%n : $Builtin.NativeObject): |
| %r = unchecked_ref_cast %n : $Builtin.NativeObject to $AnyObject |
| return %r : $AnyObject |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8** } @u_cast_to_class_existential(%objc_object*) |
| // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP) |
| // CHECK-LABEL: define{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8*, %swift.type*, %swift.protocol*) {{.*}} { |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont |
| // CHECK: cont: |
| // CHECK: [[FIRST:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0 |
| // CHECK: [[SECOND:%.*]] = insertvalue { i8*, i8** } [[FIRST]], i8** [[WITNESS]], 1 |
| // CHECK: ret { i8*, i8** } [[SECOND]] |
| // CHECK: fail: |
| // CHECK: call void @llvm.trap() |
| sil @u_cast_to_class_existential : $@convention(thin) (@owned AnyObject) -> @owned CP { |
| entry(%a : $AnyObject): |
| %p = unconditional_checked_cast %a : $AnyObject to $CP |
| return %p : $CP |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %swift.type*, i8** } @u_cast_to_existential_metatype(%swift.type*) |
| // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %1, %swift.type* %0, %swift.protocol* @_TMp5casts2CP) |
| sil @u_cast_to_existential_metatype : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick CP.Type { |
| entry(%a : $@thick Any.Type): |
| %p = unconditional_checked_cast %a : $@thick Any.Type to $@thick CP.Type |
| return %p : $@thick CP.Type |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8**, i8** } @u_cast_to_class_existential_2(%objc_object*) |
| // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| // CHECK-LABEL: define{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8*, %swift.type*, %swift.protocol*, %swift.protocol*) |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont |
| // CHECK: cont: |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %3) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont1 |
| // CHECK: cont1: |
| // CHECK: ret { i8*, i8**, i8** } |
| // CHECK: fail: |
| // CHECK: call void @llvm.trap() |
| sil @u_cast_to_class_existential_2 : $@convention(thin) (@owned AnyObject) -> @owned CP & CP2 { |
| entry(%a : $AnyObject): |
| %p = unconditional_checked_cast %a : $AnyObject to $CP & CP2 |
| return %p : $CP & CP2 |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8**, i8** } @u_cast_to_class_existential_mixed(%objc_object*) |
| // CHECK: call %objc_object* @swift_dynamicCastObjCProtocolUnconditional |
| // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| sil @u_cast_to_class_existential_mixed : $@convention(thin) (@owned AnyObject) -> @owned CP & OP & CP2 { |
| entry(%a : $AnyObject): |
| %p = unconditional_checked_cast %a : $AnyObject to $CP & OP & CP2 |
| return %p : $CP & OP & CP2 |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %swift.type*, i8**, i8** } @u_cast_to_existential_metatype_mixed(%swift.type*) |
| // CHECK: call %swift.type* @swift_dynamicCastTypeToObjCProtocolUnconditional(%swift.type* %0, {{(i32|i64)}} 1, i8** {{%.*}}) |
| // CHECK: [[CAST:%.*]] = call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{.*}}, %swift.type* %0, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| // CHECK: [[OBJPTR:%.*]] = extractvalue { i8*, i8**, i8** } [[CAST]], 0 |
| // CHECK: [[OBJ:%.*]] = bitcast i8* [[OBJPTR]] to %swift.type* |
| // CHECK: insertvalue {{.*}} [[OBJ]] |
| sil @u_cast_to_existential_metatype_mixed : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick (CP & OP & CP2).Type { |
| entry(%a : $@thick Any.Type): |
| %p = unconditional_checked_cast %a : $@thick Any.Type to $@thick (CP & OP & CP2).Type |
| return %p : $@thick (CP & OP & CP2).Type |
| } |
| |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8** } @c_cast_to_class_existential(%objc_object*) |
| // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* {{.*}}, %swift.type* %.Type, %swift.protocol* @_TMp5casts2CP) |
| // CHECK-LABEL: define{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_conditional(i8*, %swift.type*, %swift.protocol*) |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont |
| // CHECK: cont: |
| // CHECK: ret { i8*, i8** } |
| // CHECK: fail: |
| // CHECK: ret { i8*, i8** } zeroinitializer |
| sil @c_cast_to_class_existential : $@convention(thin) (@owned AnyObject) -> @owned CP { |
| entry(%a : $AnyObject): |
| checked_cast_br %a : $AnyObject to $CP, yea, nay |
| yea(%p : $CP): |
| return %p : $CP |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %swift.type*, i8** } @c_cast_to_existential_metatype(%swift.type*) {{.*}} { |
| // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %1, %swift.type* %0, %swift.protocol* @_TMp5casts2CP) |
| sil @c_cast_to_existential_metatype : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick CP.Type { |
| entry(%a : $@thick Any.Type): |
| checked_cast_br %a : $@thick Any.Type to $@thick CP.Type, yea, nay |
| yea(%p : $@thick CP.Type): |
| return %p : $@thick CP.Type |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8**, i8** } @c_cast_to_class_existential_2(%objc_object*) |
| // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| // CHECK-LABEL: define{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8*, %swift.type*, %swift.protocol*, %swift.protocol*) |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont |
| // CHECK: cont: |
| // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %3) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null |
| // CHECK: br i1 [[IS_NULL]], label %fail, label %cont1 |
| // CHECK: cont1: |
| // CHECK: ret { i8*, i8**, i8** } |
| // CHECK: fail: |
| // CHECK: ret { i8*, i8**, i8** } zeroinitializer |
| sil @c_cast_to_class_existential_2 : $@convention(thin) (@owned AnyObject) -> @owned CP & CP2 { |
| entry(%a : $AnyObject): |
| checked_cast_br %a : $AnyObject to $CP & CP2, yea, nay |
| yea(%p : $CP & CP2): |
| return %p : $CP & CP2 |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %objc_object*, i8**, i8** } @c_cast_to_class_existential_mixed(%objc_object*) |
| // CHECK: [[CAST:%.*]] = call %objc_object* @swift_dynamicCastObjCProtocolConditional |
| // CHECK: [[IS_NULL:%.*]] = icmp eq %objc_object* [[CAST]], null |
| // CHECK: br i1 [[IS_NULL]], label %cont, label %success |
| // CHECK: success: |
| // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| // CHECK: br label %cont |
| // CHECK: cont: |
| // CHECK: phi %objc_object* [ [[CAST:%.*]], %success ], [ null, %entry ] |
| sil @c_cast_to_class_existential_mixed : $@convention(thin) (@owned AnyObject) -> @owned CP & OP & CP2 { |
| entry(%a : $AnyObject): |
| checked_cast_br %a : $AnyObject to $CP & OP & CP2, yea, nay |
| yea(%p : $CP & OP & CP2): |
| return %p : $CP & OP & CP2 |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} { %swift.type*, i8**, i8** } @c_cast_to_existential_metatype_mixed(%swift.type*) |
| // CHECK: [[OBJC_CAST:%.*]] = call %swift.type* @swift_dynamicCastTypeToObjCProtocolConditional(%swift.type* %0, {{(i32|i64)}} 1, i8** {{%.*}}) |
| // CHECK: [[IS_NULL:%.*]] = icmp eq %swift.type* [[OBJC_CAST]], null |
| // CHECK: br i1 [[IS_NULL]], label %cont, label %success |
| // CHECK: success: |
| // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{.*}}, %swift.type* %0, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2) |
| sil @c_cast_to_existential_metatype_mixed : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick (CP & OP & CP2).Type { |
| entry(%a : $@thick Any.Type): |
| checked_cast_br %a : $@thick Any.Type to $@thick (CP & OP & CP2).Type, yea, nay |
| yea(%p : $@thick (CP & OP & CP2).Type): |
| return %p : $@thick (CP & OP & CP2).Type |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %objc_object* @checked_upcast(%C5casts1A*) {{.*}} { |
| // -- Don't need to check conformance of an object to AnyObject. |
| // CHECK-NOT: call %objc_object* @swift_dynamicCastObjCProtocolConditional |
| // CHECK: phi %objc_object* |
| sil @checked_upcast : $@convention(thin) (@owned A) -> @owned AnyObject { |
| entry(%a : $A): |
| checked_cast_br %a : $A to $AnyObject, yea, nay |
| yea(%o : $AnyObject): |
| return %o : $AnyObject |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %C5casts1A* @checked_downcast_optional({{(i32|i64)}}) {{.*}} { |
| // CHECK: [[T0:%.*]] = inttoptr {{(i32|i64)}} %0 to %C5casts1A* |
| // CHECK: [[OBJ_PTR:%.*]] = bitcast %C5casts1A* [[T0]] to i8* |
| // CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaC5casts1A() |
| // CHECK: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to i8* |
| // CHECK: [[RESULT_PTR:%.*]] = call i8* @rt_swift_dynamicCastClass(i8* [[OBJ_PTR]], i8* [[METADATA_PTR]]) |
| // CHECK: [[RESULT:%.*]] = bitcast i8* [[RESULT_PTR]] to %C5casts1A* |
| // CHECK: [[COND:%.*]] = icmp ne %C5casts1A* [[RESULT]], null |
| // CHECK: br i1 [[COND]] |
| sil @checked_downcast_optional : $@convention(thin) (Optional<A>) -> @owned A { |
| entry(%a : $Optional<A>): |
| checked_cast_br %a : $Optional<A> to $A, yea, nay |
| yea(%aa : $A): |
| return %aa : $A |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %swift.type* @checked_downcast_optional_metatype({{(i32|i64)}}) {{.*}} { |
| // CHECK: [[VALUE:%.*]] = inttoptr {{(i32|i64)}} %0 to %swift.type* |
| // CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaC5casts1B() |
| // CHECK: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatype(%swift.type* [[VALUE]], %swift.type* [[METADATA]]) |
| // CHECK: [[COND:%.*]] = icmp ne %swift.type* [[RESULT]], null |
| // CHECK: br i1 [[COND]] |
| sil @checked_downcast_optional_metatype : $@convention(thin) (Optional<A.Type>) -> @thick B.Type { |
| entry(%a : $Optional<A.Type>): |
| checked_cast_br %a : $Optional<A.Type> to $@thick B.Type, yea, nay |
| yea(%b : $@thick B.Type): |
| return %b : $@thick B.Type |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %swift.type* @checked_downcast_optional_exmetatype({{(i32, i32|i64, i64)}}) {{.*}} { |
| // CHECK: [[VALUE:%.*]] = inttoptr {{(i32|i64)}} %0 to %swift.type* |
| // CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaC5casts1B() |
| // CHECK: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatype(%swift.type* [[VALUE]], %swift.type* [[METADATA]]) |
| // CHECK: [[COND:%.*]] = icmp ne %swift.type* [[RESULT]], null |
| // CHECK: br i1 [[COND]] |
| sil @checked_downcast_optional_exmetatype : $@convention(thin) (Optional<CP.Type>) -> @thick B.Type { |
| entry(%a : $Optional<CP.Type>): |
| checked_cast_br %a : $Optional<CP.Type> to $@thick B.Type, yea, nay |
| yea(%b : $@thick B.Type): |
| return %b : $@thick B.Type |
| nay: |
| unreachable |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} void @checked_metatype_to_object_casts |
| sil @checked_metatype_to_object_casts : $@convention(thin) <T> (@thick Any.Type) -> () { |
| entry(%e : $@thick Any.Type): |
| %a = metatype $@thin NotClass.Type |
| // CHECK: br i1 false |
| checked_cast_br %a : $@thin NotClass.Type to $AnyObject, a_yea, a_nay |
| a_yea(%1 : $AnyObject): |
| %b = metatype $@thick A.Type |
| // CHECK: bitcast %swift.type* {{%.*}} to %objc_object* |
| checked_cast_br %b : $@thick A.Type to $AnyObject, b_yea, b_nay |
| b_yea(%2 : $AnyObject): |
| %c = metatype $@objc_metatype A.Type |
| // CHECK: bitcast %objc_class* {{%.*}} to %objc_object* |
| checked_cast_br %c : $@objc_metatype A.Type to $AnyObject, c_yea, c_nay |
| c_yea(%3 : $AnyObject): |
| %d = metatype $@thick T.Type |
| // CHECK: call %objc_object* @swift_dynamicCastMetatypeToObjectConditional(%swift.type* %T) |
| checked_cast_br %d : $@thick T.Type to $AnyObject, d_yea, d_nay |
| d_yea(%4 : $AnyObject): |
| // CHECK: call %objc_object* @swift_dynamicCastMetatypeToObjectConditional(%swift.type* %0) |
| checked_cast_br %e : $@thick Any.Type to $AnyObject, e_yea, e_nay |
| e_yea(%5 : $AnyObject): |
| return undef : $() |
| a_nay: |
| unreachable |
| b_nay: |
| unreachable |
| c_nay: |
| unreachable |
| d_nay: |
| unreachable |
| e_nay: |
| unreachable |
| } |
| |
| @objc class OA {} |
| sil_vtable OA {} |
| sil hidden @_TToFC5casts2OAcfT_S0_ : $@convention(thin) (OA) -> OA { |
| entry(%x : $OA): |
| return %x : $OA |
| } |
| |
| @objc class OB {} |
| sil_vtable OB {} |
| sil hidden_external @_TToFC5casts2OBcfT_S0_ : $@convention(thin) (OB) -> OB { |
| entry(%x : $OB): |
| return %x : $OB |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %C5casts1B* @checked_object_to_object_casts(%C5casts1A*) |
| // CHECK: @swift_dynamicCastClassUnconditional |
| sil @checked_object_to_object_casts : $@convention(thin) (A) -> B { |
| entry(%a : $A): |
| %b = unconditional_checked_cast %a : $A to $B |
| return %b : $B |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} %C5casts2OB* @checked_objc_object_to_object_casts(%C5casts2OA*) |
| // CHECK: @swift_dynamicCastClassUnconditional |
| sil @checked_objc_object_to_object_casts : $@convention(thin) (OA) -> OB { |
| entry(%a : $OA): |
| %b = unconditional_checked_cast %a : $OA to $OB |
| return %b : $OB |
| } |