Handle the special case of an guaranteed return value with no uses.
Fixes an assertion crash.
Unfortunately I don't have an isolated test case for this.
But this problem showed up in the `Interpreter/moveonly_read_modify_coroutines.swift` test with OSSA modules and will therefore be tested by this test once we enable OSSA modules.
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand
This is used for synthetic uses like _ = x that do not act as a true use but
instead only suppress unused variable warnings. This patch just adds the
instruction.
Eventually, we can use it to move the unused variable warning from Sema to SIL
slimmming the type checker down a little bit... but for now I am using it so
that other diagnostic passes can have a SIL instruction (with SIL location) so
that we can emit diagnostics on code like _ = x. Today we just do not emit
anything at all for that case so a diagnostic SIL pass would not see any
instruction that it could emit a diagnostic upon. In the next patch of this
series, I am going to add SILGen support to do that.
To determine where a lifetime ends within dead-end blocks,
OSSACanonicalizeOwned uses OSSACompleteLifetime's
visitAvailabilityBoundary. This API takes a liveness which it uses to
walk forward to the availability boundary. Specifically, the liveness
passed from OSSACanonicalizeOwned to OSSACompleteLifetime is a variation
of OSSACanonicalizeOwned's own liveness (it has destroys added).
There is a mismatch in the characteristics of livenesses created by
OSSACanonicalizeOwned and OSSACompleteLifetime: The former deals with
not only direct uses of a value but also uses of its copies; that
introduces the possibility for consuming uses in the middle of liveness.
The latter on the other hand deals only with uses of a single value
(nestedly, but at each level of nesting only a single value). Passing a
liveness from the former to the latter without handling this mismatch
is incorrect: OSSACompleteLifetime understands consuming uses to always
end a lifetime, even when they are in the middle of a copy-extended
liveness. The result is that OSSACompleteLifetime produces non-sensical
results when provided with such a liveness.
To address this, fixup the liveness passed from OSSACanonicalizeOwned to
OSSACompleteLifetime by demoting consuming uses that appear within
(that's to say _not_ on the boundary) of liveness to non-consuming uses.
rdar://142846936
When visiting a consuming use of a move-only value (which can be
produced by a forwarding operation), the inner rewriter must bail out.
Otherwise, it would produce a copy of that move-only value.
rdar://142520491
Allow rewriting of arguments to bail out. This is necessary because not
all forwarding instructions allow rewriting of forward(copy) as
copy(forward) (e.g. when forward produces a move-only value).
I did the correct thing for indirect parameters, but did not do the correct
thing for direct parameters. This is now fixed with some tests to boot.
rdar://141631655
This is needed after running the SSAUpdater for an existing OSSA value, because the updater can
insert unnecessary phis in the middle of the original liverange which breaks up the original
liverange into smaller ones:
```
%1 = def_of_owned_value
%2 = begin_borrow %1
...
br bb2(%1)
bb2(%3 : @owned $T): // inserted by SSAUpdater
...
end_borrow %2 // use after end-of-lifetime!
destroy_value %3
```
It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange.
It can happen that the SSAUpdater inserts a phi-argument with all incoming values being the same.
If a value is requested in the phi-block we must not use the unique incoming value, but we have to re-use the phi argument, because the lifetime of the incoming values end at in the predecessor blocks.
rdar://129859331
This patch adds false positive detection to sil-stats-lost-variables.
We will now only detect a debug_value as lost if there is a real
instruction which belongs to the same scope or a child scope of the
scope of the debug_value and if they are both inline at the same
location.
//a
Because discovery of defs walks into reborrows and borrowed-from
instructions, copies may be seen whose underlying value is a guaranteed
value (namely, a reborrow or a borrowed-from instruction). Such copies
may be used beyond the lifetime end of such guaranteed values, so it's
not allowed to sink copies to their consuming uses. Such
canonicalization is the responsibility of the OSSACanonicalizeGuaranteed
utility.
rdar://139842132
The utility performs two def-use traversals. The first determines
liveness from uses. The second rewrites copies.
Previously, the defs whose uses were analyzed were discovered twice,
once during each traversal. The non-triviality of the discovery logic
(i.e. the logic determining when to walk into the values produced by the
instructions which were the users of visited uses) opened the
possibility for a divergence between the two discoveries. This
possibility had indeed been realized--the two traversals didn't visit
exactly the same uses, and issues ensue.
Here, the defs whose uses are analyzed are discovered only once (and not
discarded as their uses are analyzed) during the first traversal. The
second traversal reuses the defs discovered in the first traversal,
eliminating the possibility of a def discovery difference.
The second traversal is now done in a different order. This results in
perturbing the SIL in certain cases.
In preparation for only recording the defs once, replace the
GraphNodeWorklist of defs with a SetVector. Preserve the current
visitation order by creating a worklist of indices to be visited.
When rewriting uses, determine how that rewriting should proceed based
on the kind of def whose use is being visited. Direct uses of reborrows
and borrowed-froms never need to be rewritten because every such use is
a use of a guaranteed value and can never require a copy.
Add a type which distinguishes among the types of defs that are pushed
onto the "def-use worklist". Note that it's not possible to rely on the
kind of value because the root may itself be a copy_value. For now, the
distinction is discarded as soon as the def is visited.
In terms of the test suite the only difference is that we allow for non-Sendable
types to be returned from nonisolated functions. This is safe due to the rules
of rbi. We do still error when we return non-Sendable functions across isolation
boundaries though.
The reason that I am doing this now is that I am implementing a prototype that
allows for nonisolated functions to inherit isolation from their caller. This
would have required me to implement support both in Sema for results and
arguments in SIL. Rather than implement results in Sema, I just finished the
work of transitioning the result checking out of Sema and into SIL. The actual
prototype will land in a subsequent change.
rdar://127477211
I am doing this since I discovered that we are not printing certain errors as
early as we used to (due to the refactoring I did here), which makes it harder
to see the errors that we are emitting while processing individual instructions
and before we run the actual dataflow.
A nice side-effect of this is that it will make it easy to dump the error in the
debugger rather than having to wait until the point in the code where the normal
logging takes place.
A begin_apply token may be used by operands that do not end the coroutine:
mark_dependence.
We need an API that gives us only the coroutine-ending uses. This blocks
~Escapable accessors.
end_borrow is considered coroutine-ending even though it does not actually
terminate the coroutine.
We cannot simply ask isLifetimeEnding, because end_apply and abort_apply do not
end any lifetime.
The conformances no longer match the replacement types after the
transformation here, so we must look them up again. This is now
flagged by SubstitutionMap::verify().