@@ -67,6 +67,8 @@ public struct InlineInt {
6767}
6868sil @globalAddress : $@convention(thin) () -> Builtin.RawPointer
6969sil @addressInt : $@convention(thin) (@in_guaranteed InlineInt) -> @lifetime(borrow address_for_deps 0) @owned Span<Int>
70+ sil @addressOfInt : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow address 0) @owned Span<Int>
71+ sil @noAddressInt : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow 0) @owned Span<Int>
7072sil @useSpan : $@convention(thin) (@guaranteed Span<Int>) -> ()
7173
7274// Test returning a owned dependence on a trivial value
@@ -259,10 +261,12 @@ bb0(%0 : $*NE, %1 : $*Holder):
259261// extends to the dealloc_stack.
260262//
261263// SILGen should never generate temporary stack copies for addressable dependencies, but we need to diagnose them anyway
262- // so that a SILGen bug does not become a miscompile.
264+ // so that a SILGen bug does not become a miscompile. Furthermore, LifetimeDependenceScopeFixup now automatically
265+ // extends such local allocations, so this diagnostic only fires on source-level tests when scope extension is
266+ // impossible.
263267//
264268// rdar://159680262 ([nonescapable] diagnose dependence on a temporary copy of a global array)
265- sil hidden [noinline] [ossa] @testTrivialStackCopy : $@convention(thin) () -> () {
269+ sil hidden [noinline] [ossa] @testTempTrivialStackCopy : $@convention(thin) () -> () {
266270bb0:
267271 %0 = function_ref @globalAddress : $@convention(thin) () -> Builtin.RawPointer
268272 %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
@@ -287,3 +291,64 @@ bb0:
287291 %18 = tuple ()
288292 return %18
289293}
294+
295+ // Test an address dependency on a trivial value temporarily copied to the stack. The value's addressable range only
296+ // extends to the dealloc_stack. This represents the SIL from @testTempTrivialStackCopy after
297+ // LifetimeDependenceScopeFixup has extended the local allocation.
298+ sil hidden [noinline] [ossa] @testExtendedTrivialStackCopy : $@convention(thin) () -> () {
299+ bb0:
300+ %0 = function_ref @globalAddress : $@convention(thin) () -> Builtin.RawPointer
301+ %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
302+ %2 = pointer_to_address %1 to [strict] $*InlineInt
303+ %3 = begin_access [read] [dynamic] %2
304+ %4 = load [trivial] %3
305+ end_access %3
306+ %6 = alloc_stack $InlineInt
307+ store %4 to [trivial] %6
308+
309+ %8 = function_ref @addressInt : $@convention(thin) (@in_guaranteed InlineInt) -> @lifetime(borrow address_for_deps 0) @owned Span<Int>
310+ %9 = apply %8(%6) : $@convention(thin) (@in_guaranteed InlineInt) -> @lifetime(borrow address_for_deps 0) @owned Span<Int>
311+ %10 = mark_dependence [unresolved] %9 on %6
312+ %11 = move_value [var_decl] %10
313+ %13 = begin_borrow %11
314+
315+ %14 = function_ref @useSpan : $@convention(thin) (@guaranteed Span<Int>) -> ()
316+ %15 = apply %14(%13) : $@convention(thin) (@guaranteed Span<Int>) -> ()
317+ end_borrow %13
318+ destroy_value %11
319+ dealloc_stack %6
320+ %18 = tuple ()
321+ return %18
322+ }
323+
324+ // Test two address dependencies on the same temporay. The first dependency is addressable; it's uses are covered by the
325+ // stack allocation. The second dependency is non-addressable; it's uses are not covered by the stack allocation. So,
326+ // this is correct SIL but is falsely diagnosed as a lifetime error. This conservative error is fine because SILGen
327+ // never reuses a temporary allocaiton for both an addressable and non-addressable dependency.
328+ sil hidden [noinline] [ossa] @testFalseTempTrivialStackCopy : $@convention(thin) (Int) -> () {
329+ bb0(%0: $Int):
330+ %1 = alloc_stack $Int
331+ store %0 to [trivial] %1
332+
333+ %3 = function_ref @addressOfInt : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow address 0) @owned Span<Int>
334+ %4 = apply %3(%1) : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow address 0) @owned Span<Int>
335+ %5 = mark_dependence [unresolved] %4 on %1
336+ %6 = move_value [var_decl] %5
337+ destroy_value %6
338+
339+ %8 = function_ref @noAddressInt : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow 0) @owned Span<Int>
340+ %9 = apply %8(%1) : $@convention(thin) (@in_guaranteed Int) -> @lifetime(borrow 0) @owned Span<Int>
341+ %10 = mark_dependence [unresolved] %9 on %1
342+ %11 = move_value [var_decl] %10 // expected-error{{lifetime-dependent value escapes its scope}}
343+ // expected-note@-15{{it depends on the lifetime of an argument of 'testFalseTempTrivialStackCopy'}}
344+
345+ dealloc_stack %1
346+
347+ %13 = begin_borrow %11
348+ %14 = function_ref @useSpan : $@convention(thin) (@guaranteed Span<Int>) -> ()
349+ %15 = apply %14(%13) : $@convention(thin) (@guaranteed Span<Int>) -> ()
350+ end_borrow %13
351+ destroy_value %11 // expected-note{{this use of the lifetime-dependent value is out of scope}}
352+ %18 = tuple ()
353+ return %18
354+ }
0 commit comments