Skip to content

[send-non-sendable] Recurse to the full underlying value computation instead of just the object one when computing the underlying object of an address. #81716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions lib/SILOptimizer/Analysis/RegionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -985,13 +985,12 @@ RegionAnalysisValueMap::getUnderlyingTrackedValueHelperAddress(
// occur in the underlying DenseMap that backs getUnderlyingTrackedValue()
// if we insert another entry into the DenseMap.
if (!visitor.value)
return UnderlyingTrackedValueInfo(
getUnderlyingTrackedValueHelperObject(base));
return UnderlyingTrackedValueInfo(getUnderlyingTrackedValueHelper(base));

// TODO: Should we us the base or value from
// getUnderlyingTrackedValueHelperObject as our base?
return UnderlyingTrackedValueInfo(
visitor.value, getUnderlyingTrackedValueHelperObject(base).value);
visitor.value, getUnderlyingTrackedValueHelper(base).value);
}

// Otherwise, we return the actorIsolation that our visitor found.
Expand Down
42 changes: 42 additions & 0 deletions test/Concurrency/regionanalysis_trackable_value.sil
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ class NonSendableKlassWithState {

actor Custom {}

enum MyEnum<T> {
case none
indirect case some(NonSendableKlass)
case some2(T)
}

sil @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
sil @useNonSendableKlass : $@convention(thin) (@guaranteed NonSendableKlass) -> ()
sil @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
Expand Down Expand Up @@ -639,4 +645,40 @@ bb0(%0 : @owned $Struct2):
dealloc_stack %1
%9999 = tuple ()
return %9999 : $()
}

// CHECK-LABEL: begin running test 1 of 1 on indirect_enum_load_take: sil_regionanalysis_underlying_tracked_value with: @trace[0]
// CHECK: TrackableValue. State: TrackableValueState[id: 0][is_no_alias: yes][is_sendable: no][region_value_kind: disconnected].
// CHECK: Rep Value: %1 = alloc_stack $MyEnum<T>
// CHECK: end running test 1 of 1 on indirect_enum_load_take: sil_regionanalysis_underlying_tracked_value with: @trace[0]
sil [ossa] @indirect_enum_load_take : $@convention(thin) @async <T> (@in_guaranteed MyEnum<T>) -> () {
bb0(%0 : $*MyEnum<T>):
specify_test "sil_regionanalysis_underlying_tracked_value @trace[0]"
%1 = alloc_stack $MyEnum<T>
copy_addr %0 to [init] %1
switch_enum_addr %1, case #MyEnum.some!enumelt: bb1, default bb2

bb1:
%2 = unchecked_take_enum_data_addr %1, #MyEnum.some!enumelt
%3 = load [take] %2
%4 = project_box %3, 0
%5 = load_borrow %4
%6 = copy_value %5
debug_value [trace] %5
%7 = move_value [var_decl] %6
debug_value %5, let, name "x"
destroy_value %7
end_borrow %5
destroy_value %3
dealloc_stack %1
br bb3

bb2:
destroy_addr %1
dealloc_stack %1
br bb3

bb3:
%9999 = tuple ()
return %9999 : $()
}
18 changes: 18 additions & 0 deletions test/Concurrency/transfernonsendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ struct SendableGenericStruct : Sendable {
var x = SendableKlass()
}

enum MyEnum<T> {
case none
indirect case some(NonSendableKlass)
case more(T)
}

////////////////////////////
// MARK: Actor Self Tests //
////////////////////////////
Expand Down Expand Up @@ -2054,3 +2060,15 @@ func sendIsolatedValueToItsOwnIsolationDomain() {
}
}
}

// We used to crash on this since we were not looking finding underlying objects
// hard enough.
func indirectEnumTestCase<T>(_ e: MyEnum<T>) async -> Bool {
switch e {
case .some(let x):
_ = x
return true
default:
return false
}
}