This is necessary to fix a recent OSSA bug that breaks common occurrences on
mark_dependence [nonescaping]. Rather than reverting that change above, we make
forward progress toward implicit borrows scopes, as was the original intention.
In the near future, all InteriorPointer instructions will create an implicit
borrow scope. This means we have the option of not emitting extraneous
begin/end_borrow instructions around intructions like ref_element_addr,
open_existential, and project_box. After that, we can also migrate
GuaranteedForwarding instructions like tuple_extract and struct_extract.
When checking whether an instruction is contained in a liveness
boundary, a pointer to a DeadEndBlocks instance must always be passed.
When the pointer is null, it is only checked that the instruction occurs
within the direct live region. When the pointer is non-null, it is
checked whether the instruction occurs within the region obtained by
extending the live region up to the availability boundary within
dead-end regions that are adjacent to the non-lifetime-ending portion of
the liveness boundary.
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
Function call arguments were not being treated as liveness uses.
Unblocks SIL: Treat store_borrow as borrowing its source, and have the
move-only checker account for borrow scopes. #69169https://github.com/apple/swift/pull/69169
`SSAPrunedLiveness::invalidate` is used as though it reset the state of
the instance it is called on. Clients then reuse the instance with the
expectation that it has been reset. But since it has not been reset,
this results in unexpected liveness results.
rdar://108627366
Use BasicBlockBitfield to record per-block liveness state. This has
been the intention since BasicBlockBitfield was first introduced.
Remove the per-field bitfield from PrunedLiveBlocks. This
(re)specializes the data structure for scalar liveness and drastically
simplifies the implementation.
This utility is fundamental to all ownership utilities. It will be on
the critical path in many areas of the compiler, including at
-Onone. It needs to be minimal and as easy as possible for compiler
engineers to understand, investigate, and debug.
This is in preparation for fixing bugs related to multi-def liveness
as used by the move checker.
The API for computing simple liveness now returns a
SimpleLiveRangeSummary. Callers need to decide how to handle reborrows
and pointer escapes. If either condition exists then the resulting
liveness does not necessarily encapsulate the definition's ownership.
Fixes some number of latent bugs w.r.t. liveness clients.
First restore the basic PrunedLiveness abstraction to its original
intention. Move code outside of the basic abstraction that polutes the
abstraction and is fundamentally wrong from the perspective of the
liveness abstraction.
Most clients need to reason about live ranges, including the def
points, not just liveness based on use points. Add a PrunedLiveRange
layer of types that understand where the live range is
defined. Knowing where the live range is defined (the kill set) helps
reliably check that arbitrary points are within the boundary. This
way, the client doesn't need to be manage this on its own. We can also
support holes in the live range for non-SSA liveness. This makes it
safe and correct for the way liveness is now being used. This layer
safety handles:
- multiple defs
- instructions that are both uses and defs
- dead values
- unreachable code
- self-loops
So it's no longer the client's responsibility to check these things!
Add SSAPrunedLiveness and MultiDefPrunedLiveness to safely handle each
situation.
Split code that I can't figure out into
DiagnosticPrunedLiveness. Hopefully it will be deleted soon.
Andy some time ago already created the new API but didn't go through and update
the old occurences. I did that in this PR and then deprecated the old API. The
tree is clean, so I could just remove it, but I decided to be nicer to
downstream people by deprecating it first.
Borrowed values can still escape and be copied:
%alloc = allocation
%borrow = begin_borrow %alloc
apply(%borrow) // escape
end_borrow %borrow
weak_store %alloc
Don't warn in this case.
While we're at it, handle all kinds of forwarding operations
consistently. Otherwise, it's far too easy for the anlysis to be
defeated, making it unlikely to catch bugs that cause spurious
warnings.
Fixes rdar://79146338 (Xcode warns that "referenced object is
deallocated here" but that object was passed into a method that causes
strong retention)
This
1. fixes a bug, where we didn't consider that an object can escape via a function call. The pass issued a false warning in this case.
rdar://76115467
2. improves the accuracy by doing a simple form of interprocedural analysis. E.g. it now can see if a weak store is done in a called function.
rdar://76297286
Issue warnings if an object is stored to an ObjectiveC weak property (via a setter) and destroyed before the property is ever used again.
rdar://74620325
The DiagnoseLifetimeIssuesPass pass prints a warning if an object is stored to a weak property (or is weakly captured) and destroyed before the property (or captured reference) is ever used again.
This can happen if the programmer relies on the lexical scope to keep an object alive, but copy-propagation can shrink the object's lifetime to its last use.
For example:
func test() {
let k = Klass()
// k is deallocated immediately after the closure capture (a store_weak).
functionWithClosure({ [weak k] in
// crash!
k!.foo()
})
}
Unfortunately this pass can only catch simple cases, but it's better than nothing.
rdar://73910632