| // RUN: %target-sil-opt -enable-sil-verify-all %s -inout-deshadow | FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| |
| protocol P { |
| func foo() |
| } |
| |
| sil @takeInt : $@convention(method) (@inout Int64) -> () |
| |
| sil @TrivialTest : $@convention(thin) (@inout Int64) -> () { |
| bb0(%0 : $*Int64): |
| %1 = alloc_stack $Int64, var, name "a" // users: %6, %2, %4, %5 |
| copy_addr %0 to [initialization] %1 : $*Int64 |
| %3 = function_ref @takeInt : $@convention(method) (@inout Int64) -> () // user: %4 |
| %4 = apply %3(%1) : $@convention(method) (@inout Int64) -> () |
| copy_addr %1 to %0 : $*Int64 |
| dealloc_stack %1 : $*Int64 |
| %7 = tuple () // user: %8 |
| return %7 : $() |
| } |
| |
| |
| // CHECK-LABEL: sil @AddressOnlyTest |
| sil @AddressOnlyTest : $@convention(thin) (@inout P) -> () { |
| bb0(%0 : $*P): // CHECK: bb0(%0 : $*P): |
| %1 = alloc_stack $P |
| copy_addr %0 to [initialization] %1 : $*P |
| |
| // CHECK-NEXT: debug_value_addr %0 |
| // CHECK-NEXT: open_existential_addr %0 : $*P |
| %3 = open_existential_addr %1 : $*P to $*@opened("01234567-89ab-cdef-0123-000000000000") P |
| %4 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000") P, #P.foo!1, %3 : $*@opened("01234567-89ab-cdef-0123-000000000000") P : $@convention(witness_method) @callee_owned <T: P> (@inout T) -> () |
| |
| // CHECK: apply |
| %5 = apply %4<@opened("01234567-89ab-cdef-0123-000000000000") P>(%3) : $@convention(witness_method) @callee_owned <T: P> (@inout T) -> () |
| |
| copy_addr [take] %1 to %0 : $*P |
| dealloc_stack %1 : $*P |
| |
| // CHECK-NEXT: tuple () |
| %9 = tuple () |
| // CHECK-NEXT: return |
| return %9 : $() |
| } |
| |
| class C { |
| } |
| |
| struct NontrivialStruct { |
| var a: Int |
| var b: C |
| func foo() |
| } |
| |
| |
| sil @takeNontrivial : $@convention(method) (@inout NontrivialStruct) -> () |
| |
| // CHECK-LABEL: sil @NontrivialTest |
| sil @NontrivialTest : $@convention(thin) (@inout NontrivialStruct) -> () { |
| bb0(%0 : $*NontrivialStruct): |
| // CHECK: bb0(%0 : $*NontrivialStruct): |
| |
| %1 = alloc_stack $NontrivialStruct |
| copy_addr %0 to [initialization] %1 : $*NontrivialStruct |
| |
| // CHECK-NEXT: debug_value_addr %0 |
| // CHECK-NEXT: // function_ref takeNontrivial |
| // CHECK-NEXT: function_ref @takeNontrivial |
| %3 = function_ref @takeNontrivial : $@convention(method) (@inout NontrivialStruct) -> () // user: %4 |
| |
| // CHECK-NEXT: apply |
| %4 = apply %3(%1) : $@convention(method) (@inout NontrivialStruct) -> () |
| copy_addr [take] %1 to %0 : $*NontrivialStruct |
| dealloc_stack %1 : $*NontrivialStruct |
| |
| // CHECK-NEXT: tuple |
| %9 = tuple () |
| // CHECK-NEXT: return |
| return %9 : $() |
| } |
| |
| // Inout deshadowing should *not* deshadow inouts that are copied to temporaries for use by |
| // @in arguments. <rdar://problem/16105449> |
| |
| sil @in_argument : $@convention(thin) (@in Any) -> () |
| |
| // CHECK-LABEL: sil @inout_argument_passed_to_in_argument |
| sil @inout_argument_passed_to_in_argument : $@convention(thin) (@inout Any) -> () { |
| // CHECK: bb0([[INOUT:%.*]] : $*Any): |
| entry(%0 : $*Any): |
| %f = function_ref @in_argument : $@convention(thin) (@in Any) -> () |
| %x = alloc_stack $Any |
| // CHECK: copy_addr [[INOUT]] to [initialization] |
| copy_addr %0 to [initialization] %x : $*Any |
| %z = apply %f(%x) : $@convention(thin) (@in Any) -> () |
| dealloc_stack %x : $*Any |
| return %z : $() |
| } |
| |
| sil @makeError : $@convention(thin) () -> @owned Error |
| |
| struct MyStruct<T> { |
| @sil_stored var placeholder: T |
| @sil_stored var value: Bool |
| mutating func throwing(value: Bool) throws |
| init(placeholder: T, value: Bool) |
| } |
| |
| // Verify that we deshadow in functions that throw. |
| // CHECK-LABEL: throwing |
| sil hidden @throwing : $@convention(method) <T> (Bool, @inout MyStruct<T>) -> @error Error { |
| // CHECK: bb0 |
| bb0(%0 : $Bool, %1 : $*MyStruct<T>): |
| %2 = alloc_stack $MyStruct<T> |
| debug_value %0 : $Bool |
| // CHECK-NOT: copy_addr |
| copy_addr %1 to [initialization] %2 : $*MyStruct<T> |
| %5 = struct_extract %0 : $Bool, #Bool._value |
| cond_br %5, bb1, bb2 |
| |
| // CHECK: bb1 |
| bb1: |
| %7 = function_ref @makeError : $@convention(thin) () -> @owned Error |
| %8 = apply %7() : $@convention(thin) () -> @owned Error |
| %9 = builtin "willThrow"(%8 : $Error) : $() |
| // CHECK-NOT: copy_addr |
| copy_addr [take] %2 to %1 : $*MyStruct<T> |
| dealloc_stack %2 : $*MyStruct<T> |
| throw %8 : $Error |
| |
| // CHECK: bb2 |
| bb2: |
| %12 = struct_element_addr %2 : $*MyStruct<T>, #MyStruct.value |
| store %0 to %12 : $*Bool |
| // CHECK-NOT: copy_addr |
| copy_addr [take] %2 to %1 : $*MyStruct<T> |
| %15 = tuple () |
| dealloc_stack %2 : $*MyStruct<T> |
| return %15 : $() |
| } |