Skip to content

Commit

Permalink
LifetimeDependence.Scope: recognize @in_guaranteed dependencies.
Browse files Browse the repository at this point in the history
Unlike @in, treat @in_guaranteed like a caller-side dependence
scope because there is not need to look for the end of the lifetime in the
current function.

Completely fixes rdar://142847915 (Crash during lifetime checking
while building new swift standard library `Span`-related features)
  • Loading branch information
atrick committed Jan 14, 2025
1 parent 9f1d727 commit c8bec28
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ extension LifetimeDependence.Scope {
self = Self(guaranteed: refElt.operand.value, context)
case let .argument(arg):
if arg.convention.isIndirectIn {
self = .initialized(initialAddress: arg, initializingStore: nil)
if arg.convention.isGuaranteed {
self = .caller(arg)
} else {
self = .initialized(initialAddress: arg, initializingStore: nil)
}
} else if arg.convention.isIndirectOut || arg.convention.isInout {
// TODO: verify that @out values are never reassigned.
self = .caller(arg)
Expand Down
69 changes: 69 additions & 0 deletions test/SILOptimizer/lifetime_dependence/diagnostic_passes.sil
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %target-sil-opt -test-runner %s \
// RUN: -diagnostics -sil-verify-all \
// RUN: -enable-experimental-feature LifetimeDependence \
// RUN: -enable-experimental-feature Span \
// RUN: 2>&1 | %FileCheck %s

// Test SIL expected from SILGen output. Run all diagnostic passes which includes lifetime dependence handling:
Expand All @@ -12,6 +13,7 @@

// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_LifetimeDependence
// REQUIRES: swift_feature_Span

sil_stage raw

Expand All @@ -23,9 +25,15 @@ struct Owner {}
struct NE: ~Escapable {}
struct OtherNE: ~Escapable {}

public struct Container {
var pointer: UnsafeRawPointer
var object: AnyObject
}

sil @getNE : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased NE
sil @copyNE : $@convention(c) (NE, @lifetime(copy 0) @inout NE) -> ()
sil @makeOwner : $@convention(c) () -> Owner
sil @_overrideLifetimeBorrowing : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : ~Copyable, τ_0_0 : ~Escapable, τ_0_1 : ~Copyable, τ_0_1 : ~Escapable> (@in τ_0_0, @in_guaranteed τ_0_1) -> @lifetime(borrow 1) @out τ_0_0

// Modify a local via 'inout' assignment.
// Do not insert a mark_dep.
Expand Down Expand Up @@ -129,3 +137,64 @@ bb0:
%93 = tuple ()
return %93 : $()
}

// Init.init()
sil @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
// RawSpan.init()
sil @$ss7RawSpanV12_unsafeStart9byteCountABSV_SitcfC : $@convention(method) (UnsafeRawPointer, Int, @thin RawSpan.Type) -> @lifetime(borrow 0) @owned RawSpan

// Test dependence on an in_guaranteed address and a store_borrow.
//
// A mark_dependence will be created for %23 apply, but OnonSimplify will later remove it.
//
// CHECK-LABEL: sil [available 9999] [ossa] @testInGuaranteedRawSpan : $@convention(method) (@in_guaranteed Container) -> @lifetime(borrow 0) @owned RawSpan {
// CHECK: bb0(%0 : $*Container):
// CHECK: [[GETSPAN:%.*]] = apply %{{.*}}({{.*}}) : $@convention(method) (UnsafeRawPointer, Int, @thin RawSpan.Type) -> @lifetime(borrow 0) @owned RawSpan
// CHECK: mark_dependence [nonescaping] [[GETSPAN]] on %0
// CHECK: [[OUT:%.*]] = alloc_stack $RawSpan
// CHECK: [[IN:%.*]] = alloc_stack $RawSpan
// CHECK: store %{{.*}} to [init] [[IN]]
// CHECK: [[LB:%.*]] = load_borrow %0
// CHECK: [[BORROWSELF:%.*]] = alloc_stack $Container
// CHECK: [[SB:%.*]] = store_borrow [[LB]] to [[BORROWSELF]]
// CHECK: apply %{{.*}}<RawSpan, Container>([[OUT]], [[IN]], [[SB]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : ~Copyable, τ_0_0 : ~Escapable, τ_0_1 : ~Copyable, τ_0_1 : ~Escapable> (@in τ_0_0, @in_guaranteed τ_0_1) -> @lifetime(borrow 1) @out τ_0_0
// CHECK: [[RET:%.*]] = load [take] [[OUT]]
// CHECK: return [[RET]]
// CHECK-LABEL: } // end sil function 'testInGuaranteedRawSpan'
sil [available 9999] [ossa] @testInGuaranteedRawSpan : $@convention(method) (@in_guaranteed Container) -> @lifetime(borrow 0) @owned RawSpan {
bb0(%0 : $*Container):
debug_value %0, let, name "self", argno 1, expr op_deref
%2 = metatype $@thin RawSpan.Type
%3 = load_borrow %0
%4 = struct_extract %3, #Container.pointer
%5 = integer_literal $Builtin.IntLiteral, 0
%6 = metatype $@thin Int.Type
%7 = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
%8 = apply %7(%5, %6) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int

%9 = function_ref @$ss7RawSpanV12_unsafeStart9byteCountABSV_SitcfC : $@convention(method) (UnsafeRawPointer, Int, @thin RawSpan.Type) -> @lifetime(borrow 0) @owned RawSpan
%10 = apply %9(%4, %8, %2) : $@convention(method) (UnsafeRawPointer, Int, @thin RawSpan.Type) -> @lifetime(borrow 0) @owned RawSpan
end_borrow %3
%12 = move_value [var_decl] %10
debug_value %12, let, name "span"
%14 = alloc_stack $RawSpan
%15 = begin_borrow %12
%16 = copy_value %15
%17 = alloc_stack $RawSpan
store %16 to [init] %17
%19 = load_borrow %0
%20 = alloc_stack $Container
%21 = store_borrow %19 to %20

%22 = function_ref @_overrideLifetimeBorrowing : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : ~Copyable, τ_0_0 : ~Escapable, τ_0_1 : ~Copyable, τ_0_1 : ~Escapable> (@in τ_0_0, @in_guaranteed τ_0_1) -> @lifetime(borrow 1) @out τ_0_0
%23 = apply %22<RawSpan, Container>(%14, %17, %21) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : ~Copyable, τ_0_0 : ~Escapable, τ_0_1 : ~Copyable, τ_0_1 : ~Escapable> (@in τ_0_0, @in_guaranteed τ_0_1) -> @lifetime(borrow 1) @out τ_0_0
end_borrow %21
dealloc_stack %20
end_borrow %19
dealloc_stack %17
end_borrow %15
%29 = load [take] %14
dealloc_stack %14
destroy_value %12
return %29
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,9 @@ entry(%0 : @owned $C, %1 : @owned $D, %2 : @guaranteed $D, %3 : $*D, %4 : $*D):
%inguaranteed_arg_mark = mark_dependence [nonescaping] %guaranteed_arg_mark : $C on %3 : $*D
specify_test "lifetime_dependence_scope %inguaranteed_arg_mark"
// CHECK-LABEL: dependence_scope: lifetime_dependence_scope with: %inguaranteed_arg_mark
// CHECK-NEXT: Initialized: %3 = argument of bb0 : $*D
// CHECK-NEXT: Caller: %3 = argument of bb0 : $*D
// CHECK-NEXT: Dependent: %{{.*}} = mark_dependence [nonescaping] %{{.*}} : $C on %3 : $*D
// CHECK-NEXT: begin: bb0
// CHECK-NEXT: ends:
// CHECK-NEXT: Caller range
// CHECK: dependence_scope: lifetime_dependence_scope with: %inguaranteed_arg_mark

%inout_arg_mark = mark_dependence [nonescaping] %inguaranteed_arg_mark : $C on %4 : $*D
Expand Down

0 comments on commit c8bec28

Please sign in to comment.