Files
swift-mirror/test/SILOptimizer/mandatory_inlining_ownership.sil
Michael Gottesman f854547c55 [ownership] Enable ownership verification by default.
I also removed the -verify-sil-ownership flag in favor of a disable flag
-disable-sil-ownership-verifier. I used this on only two tests that still need
work to get them to pass with ownership, but whose problems are well understood,
small corner cases. I am going to fix them in follow on commits. I detail them
below:

1. SILOptimizer/definite_init_inout_super_init.swift. This is a test case where
DI is supposed to error. The only problem is that we crash before we error since
the code emitting by SILGen to trigger this error does not pass ownership
invariants. I have spoken with JoeG about this and he suggested that I fix this
earlier in the compiler. Since we do not run the ownership verifier without
asserts enabled, this should not affect compiler users. Given that it has
triggered DI errors previously I think it is safe to disable ownership here.

2. PrintAsObjC/extensions.swift. In this case, the signature generated by type
lowering for one of the thunks here uses an unsafe +0 return value instead of
doing an autorelease return. The ownership checker rightly flags this leak. This
is going to require either an AST level change or a change to TypeLowering. I
think it is safe to turn this off since it is such a corner case that it was
found by a test that has nothing to do with it.

rdar://43398898
2019-03-25 00:11:52 -07:00

317 lines
14 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -mandatory-inlining | %FileCheck %s
sil_stage raw
import Builtin
import Swift
class C {
var i: Builtin.Int64
init(i: Builtin.Int64)
}
class Klass {}
sil [transparent] [ossa] @calleeWithGuaranteed : $@convention(thin) (@guaranteed C) -> Builtin.Int64 {
bb(%0 : @guaranteed $C):
%1 = ref_element_addr %0 : $C, #C.i
%2 = load [trivial] %1 : $*Builtin.Int64
return %2 : $Builtin.Int64
}
// CHECK-LABEL: sil [ossa] @callerWithOwned : $@convention(thin) (@owned C) -> Builtin.Int64 {
// CHECK: bb0(%0 : @owned $C):
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $C
// CHECK: [[ADDR:%.*]] = ref_element_addr [[BORROW]] : $C, #C.i
// CHECK: [[VAL:%.*]] = load [trivial] [[ADDR]] : $*Builtin.Int64
// CHECK: end_borrow [[BORROW]] : $C
// CHECK: destroy_value %0 : $C
// CHECK: return [[VAL]] : $Builtin.Int64
// CHECK-LABEL: } // end sil function 'callerWithOwned'
sil [ossa] @callerWithOwned : $@convention(thin) (@owned C) -> Builtin.Int64 {
bb(%0 : @owned $C):
%fn = function_ref @calleeWithGuaranteed : $@convention(thin) (@guaranteed C) -> Builtin.Int64
%call = apply %fn(%0) : $@convention(thin) (@guaranteed C) -> Builtin.Int64
destroy_value %0 : $C
return %call : $Builtin.Int64
}
struct MyError : Error {}
sil [transparent] [ossa] @calleeWithGuaranteedThrows : $@convention(thin) (@guaranteed C) -> (Builtin.Int64, @error Error) {
bb(%0 : @guaranteed $C):
%1 = ref_element_addr %0 : $C, #C.i
%2 = load [trivial] %1 : $*Builtin.Int64
%3 = integer_literal $Builtin.Int64, 0
%5 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_br %5, bb1, bb2
bb1:
%6 = alloc_existential_box $Error, $MyError
throw %6 : $Error
bb2:
return %2 : $Builtin.Int64
}
// CHECK-LABEL: sil [ossa] @callerWithThrow : $@convention(thin) (@owned C) -> (Builtin.Int64, @error Error) {
// CHECK: bb0(%0 : @owned $C):
// CHECK: [[BORROW:%.*]] = begin_borrow %0 : $C
// CHECK: [[ADDR:%.*]] = ref_element_addr [[BORROW]] : $C, #C.i
// CHECK: [[VAL:%.*]] = load [trivial] [[ADDR]] : $*Builtin.Int64
// CHECK: bb{{.*}}:
// CHECK: [[ERR:%.*]] = alloc_existential_box $Error, $MyError
// CHECK: end_borrow [[BORROW]] : $C
// CHECK: destroy_value %0 : $C
// CHECK: throw [[ERR]] : $Error
// CHECK: bb{{.*}}:
// CHECK: end_borrow [[BORROW]] : $C
// CHECK: destroy_value %0 : $C
// CHECK: return [[VAL]] : $Builtin.Int64
// CHECK-LABEL: } // end sil function 'callerWithThrow'
sil [ossa] @callerWithThrow : $@convention(thin) (@owned C) -> (Builtin.Int64, @error Error) {
bb(%0 : @owned $C):
%fn = function_ref @calleeWithGuaranteedThrows : $@convention(thin) (@guaranteed C) -> (Builtin.Int64, @error Error)
try_apply %fn(%0) : $@convention(thin) (@guaranteed C) -> (Builtin.Int64, @error Error), normal bb1, error bb2
bb1(%4 : $Builtin.Int64):
destroy_value %0 : $C
return %4 : $Builtin.Int64
bb2(%5 : @owned $Error):
destroy_value %0 : $C
throw %5 : $Error
}
// Partial Apply copy_value test.
sil @nativeobject_plus : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
sil @partial_apply_user : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject) -> ()
sil [ossa] [transparent] @test_partial_nativeobject_baz : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%6 = function_ref @nativeobject_plus : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
%7 = apply %6(%0, %1) : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
return %7 : $Builtin.NativeObject
}
sil [ossa] [transparent] @test_partial_nativeobject_bar : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $@callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%7 = apply %0(%1) : $@callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject
return %7 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [transparent] [ossa] @test_partial_nativeobject_foo : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $Builtin.NativeObject):
// CHECK: [[FN:%.*]] = function_ref @test_partial_nativeobject_baz :
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: [[ARG_COPY_2:%.*]] = copy_value [[ARG_COPY]]
// CHECK: [[PAI:%.*]] = partial_apply [[FN]]([[ARG_COPY]])
// CHECK: [[ARG_COPY_3:%.*]] = copy_value [[ARG]]
// CHECK: [[PAI_COPY:%.*]] = copy_value [[PAI]]
// CHECK: [[FN2:%.*]] = function_ref @nativeobject_plus :
// CHECK: [[RESULT:%.*]] = apply [[FN2]]([[ARG_COPY_3]], [[ARG_COPY_2]])
// CHECK: destroy_value [[PAI_COPY]]
// CHECK: [[PAI_COPY_2:%.*]] = copy_value [[PAI]]
// CHECK: [[OPAQUE_FN:%.*]] = function_ref @partial_apply_user
// CHECK: apply [[OPAQUE_FN]]([[PAI_COPY_2]])
// CHECK: destroy_value [[PAI]]
// CHECK: destroy_value [[ARG]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'test_partial_nativeobject_foo'
sil [transparent] [ossa] @test_partial_nativeobject_foo : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%2 = function_ref @test_partial_nativeobject_bar : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
%3 = function_ref @test_partial_nativeobject_baz : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
br bb1
bb1:
%0copy1 = copy_value %0 : $Builtin.NativeObject
%5 = partial_apply %3(%0copy1) : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
br bb2
bb2:
%0copy2 = copy_value %0 : $Builtin.NativeObject
%5copy1 = copy_value %5 : $@callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject
%13 = apply %2(%5copy1, %0copy2) : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject
br bb3
bb3:
%5copy2 = copy_value %5 : $@callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject
%15 = function_ref @partial_apply_user : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject) -> ()
apply %15(%5copy2) : $@convention(thin) (@owned @callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject) -> ()
destroy_value %5 : $@callee_owned (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject
destroy_value %0 : $Builtin.NativeObject
return %13 : $Builtin.NativeObject
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br take_always Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
br bb3
bb2:
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [take] [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// ==> On success, we store the value into dest. The destroy is not from the
// ==> optimizer, but from the code.
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
// CHECK-NEXT: store [[CAST_VALUE]] to [init] [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// ==> take_always implies we destroy in failure
// CHECK: [[FAILURE_BB]]([[FAILURE_ARG:%.*]] :
// CHECK-NEXT: destroy_value [[FAILURE_ARG]]
// CHECK-NEXT: br [[CONT_BB]]
//
// CHECK: [[CONT_BB]]:
// CHECK: destroy_value [[ARG]]
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takealways_caller'
sil [ossa] @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%3 = function_ref @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%1 = copy_value %0 : $Builtin.NativeObject
apply %3(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br take_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
br bb3
bb2:
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [take] [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
// ==> On success, we store into dest and destroy dest.
// CHECK-NEXT: store [[CAST_VALUE]] to [init] [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// ==> Since we are doing a take on success and we failed... store the original
// ==> value back into the memory slot.
// CHECK: [[FAILURE_BB]]([[FAIL_ARG:%.*]] :
// CHECK-NEXT: store [[FAIL_ARG]] to [init] [[SRC_ADDR]]
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB]]
//
// CHECK: } // end sil function 'checked_cast_addr_br_takeonsuccess_caller'
sil [ossa] @checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%2 = function_ref @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%1 = copy_value %0 : $Builtin.NativeObject
apply %2(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br copy_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb2:
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG_COPY]] to [init] [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load_borrow [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] : @guaranteed
// CHECK-NEXT: [[CAST_VALUE_COPY:%.*]] = copy_value [[CAST_VALUE]]
// CHECK-NEXT: end_borrow [[CAST_VALUE]]
// CHECK-NEXT: end_borrow [[RELOADED_ARG]]
// CHECK-NEXT: store [[CAST_VALUE_COPY]] to [init] [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// CHECK: [[FAILURE_BB]]([[FAILURE_BORROWED_ARG:%.*]] :
// CHECK-NEXT: end_borrow [[FAILURE_BORROWED_ARG]]
// CHECK-NEXT: end_borrow [[RELOADED_ARG]]
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB]]
//
// CHECK: } // end sil function 'checked_cast_addr_br_copyonsuccess_caller'
sil [ossa] @checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = function_ref @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%2 = copy_value %0 : $Builtin.NativeObject
apply %1(%2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}