Specifically, if we access a Sendable type from a ref_element_addr and the field
is mutable, we need to treat the use as a require since we could race on writing
to the field. If the field is a let though (and thus immutable), we can still
ignore it.
I also used this as an opportunity to add SIL tests for ref_element_addr.
This commit makes it so that we treat values captured by an actor isolated
closure as being transferred to that closure. I also introduced a new diagnostic
for these warnings that puts the main warning on the capture point of the value
so the user is able to see the actual capture that causes the transfer to occur:
```swift
nonisolated func testLocal2() async {
let l = NonSendableKlass()
// This is not safe since we use l later.
self.assumeIsolated { isolatedSelf in
isolatedSelf.ns = l
}
useValue(l) // expected-note {{access here could race}}
}
```
```
test.swift:74:14: warning: main actor-isolated closure captures value of non-Sendable type 'NonSendableKlass' from nonisolated context; later accesses to value could race
useValue(x) // expected-warning {{main actor-isolated closure captures value of non-Sendable type 'NonSendableKlass' from nonisolated context; later accesses to value could race}}
^
test.swift:76:12: note: access here could race
useValue(x) // expected-note {{access here could race}}
^
```
One thing to keep in mind is that if we have a function argument being captured
in this way, we still emit the "call site passes `self`" error. I am going to
begin cleaning that up in the next commit in this PR so that we emit a better
error here. But it makes sense to split these into two separate commits since
they are doing different things.
rdar://121345525
llvm::Optional<T> used to make it so that in asserts builds if one dereferenced the optional and nothing was there, one would get an assert. std::optional<T> does not have that property.
The specific semantics is if we assign into a transferring parameter's field,
then we "merge" src's value into the transferring parameter, so we
conservatively leave the region of the transferring parameter alone. If we
assign over the entire transferring parameter, we perform an assign fresh since
any value that used to be in the transferring parameter cannot reference
anything in its new value since they are all gone.
NOTE: This does not handle yet assignment into transferring parameters. In the
next commit, I am going to teach the checker that assigning into such a
parameter is a transfer.
To ensure that we preserve the correct behavior here, I added classification
helper functions that classify if an instruction can be look through. I used
this to drive the find base value code and added in asserts in the instruction
classifier to ensure that if an instruction is ever classified as LookThrough,
one of the helper routines handles it.
I am doing this because I discovered that mark_dependence was being
misclassified as assigned even though we wanted to treat it as being look
through in its first operand and since I kept on hitting merge conflicts with
the isa list option.
With this commit:
1. I am converting it to a switch in a utility function. That should prevent the
merge conflicts.
2. I also fixed mark_dependence's semantics.
3. I added an assert into CONSTANT_TRANSLATION(..., LookThrough) to make sure
that the switch and the CONSTANT_TRANSLATION code stays in sync.
Before this commit, this was done at the beginning of TransferNonSendable. I
thought that those checks would be sufficient to ensure that
RegionAnalysisFunctionInfo was not created for functions that we do not
support. Turns out when we perform certain forms of verification, we force all
function analyses to be created for all functions meaning that we would create a
RegionAnalysisFunctionInfo for such an unsupported function causing us to hit
asserts.
In this commit, I move the check to whether or not we support a function into
RegionAnalysisFunctionInfo itself and use that to determine if we should run
TransferNonSendable. This additionally allows me to change
RegionAnalysisFunctionInfo so that one can construct one for an unsupported
function... as long as one doesn't actually touch any of its methods. If one
does, I put in an assert so we will know that operator error has occured.
NFCI. This is just a pure refactor of the analysis part of TransferNonSendable
into a separate SIL level analysis so it can be reused by other passes.
The reason that I am committing this earlier is that I am working concurrently
on other patches that change TransferNonSendable itself and I want to avoid
issues when rebasing those patches. Getting this patch into tree earlier avoids
that.
This is in preparation for adding a new flow sensitive initialization pass that
combines region based analysis with the current flow sensitive isolation's
diagnostic emitter. The idea is that we want to preserve the diagnostics from
that pass rather than try to make our own as an initial step.