Files
swift-mirror/test/SILGen/existential_erasure.swift
Jamie 62fedfc81c [SILGen]: enforce only expected types are used with InitExistentialRef
We currently appear to miscompile when emitting the erased isolation
existential codegen if the isolated capture is unowned. To patch this,
add new assertions that only supported types are used when creating the
instruction in the builder.
2026-01-12 08:02:51 -06:00

145 lines
5.8 KiB
Swift

// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name existential_erasure %s | %FileCheck %s
protocol P {
func downgrade(_ m68k: Bool) -> Self
func upgrade() throws -> Self
}
protocol Q {}
struct X: P, Q {
func downgrade(_ m68k: Bool) -> X {
return self
}
func upgrade() throws -> X {
return self
}
}
func makePQ() -> P & Q { return X() }
func useP(_ x: P) { }
func throwingFunc() throws -> Bool { return true }
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure5PQtoPyyF : $@convention(thin) () -> () {
func PQtoP() {
// CHECK: [[PQ_PAYLOAD:%.*]] = open_existential_addr immutable_access [[PQ:%.*]] : $*any P & Q to $*[[OPENED_TYPE:@opened\(.*, any P & Q\) Self]]
// CHECK: [[P_PAYLOAD:%.*]] = init_existential_addr [[P:%.*]] : $*any P, $[[OPENED_TYPE]]
// CHECK: copy_addr [[PQ_PAYLOAD]] to [init] [[P_PAYLOAD]]
// CHECK: destroy_addr [[PQ]]
// CHECK-NOT: destroy_addr [[P]]
// CHECK-NOT: destroy_addr [[P_PAYLOAD]]
// CHECK-NOT: deinit_existential_addr [[PQ]]
// CHECK-NOT: destroy_addr [[PQ_PAYLOAD]]
useP(makePQ())
}
// Make sure uninitialized existentials are properly deallocated when we
// have an early return.
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure19openExistentialToP1yyAA1P_pKF
func openExistentialToP1(_ p: P) throws {
// CHECK: bb0(%0 : $*any P):
// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*any P to $*[[OPEN_TYPE:@opened\(.*, any P\) Self]]
// CHECK: [[RESULT:%.*]] = alloc_stack $any P
// CHECK: [[FUNC:%.*]] = function_ref @$s19existential_erasure12throwingFuncSbyKF
// CHECK: try_apply [[FUNC]]()
//
// CHECK: bb1([[SUCCESS:%.*]] : $Bool):
// CHECK: [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.downgrade : {{.*}}, [[OPEN]]
// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*any P, $[[OPEN_TYPE]]
// CHECK: apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[SUCCESS]], [[OPEN]])
// CHECK: dealloc_stack [[RESULT]]
// CHECK: return
//
// CHECK: bb2([[FAILURE:%.*]] : @owned $any Error):
// CHECK: dealloc_stack [[RESULT]]
// CHECK: throw [[FAILURE]]
//
try useP(p.downgrade(throwingFunc()))
}
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure19openExistentialToP2yyAA1P_pKF
func openExistentialToP2(_ p: P) throws {
// CHECK: bb0(%0 : $*any P):
// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*any P to $*[[OPEN_TYPE:@opened\(.*, any P\) Self]]
// CHECK: [[RESULT:%.*]] = alloc_stack $any P
// CHECK: [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.upgrade : {{.*}}, [[OPEN]]
// CHECK: [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*any P, $[[OPEN_TYPE]]
// CHECK: try_apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[OPEN]])
//
// CHECK: bb1
// CHECK: dealloc_stack [[RESULT]]
// CHECK: return
//
// CHECK: bb2([[FAILURE:%.*]]: @owned $any Error):
// CHECK: deinit_existential_addr [[RESULT]]
// CHECK: dealloc_stack [[RESULT]]
// CHECK: throw [[FAILURE]]
//
try useP(p.upgrade())
}
// Same as above but for boxed existentials
extension Error {
func returnOrThrowSelf() throws -> Self {
throw self
}
}
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure12errorHandlerys5Error_psAC_pKF
func errorHandler(_ e: Error) throws -> Error {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $any Error):
// CHECK: debug_value [[ARG]] : $any Error
// CHECK: [[OPEN:%.*]] = open_existential_box [[ARG]] : $any Error to $*[[OPEN_TYPE:@opened\(.*, any Error\) Self]]
// CHECK: [[FUNC:%.*]] = function_ref @$ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
// CHECK: [[RESULT:%.*]] = alloc_existential_box $any Error, $[[OPEN_TYPE]]
// CHECK: [[ADDR:%.*]] = project_existential_box $[[OPEN_TYPE]] in [[RESULT]] : $any Error
// CHECK: store [[RESULT]] to [init] [[RESULT_BUF:%.*]] :
// CHECK: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
//
// CHECK: bb1
// CHECK: [[RESULT2:%.*]] = load [take] [[RESULT_BUF]]
// CHECK: return [[RESULT2]] : $any Error
//
// CHECK: bb2([[FAILURE:%.*]] : @owned $any Error):
// CHECK: [[RESULT3:%.*]] = load [take] [[RESULT_BUF]]
// CHECK: dealloc_existential_box [[RESULT3]]
// CHECK: throw [[FAILURE]] : $any Error
//
return try e.returnOrThrowSelf()
}
// rdar://problem/22003864 -- SIL verifier crash when init_existential_addr
// references dynamic Self type
class EraseDynamicSelf {
required init() {}
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure16EraseDynamicSelfC7factoryACXDyFZ : $@convention(method) (@thick EraseDynamicSelf.Type) -> @owned EraseDynamicSelf
// CHECK: [[ANY:%.*]] = alloc_stack $Any
// CHECK: init_existential_addr [[ANY]] : $*Any, $@dynamic_self EraseDynamicSelf
//
class func factory() -> Self {
let instance = self.init()
let _: Any = instance
return instance
}
// CHECK-LABEL: sil hidden [ossa] @$s19existential_erasure16EraseDynamicSelfC23eraseToClassExistentialyXlyF : $@convention(method) (@guaranteed EraseDynamicSelf) -> @owned AnyObject
// CHECK: bb0([[ARG:%.*]] : @guaranteed $EraseDynamicSelf):
// CHECK: debug_value [[ARG]] : $EraseDynamicSelf, let, name "self", argno 1
// CHECK: [[METATYPE:%.*]] = metatype $@thick @dynamic_self EraseDynamicSelf.Type
// CHECK: [[UPCAST:%.*]] = upcast [[METATYPE]] : $@thick @dynamic_self EraseDynamicSelf.Type to $@thick EraseDynamicSelf.Type
// CHECK: [[METHOD:%.*]] = class_method [[UPCAST]] : $@thick EraseDynamicSelf.Type, #EraseDynamicSelf.factory
// CHECK: [[INSTANCE:%.*]] = apply [[METHOD]]([[UPCAST]]) : $@convention(method) (@thick EraseDynamicSelf.Type) -> @owned EraseDynamicSelf
// CHECK: [[EXISTENTIAL:%.*]] = init_existential_ref [[INSTANCE]] : $EraseDynamicSelf : $@dynamic_self EraseDynamicSelf, $AnyObject
// CHECK: return [[EXISTENTIAL]] : $AnyObject
func eraseToClassExistential() -> AnyObject {
return Self.factory()
}
}