File: diagnose_lifetime_issues.sil

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (160 lines) | stat: -rw-r--r-- 6,653 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnose-lifetime-issues -o /dev/null -verify

import Builtin
import Swift

enum FakeOptional<T> {
case none
case some(T)
}

class Delegate {
  func foo() { }
}

class MyDelegate : Delegate {}

final class Container {
  weak var delegate: Delegate?
  var strongRef: Delegate

  func callDelegate()

  func strongDelegate(d: Delegate)
}

class WeakCycle {
  weak var c: WeakCycle?
}

sil [ossa] @$s24diagnose_lifetime_issues8DelegateCACycfC : $@convention(method) (@thick Delegate.Type) -> @owned Delegate
sil [ossa] @$s24diagnose_lifetime_issues10MyDelegateCACycfC : $@convention(method) (@thick MyDelegate.Type) -> @owned MyDelegate
sil [ossa] @$s24diagnose_lifetime_issues14strongDelegate1dyAA0D0C_tF : $@convention(method) (@guaranteed Delegate, @guaranteed Container) -> ()

// Test a warning for a reference that is copied, cast, and assigned
// to an enum before it is assigned to a weak reference.
sil [ossa] @testCastWarn : $@convention(thin) (@guaranteed Container) -> () {
bb0(%0 : @guaranteed $Container):
  debug_value %0 : $Container, let, name "container", argno 1
  %2 = metatype $@thick MyDelegate.Type
  // function_ref MyDelegate.__allocating_init()
  %3 = function_ref @$s24diagnose_lifetime_issues10MyDelegateCACycfC : $@convention(method) (@thick MyDelegate.Type) -> @owned MyDelegate

  // This is the owned allocation.
  %4 = apply %3(%2) : $@convention(method) (@thick MyDelegate.Type) -> @owned MyDelegate
  %11 = copy_value %4 : $MyDelegate

  // This upcast+enum is not an escape.
  %12 = upcast %11 : $MyDelegate to $Delegate
  %13 = enum $Optional<Delegate>, #Optional.some!enumelt, %12 : $Delegate
  %14 = ref_element_addr %0 : $Container, #Container.delegate
  %15 = begin_access [modify] [dynamic] %14 : $*@sil_weak Optional<Delegate>

  // This is the weak assignment.
  store_weak %13 to %15 : $*@sil_weak Optional<Delegate> // expected-warning {{weak reference will always be nil because the referenced object is deallocated here}}
  destroy_value %13 : $Optional<Delegate>
  end_access %15 : $*@sil_weak Optional<Delegate>
  destroy_value %4 : $MyDelegate
  %20 = tuple ()
  return %20 : $()
}

// Test that a reference that escapes within a borrow scope has no warning.
sil hidden [ossa] @testBorrowNoWarn : $@convention(thin) (@guaranteed Container) -> () {
// %0 "container"
bb0(%0 : @guaranteed $Container):
  debug_value %0 : $Container, let, name "container", argno 1
  %2 = metatype $@thick MyDelegate.Type
  // function_ref MyDelegate.__allocating_init()
  %3 = function_ref @$s24diagnose_lifetime_issues10MyDelegateCACycfC : $@convention(method) (@thick MyDelegate.Type) -> @owned MyDelegate

  // This is the owned allocation.
  %4 = apply %3(%2) : $@convention(method) (@thick MyDelegate.Type) -> @owned MyDelegate
  debug_value %4 : $MyDelegate, let, name "delegate"
  %6 = begin_borrow %4 : $MyDelegate
  %7 = upcast %6 : $MyDelegate to $Delegate
  // function_ref Container.strongDelegate(d:)
  %8 = function_ref @$s24diagnose_lifetime_issues14strongDelegate1dyAA0D0C_tF : $@convention(method) (@guaranteed Delegate, @guaranteed Container) -> ()

  // This apply is an escape.
  %9 = apply %8(%7, %0) : $@convention(method) (@guaranteed Delegate, @guaranteed Container) -> ()
  end_borrow %6 : $MyDelegate
  %11 = copy_value %4 : $MyDelegate
  %12 = upcast %11 : $MyDelegate to $Delegate
  %13 = enum $Optional<Delegate>, #Optional.some!enumelt, %12 : $Delegate
  %14 = ref_element_addr %0 : $Container, #Container.delegate
  %15 = begin_access [modify] [dynamic] %14 : $*@sil_weak Optional<Delegate>

  // This is the weak assignment.
  store_weak %13 to %15 : $*@sil_weak Optional<Delegate>
  destroy_value %13 : $Optional<Delegate>
  end_access %15 : $*@sil_weak Optional<Delegate>
  destroy_value %4 : $MyDelegate
  %20 = tuple ()
  return %20 : $()
}

// Helper for testReturnsAfterStore
sil hidden [ossa] @testStoresWeakly : $@convention(method) (@owned WeakCycle) -> @owned WeakCycle {
bb0(%0 : @owned $WeakCycle):
  %18 = begin_borrow %0 : $WeakCycle
  %19 = copy_value %0 : $WeakCycle
  %20 = enum $Optional<WeakCycle>, #Optional.some!enumelt, %19 : $WeakCycle
  %21 = ref_element_addr %18 : $WeakCycle, #WeakCycle.c
  %22 = begin_access [modify] [dynamic] %21 : $*@sil_weak Optional<WeakCycle>
  store_weak %20 to %22 : $*@sil_weak Optional<WeakCycle>
  destroy_value %20 : $Optional<WeakCycle>
  end_access %22 : $*@sil_weak Optional<WeakCycle>
  end_borrow %18 : $WeakCycle
  %27 = copy_value %0 : $WeakCycle
  destroy_value %0 : $WeakCycle
  return %27 : $WeakCycle
}

// Test no warning for a value returned after a weak store.
sil hidden [exact_self_class] [ossa] @testReturnsAfterStore : $@convention(method) (@thick WeakCycle.Type) -> @owned WeakCycle {
bb0(%0 : $@thick WeakCycle.Type):
  %1 = alloc_ref $WeakCycle

  %2 = function_ref @testStoresWeakly : $@convention(method) (@owned WeakCycle) -> @owned WeakCycle
  %3 = apply %2(%1) : $@convention(method) (@owned WeakCycle) -> @owned WeakCycle
  return %3 : $WeakCycle
}

// Helper
sil private [ossa] @testBorrowInDefer$defer : $@convention(thin) (@guaranteed Delegate) -> () {
bb0(%0 : @closureCapture @guaranteed $Delegate):
  debug_value %0 : $Delegate, let, name "delegate", argno 1
  fix_lifetime %0 : $Delegate
  %8 = tuple ()
  return %8 : $()
}

// Test no warning for a value kept alive within a call which does not escape its argument.
sil hidden [ossa] @testBorrowinDefer : $@convention(thin) (@guaranteed Container) -> () {
bb0(%0 : @guaranteed $Container):
  debug_value %0 : $Container, let, name "container", argno 1
  %2 = metatype $@thick Delegate.Type
  // function_ref Delegate.__allocating_init()
  %3 = function_ref @$s24diagnose_lifetime_issues8DelegateCACycfC : $@convention(method) (@thick Delegate.Type) -> @owned Delegate

  // This is the owned allocation.
  %4 = apply %3(%2) : $@convention(method) (@thick Delegate.Type) -> @owned Delegate
  %6 = copy_value %4 : $Delegate
  %7 = enum $Optional<Delegate>, #Optional.some!enumelt, %6 : $Delegate
  %8 = ref_element_addr %0 : $Container, #Container.delegate
  %9 = begin_access [modify] [dynamic] %8 : $*@sil_weak Optional<Delegate>

  // This is the weak assignment.
  store_weak %7 to %9 : $*@sil_weak Optional<Delegate>
  destroy_value %7 : $Optional<Delegate>
  end_access %9 : $*@sil_weak Optional<Delegate>

  // This call keeps the parent alive
  %15 = function_ref @testBorrowInDefer$defer : $@convention(thin) (@guaranteed Delegate) -> () // user: %16
  %16 = apply %15(%4) : $@convention(thin) (@guaranteed Delegate) -> ()

  destroy_value %4 : $Delegate
  %18 = tuple ()
  return %18 : $()
}