Commit Graph

41 Commits

Author SHA1 Message Date
Nate Chandler
8f1d6616af [NFC] OSSACanonicalizeOwned: Renamed. 2025-08-18 09:45:21 -07:00
Nate Chandler
aa85694237 [NFC] OSSACompleteLifetime: Renamed. 2025-08-18 09:45:19 -07:00
Nate Chandler
9b3db3646a [MoveOnlyChecker] Don't complete phis.
Apply the MoveOnlyAddressChecker change from
https://github.com/swiftlang/swift/pull/73358 to the
MoveOnly[Value]Checker.

After 7713eef817, before running value
checking, all lifetimes in the function are completed.  That doesn't
quite work because lifetime completion expects not to encounter
reborrows or their adjacent phis.

rdar://151325025
2025-05-16 11:58:44 -07:00
Nate Chandler
d18a0178bb [Gardening] Whitespace cleanup. 2025-05-16 11:36:22 -07:00
Nate Chandler
4a397cc018 [NFC] OwnedLifetimeCan: Take DeadEndBlocksAnalysis
All clients of OwnedLifetimeCanonicalization pass an instance of the
analysis in.  For now, it's unused.
2024-07-22 21:51:28 -07:00
Nate Chandler
dd730b849c [LifetimeCompletion] Flag instructions dead_end. 2024-07-03 16:44:35 -07:00
Nate Chandler
451a814363 [MoveOnlyAddressChecker] Complete block args.
Now that the underlying issue (PrunedLiveness' merging of summaries for
branch instructions) has been fixed, reinstate lifetime completion and
add a test to verify that it behaves correctly.

This reverts commit c552b90b61
("Temporarily turn off completing lifetimes of block arguments").

rdar://130427564
2024-06-28 15:07:31 -07:00
Joe Groff
636a19d11b Merge pull request #74707 from jckarter/consume-during-borrow-checks
MoveOnlyAddressChecker: More robust checking for consume-during-borrow.
2024-06-26 08:22:04 -07:00
Joe Groff
27a8852290 MoveOnlyAddressChecker: More robust checking for consume-during-borrow.
- While an opaque borrow access occurs to part of a value, the entire scope of
  the access needs to be treated as a liveness range, so add the `EndAccess`es
  to the liveness range.
- The SIL verifier may crash the compiler on SILGen-generated code when the
  developer's source contains consume-during-borrow code patterns. Allow
  `load_borrow` instructions to be marked `[unchecked]`, which suppresses
  verifier checks until the move checker runs and gets a chance to properly
  diagnose these errors.

Fixes rdar://124360175.
2024-06-25 14:10:02 -07:00
Meghana Gupta
c552b90b61 Temporarily turn off completing lifetimes of block arguments 2024-06-24 08:14:18 -07:00
Tim Kientzle
1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
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)
2024-06-05 19:37:30 -07:00
Nate Chandler
518de7c6b1 [LifetimeCompletion] Require boundary spec.
Don't default to one boundary or another based on whether the value
being completed is lexical.
2024-05-08 17:15:15 -07:00
Nate Chandler
3e2d1d0e4c [MoveOnlyAddressChecker] Complete lifetimes first.
It relies on complete lifetimes for its analysis.  So if there are any
instructions to check, complete all lifetimes in the function first.
2024-04-19 14:47:35 -07:00
Nate Chandler
e40581a61b [MoveChecker] Visit and delete markers in PO.
Visit in post-order in order to resolve markers from the inside out,
required for per-field consume.
2024-03-06 20:54:17 -08:00
Michael Gottesman
3236bc26fa [region-isolation] Refactor out the stubify dead function if no longer used functionality from move only checker into its own pass and put it before region based isolation.
I am doing this since region based isolation hit the same issue that the move
checker did. So it makes sense to refactor the functionality into its own pass
and move it into a helper pass that runs before both.

It is very conservative and only stubifies functions that the specialization
passes explicitly mark as this being ok to be done to.
2024-03-01 13:11:07 -08:00
Nate Chandler
336afca477 [SILOpt] Removed unreachable bailouts.
Now that supportsMoveOnlyTypes is always true, these bailouts can't be
reached.  Delete the bailouts and the predicate.
2024-02-05 17:40:17 -08:00
swift-ci
7fed4ac81f Merge remote-tracking branch 'origin/main' into rebranch 2023-09-07 12:38:47 -07:00
Nate Chandler
7713eef817 [MoveValueChecker] Complete lifetimes first.
Before move-checking values, complete the lifetimes of all the values
derived from them via copy, borrow, and move.

Collect all such values and their derived transitive values and then
complete the lifetimes of each, visiting the instructions which produce
them in post-order.

Once OSSALifetimeCommpletion runs as part of SILGenCleanup, this code
can be deleted.
2023-09-07 07:11:24 -07:00
Sophia Poirier
86d368f364 Merge remote-tracking branch 'upstream/main' into fix-rebranch-automerger 2023-08-31 14:10:52 -07:00
Michael Gottesman
37d60a08bb [move-only] Rename mark_must_check -> mark_unresolved_non_copyable_value.
I was originally hoping to reuse mark_must_check for multiple types of checkers.
In practice, this is not what happened... so giving it a name specifically to do
with non copyable types makes more sense and makes the code clearer.

Just a pure rename.
2023-08-30 22:29:30 -07:00
Evan Wilde
309aed4925 Add SmallSetVector replacement
llvm::SmallSetVector changed semantics
(https://reviews.llvm.org/D152497) resulting in build failures in Swift.
The old semantics allowed usage of types that did not have an
`operator==` because `SmallDenseSet` uses `DenseSetInfo<T>::isEqual` to
determine equality. The new implementation switched to using
`std::find`, which internally uses `operator==`. This type is used
pretty frequently with `swift::Type`, which intentionally deletes
`operator==` as it is not the canonical type and therefore cannot be
compared in normal circumstances.

This patch adds a new type-alias to the Swift namespace that provides
the old semantic behavior for `SmallSetVector`. I've also gone through
and replaced usages of `llvm::SmallSetVector` with the
`Swift::SmallSetVector` in places where we're storing a type that
doesn't implement or explicitly deletes `operator==`. The changes to
`llvm::SmallSetVector` should improve compile-time performance, so I
left the `llvm::SmallSetVector` where possible.
2023-07-25 12:28:27 -07:00
Joe Groff
3d5285be6f Arrange for closure bodies promoted by AllocBoxToStack to have their originals removed by MoveOnlyChecker.
This is an improvement of #67031 which avoids deleting the closure function
body during AllocBoxToStack, which still breaks pass invariants by modifying
functions other than the currently-analyzed function. As a function pass,
AllocBoxToStack also doesn't really know with certainty whether the original
closure function is unused after stack promotion or not. We still want to
eliminate the original when it may contain invalid SIL for move-only values
that rely on the escape analysis for correct semantics, so rather than mark the
original function to be *ignored* during move-only checking, mark it to be
*deleted* by move-only checking if the function is in fact unused at that
point.

If the marked function is still used, we let it pass through move-only
checking normally, which may cause redundant diagnostics but is the right
thing to do since code is still potentially using the closure with escaping
semantics. We should rearrange things to make this situation impossible in
the future.

rdar://110675352
2023-07-10 15:18:16 -07:00
Michael Gottesman
07979f0f80 [move-only] Do not attempt to process mark_must_check if we detect they have a partial_apply that was identified by an earlier diagnostic as escaping.
Previously, we would emit a "compiler doesn't understand error" since we would
detect the escape and fail. That is the correct behavior here if the
partial_apply is not already identified as escaping by an earlier pass. But in
the case where we see that the partial_apply's callee was marked with
semantics::NO_MOVEONLY_DIAGNOSTICS, then we:

1. Suppress the "compiler doesn't understand error" for this specific
   mark_must_check.

2. Suppress function wide the "copy of noncopyable type" error. Since we stopped
   processing the mark_must_check that was passed to the partial_apply, we may
   have left copies of noncopyable types on that mark_must_check value. This is
   ok since the user will get the error, will recompile, and if any further show
   up after they fix the inout escaping issue, they will be emitted
   appropriately.
2023-05-14 14:57:56 -07:00
Michael Gottesman
b585a1870f [move-only] If we diagnose an invalid escaping capture, turn off noncopyable checking in the closure.
The reason why I am doing this is that currently SILGen knows when emitting said
closure that we are going to emit an error (that it does not have enough
information to emit itself since it doesn't know the caller), so doesn't emit
move checking markers. The result is that the move checker will not eliminate
any copies in the closure and thus will emit a "copy of noncopyable type found"
error and tell the user to file a bug. This just suppresses that.

rdar://108511866
2023-04-25 10:51:03 -07:00
Kavon Farvardin
12d33b2b84 run the move-checker if lexical borrow scopes are enabled
this pulls just the move checking passes out from
behind the experimental flag.
2023-03-13 22:39:31 -07:00
Michael Gottesman
1dd896ded9 [move-only] Implement escaping closure semantics.
NOTE: A few of the test patterns need to be made better, but this patch series
is large enough, I want to get it into tree and iterate.
2023-02-20 11:04:21 -08:00
Michael Gottesman
f4e1b2a8f2 [move-only] Update SILGen/MoveCheckers so that vars are emitted in eagerly projected box form.
This is the first slice of bringing up escaping closure support. The support is
based around introducing a new type of SILGen VarLoc: a VarLoc with a box and
without a value. Because the VarLoc only has a box, we have to in SILGen always
eagerly reproject out the address from the box. The reason why I am doing this
is that it makes it easy for the move checker to distinguish in between
different accesses to the box that we want to check separately. As such every
time that we open the box, we insert a mark_must_check
[assignable_but_not_consumable] on that project. If allocbox_to_stack manages to
determine that the box can be stack allocated, we eliminate all of the
mark_must_check and place a new mark_must_check [consumable_and_assignable] on
the alloc_stack.  The end result is that we get the old model that we had before
and also can support escaping closures.
2023-02-20 11:04:21 -08:00
Michael Gottesman
6c922af8aa [move-only] Combine the address/object checker in the same pass so that we only run cleanups once.
Otherwise, sometimes when the object checker emits a diagnostic and cleans up
the IR, some of the cleaned up copies are copies that should have been handled
by the address checker. The end result is that the address checker does not emit
diagnostics for that IR. I found this problem was exascerbated when writing code
for escaping closures.

This commit also cleans up the passes in preparation for at a future time moving
some of the transformations into the utils folder.
2023-02-19 13:55:22 -08:00
Michael Gottesman
e65601f592 Rename MoveOnlyChecker -> MoveOnlyObjectChecker.cpp. 2022-08-16 16:19:55 -07:00
Michael Gottesman
a14f36f72a [move-only] Ported rest of no implicit copy tests to move only and fixed resulting issues.
This is just to get code coverage. A few interesting things I noticed:

1. I am seeing a false diagnostic on this pattern:

let x = ...
var x2 = x
print(x2) // I get that print(x2) is a consuming use of x.

I think it is predictable mem opts maybe forwarding in an interesting way. I am
not sure. It doesn't happen with no implicit copy types since x2 would not be no
implicit copy so we would leave the no implicit copy monad.

2. I think that SILGen creates a real lexical scope for temporary variables
meaning that compiler generated code would actually hit the move checker. I had
to add an extra code pattern to handle this.
2022-07-26 17:04:09 -07:00
Michael Gottesman
5c95b7a7d1 [move-only] Remove borrow of subvalue error from the move checker.
The reason why we are doing this is that we are really accessing a getter on the
type. The error would be necessarily done inside the getter where any
consumption would happen. So it shouldn't be on the move only value itself.
2022-07-25 16:09:55 -07:00
Michael Gottesman
65c21b61bf [move-only] Begin implementing support for concrete move only types.
This is just the very beginning... I still need to implement more parts of
SILGen for this. But all great things start small. I am going to iterate on top
of this and just wanted to get some initial parts of the work in as I go.
2022-07-21 15:33:17 -07:00
Michael Gottesman
5b2fb3648f [no-implicit-copy] Add an option to turn off performing the copy of subvalue check.
Just adding this as something for @glessard to play with.
2022-07-20 14:40:23 -07:00
Michael Gottesman
f1182a73da [no-implicit-copy] Remove auto +1 param signature change called by noimplicit copy in favor of following normal convention.
I also added a bunch of tests for both the trivial/non-trivial case as well as
some docs to SIL.rst.
2022-07-19 16:39:03 -07:00
Michael Gottesman
d2a8cd195c [noimplicitcopy] Refactor out a helper method and add some docs.
NFC.
2022-06-30 22:37:20 -07:00
Michael Gottesman
79042f1cec [no-implicit-copy] Emit an error diagnostic if we find a mark_must_check [no_implicit_copy] we don't know how to check.
We do the same thing already with the move function. If someone is using this
functionality and the compiler fails, we don't want to succeed the compilation
since the user is relying on the compiler for safety!
2022-06-30 22:22:27 -07:00
Michael Gottesman
0d11e8ef69 [no-implicit-copy] Update SILGen/move checker to work with new patterns from copyable_to_moveonly and friends.
This involved doing the following:

1. Update the move only checker to look for new patterns.

2. Teach emitSemanticStore to use a moveonlywrapper_to_copyable to store moveonly
   values into memory. The various checkers will validate that this code is
   correct.

3. When emitting an apply, always unwrap move only variables. In the
   future, I am going to avoid this if a parameter is explicitly marked as also
   being moveonly (e.x.: @moveOnly parameter or @noEscape argument).

4. Convert from moveOnly -> copyable on return inst automatically in SILGen.

5. Fix SILGenLValue emission so we emit an error diagnostic later rather than
   crash. This is needed to keep SILGen emitting move only addresses (that is no
   implicit copy address only lets) in a form that the move only checker then
   will error upon. Without this change, SILGen crashes instead of emitting an
   error diagnostic in the following test:
   .//test/SILOptimizer/move_only_checker_addressonly_fail.swift
2022-06-21 16:47:58 -07:00
Andrew Trick
64ec981f3b Rename isDirectlyForwarding to preservesOwnership. 2022-04-12 22:23:17 -07:00
Michael Gottesman
8fd75eac3f [no-implicit-copy] Make sure to error on copies on borrowed structural sub-values.
Example: consume(x.field). This turned out to be a pretty simple extension of
the underlying model. The cases we are interested in are caused by a
non-reference nominal type having an extracted field being passed to a consuming
use. This always requires a copy.

The reason I missed this was I originally wrote the test cases around this for
classes which do not have this problem since the class is move only, not the
field due to class being a reference type. I then cargo culted this test case
for struct/other types and did not notice that we should have started to error
on these tests.

On an interesting note, I caught this on my branch where I am preparing the
optimizer to allow for values to have a move only bit. One of the constraints is
that once we are in guaranteed SIL, copy_value can not be used on any moveOnly
type (e.x.: $@moveOnly T). To ensure this doesn't happen, the move only checker:

1. Uses copy propagation to rewrite the copies of the base owned value.

2. Emit a diagnostic error upon any copies we found were needed due to the owned
   value being consumed.

3. If a diagnostic was emitted, rewrite all copies of move only typed values to
   be explicit_copy_value to ensure that in canonical SIL we do not violate the
   invariant that copy_value can not be applied to move only type values. This
   is ok to do since we are going to error and just want to avoid breaking the
   invariant.

The end effect of this is that if we do not emit any diagnostic, any copy_value
on a move only typed value that is not eliminated by the checker hits an assert
in the verifier... allowing us to know that if a program successfully compiles
that all "move only" proofs successfully ran, guaranteeing safety!
2022-01-29 21:29:28 -08:00
Michael Gottesman
68d37e142b [no-implicit-copy] Add a new instruction called MarkMustCheckInst and use it in the move checker.
This is an instruction that I am going to use to drive some of the ownership
based dataflow optimizations that I am writing now. The instruction contains a
kind that allows one to know what type of checking is required and allows the
need to add a bunch of independent instructions for independent checkers. Each
checker is responsible for removing all of its own mark instructions. NOTE:
MarkMustCheckInst is only allowed in Raw SIL since once we are in Canonical SIL
we want to ensure that all such checking has already occurred.
2022-01-29 14:49:39 -08:00
Michael Gottesman
e5d0f386e4 [moveOnly] Add a new experimental move only checker that checks noImplicitCopy variables.
NOTE: This is only available when the flag -enable-experimental-move-only. There
are no effects when the flag is disabled.

The way that this works is that it takes advantage of the following changes to
SILGen emission:

* When SILGen initializes a let with NoImplicitCopyAttribute, SILGen now emits
a begin_borrow [lexical] + copy + move_only. This is a pattern that we can check
and know that we are processing a move only value. When performing move
checking, we check move_only as a move only value and that it isn't consumed
multiple times.

* The first point works well for emitting all diagnostics except for
initializing an additional let var. To work around that I changed let
initialization to always bind to an owned value to a move of that owned
value. There is no semantic difference since that value is going to be consumed
by the binding operation anyways so we effectively just move the cleanup from
the original value we wanted to bind to the move. We still then actually borrow
the new let value with a begin_borrow [lexical] for the new let value. This
ensures that an initialization of a let value appears to be a consuming use to
the move only value checker while ensuring that the value has a proper
begin_borrow [lexical].

Some notes on functionality:

1. This attribute can only be applied to local 'let'.

2. "print" due to how we call it today with a vararg array is treated as a
   consuming use (unfortunately).

3. I have not added the builtin copy operator yet, but I recently added a _move
   skeleton attribute so one can end the lifetimes of these values early.

4. This supports all types that are not address only types (similar to
   _move). To support full on address only types we need opaque values.

rdar://83957088
2021-10-28 11:32:22 -07:00