Commit Graph

182 Commits

Author SHA1 Message Date
Michael Gottesman
c9be4bda49 Merge pull request #67677 from gottesmm/borrowed-base-silgenlvalue
[move-only] Ensure that we properly nest accesses to base values if the base is noncopyable or the accessor result is noncopyable.
2023-08-04 12:26:19 -07:00
Michael Gottesman
c3d2276241 [silgen] Eliminate two more cases around subscripts where we were not borrowing.
Also, the store_borrow work in the previous patch caused some additional issues
to crop up. I fixed them in this PR and added some tests in the process.
2023-08-02 11:09:31 -07:00
swift-ci
2919af9fa7 Merge remote-tracking branch 'origin/main' into rebranch 2023-08-01 13:36:46 -07:00
Joe Groff
9b783560ad Fix @_rawLayout initialization to avoid spurious lifetime ends.
We can't really treat them as always-initialized because that makes move checking
think that there's a value to destroy even on initialization, causing deinits to
run on uninitialized memory. Remove my previous hack, and use a `zeroInitializer`
to initialize the value state when emitting `init`, which is where we really need
the bootstrapping-into-initialized behavior. rdar://113057256
2023-08-01 08:34:02 -07:00
Michael Gottesman
55892ef30d [silgen] Add a special visitor for accessing the base of noncopyable types.
We want these to be borrowed in most cases and to create an appropriate onion
wrapping. Since we are doing this in more cases now, we fix a bunch of cases
where we used to be forced to insert a copy since a coroutine or access would
end too early.
2023-07-27 10:00:28 -07:00
swift-ci
1969199a8e Merge remote-tracking branch 'origin/main' into rebranch 2023-07-26 23:13:08 -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
aee071bf4e Introduce an experimental @_rawLayout attribute.
This attribute can be attached to a noncopyable struct to specify that its
storage is raw, meaning the type definition is (with some limitations)
able to do as it pleases with the storage. This provides a basis for
implementing types for things like atomics, locks, and data structures
that use inline storage to store conditionally-initialized values.
The example in `test/Prototypes/UnfairLock.swift` demonstrates the use
of a raw layout type to wrap Darwin's `os_unfair_lock` APIs, allowing
a lock value to be stored inside of classes or other types without
needing a separate allocation, and using the borrow model to enforce
safe access to lock-guarded storage.
2023-07-24 14:28:19 -07:00
Michael Gottesman
7aea9d44c3 Merge pull request #67414 from gottesmm/rdar112555589-112547982
[move-only] Fix two small errors around handling capturing of noncopyable self by local functions
2023-07-19 21:28:09 -07:00
Michael Gottesman
b060e5ba60 [move-only] Make sure we mark local function inout parameters with mark_must_check.
Originally, we were relying on capture info to determine if we needed to insert
this mark_must_check. This ignored that the way that we are handling
escaping/non-escaping is something that is approximated in the AST but actually
determined at SIL level. With that in mind, rather than relying on the capture
info here, just rely on us having an inout argument. The later SIL level
checking for inout escapes is able to handle mark_must_check and knows how to
turn off noncopyable errors in the closure where we detect the error to prevent
us from emitting further errors due to the mark_must_check here.

I discovered this while playing with the previous commit.

rdar://112555589
2023-07-19 15:02:04 -07:00
Michael Gottesman
2abfa25bd4 Merge pull request #67354 from gottesmm/pr-45bdcac91308a0aa164064d4356f91a367ea00fa
[move-only] Fix lazily initialized global initializers.
2023-07-18 16:38:36 -07:00
Michael Gottesman
1f22f92170 [move-only] Fix lazily initialized global initializers.
Without this, we emit a copy of noncopyable type error since we do not insert a
mark_must_check on lazily initialized global initializers.

rdar://111402912
2023-07-17 19:17:43 -07:00
Michael Gottesman
d7d7ab6ae2 [move-only] Make sure that we mask out liveness bits and use |= when merging successors
Both of these can cause us to insert destroy_addr in the wrong locations.

1. The first causes us to insert destroys for parts of values that are not
actually on the boundary since we didn't use our mask and instead used all of
the liveness information.

2. We were merging successor information using '&=' instead of '|=. This caused
a problem if we had multiple regions for the same successor. In such a case, we
would not have anything in common for the regions causing us to not have any
bits in common, resulting in us inserting too many destroy_addr instead of
skipping as we were supposed to.

rdar://112434492
2023-07-17 16:10:43 -07:00
Michael Gottesman
69a03c93f9 [move-only] Ban partial reinitialization after consuming a value.
This is similar to our ban on partial consuming a value for this release. The
reason for this is that, one can achieve a similar affect as partial consumption
via a consumption of the entire value and then a partial reinitialization. Example:

```swift
struct X : ~Copyable { var i = 5, var i2 = Klass() }
var x = X()
_ = consume x
x.i = 5
```

in the case above, we now have a value that is in a partially initialized state.

We still allow for move only types to have their fields initialized as long as
there is an intervening init.

rdar://111498740
2023-07-05 20:26:26 -07:00
Michael Gottesman
7e582b0221 [move-only] Split error emission code from testing code. 2023-07-05 18:41:27 -07:00
Michael Gottesman
7028381fe1 [move-only] When adding implicit liveness uses for class field/global accesses, do not use the terminator, use the end access.
Previously, when doing this I could just use the terminator both in cases of
inout and for class field/global accesses... but after some recent changes to
field sensitive pruned liveness, this seems to no longer work. So just do the
right thing and use the field access.

The specific bug was that we would introduce a destroy_addr along one of the
paths where the value wasn't defined resulting in a dominance error.

I added a SIL test that shows this fixes the issue, a swift test, and also an
Interpreter test that validates the correctness.

rdar://111659649
2023-07-03 15:53:51 -07:00
Michael Gottesman
fb487bf0ef [move-only] Improve logging to make it more readable and add a counter to bisect on variables that we are checking.
These are only on in NDEBUG mode. It just makes it easier to quickly triage
which variable is causing a checking problem.
2023-07-03 15:49:41 -07:00
Michael Gottesman
4591e39d02 [move-only] Fix borrowing address only no consume diagnostic to not say can't capture.
We previously were emitting a consuming partial_apply diagnostic. I had to
reformulate slightly the way we pattern match the diagnostics to make sure that
we get the proper no consume diagnostic.

rdar://111461837
2023-06-28 11:20:27 -07:00
Michael Gottesman
bd90e310e1 Merge pull request #66952 from gottesmm/pr-87fcc78991b465d8a15454dc76b66d6f347ddff0
[move-only] Emit an error if we /ever/ partially consume a noncopyable type.
2023-06-28 01:00:40 -07:00
Michael Gottesman
3dde9df468 [move-only] Emit an error if we /ever/ partially consume a noncopyable type.
The reason why I am doing this is that this was not part of the original
evolution proposal (it was called an extension) and after some discussion it was
realized that partial consumption would benefit from discussion on the forums.

rdar://111353459
2023-06-27 13:52:49 -07:00
Michael Gottesman
170ba67bd3 [move-only] Eliminate some temporary copies inserted by SILGen when accessing fields of lets.
In the next commit, I am modifying the move only checker to ensure that we
always error when partially invalidating. While doing this I discovered that
these copies were getting in the way of emitting good diagnostics in that case.
2023-06-27 13:41:31 -07:00
Nate Chandler
d00da4a0c1 [MoveOnlyAddressChecker] Fix repr for initInsts.
The address checker records instructions that initialize fields in its
initInsts map.  Previously, that map mapped from an instruction to a
range of fields of the type.  But an instruction can initialize multiple
discontiguous fields of a single value.  (Indeed an attempt to add a
second range that was initialized by an already initializing
instruction--even if it were overlapping or adjacent--would have no
effect and the map wouldn't be updated.)  Here, this is fixed by fixing
the representation and updating the storage whenver a new range is seen
to be initialized by the instruction.  As in
https://github.com/apple/swift/pull/66728 , a SmallBitVector is the
representation chosen.

rdar://111391893
2023-06-27 12:10:52 -07:00
Nate Chandler
f7f5802664 [MoveOnlyAddressChecker] NFC: Extracted helpers.
In preparation for having a third instance getting or creating the bits
affected by an instruction, introduce a typealias for maps
SILInstruction->SmallBitVector and a helper function that returns
a reference to the SmallBitVector for an instruction and two others that
set into those bits the bits from another bit vector or from a range.
2023-06-27 12:10:52 -07:00
Nate Chandler
4a5009a612 [MoveOnlyAddressChecker] Fix repr for reinits.
The address checker records instructions that reinit fields in its
reinitInsts map.  Previously, that map mapped from an instruction to a
range of fields of the type.  But an instruction can use multiple
discontiguous fields of a single value.  (Indeed an attempt to add a
second range that was reinit'd by an already reinit'ing
instruction--even if it were overlapping or adjacent--would have no
effect and the map wouldn't be updated.)  Here, this is fixed by fixing
the representation and updating the storage whenver a new range is seen
to be reinit'd by the instruction.  As in
https://github.com/apple/swift/pull/66728 , a SmallBitVector is the
representation chosen.

rdar://111356251
2023-06-27 12:10:52 -07:00
Nate Chandler
50798ff67e [MoveOnlyAddressChecker] NFC: Extracted function.
In preparation to share the getOrCreateConsumingBlock functionality with
another overload of recordConsumingBlock.
2023-06-27 11:24:47 -07:00
Nate Chandler
eb698970dd [MoveOnlyAddressChecker] NFC: Used helper.
Used the TypeTreeLeafTypeRange::setBits helper rather than looping over
the range and setting the bits in place.
2023-06-27 11:24:47 -07:00
Evan Wilde
f3ff561c6f [NFC] add llvm namespace to Optional and None
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
                     bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".

I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
2023-06-27 09:03:52 -07:00
nate-chandler
98d895db52 Merge pull request #66892 from nate-chandler/rdar111221183
[MoveOnlyAddressChecker] Fixed two use-before-def handlings.
2023-06-23 19:13:56 -07:00
Nate Chandler
ff7aa3c99a [LifetimeExtension] Fixed reinit collection.
During initializeLiveness, all blocks which contain destroys are to be
recorded in consuming blocks.  Previously, however, certain reinits were
not being added.  Here, all reinits are correctly added.
2023-06-23 12:50:05 -07:00
Nate Chandler
8eff2e8299 [LifetimeExtension] Handle use-before-def.
The multi-def algorithm is based off the single-def algorithm.  However,
it differs from it in needing to handle "liveness holes"--uses before defs.

When identifying blocks which are originally live, the algorithm starts
from consuming blocks and walks backwards until a condition is met.

Previously, that condition was finding blocks which were originally
live.  That makes sense in the single-def case: if a block is originally
live, either it was already walked through or else it was one of the
blocks discovered by liveness.  In either case, its predecessors have
already been visited if appropriate.

However, in the multi-def case, this condition is too stringent.  It
fails to account for the possibility of a block with has a "liveness
hole".  Only stop the backwards walk if the predecessor not only (1) was
in originally live but additionally (2) "kills liveness"--doesn't have a
use before a def.

rdar://111221183
2023-06-23 12:50:04 -07:00
Michael Gottesman
b8a4132af7 Merge pull request #66783 from gottesmm/pr-9c93f4322f46013f6053b162d35adfe4b4252b8f
[move-only] Remove use after move in CopiedLoadBorrowEliminationVisitor.
2023-06-21 10:53:55 -07:00
Joe Groff
282a9a7364 Merge pull request #66792 from jckarter/nonescaping-closure-conversion-moveonly-checker
MoveOnlyChecker: Look through `convert_function` of nonescaping closures.
2023-06-21 09:36:33 -07:00
Joe Groff
26d8d84270 Merge pull request #66651 from jckarter/noncopyable-address-only-borrowed-capture
ClosureLifetimeFixup: Remove copy of borrowed move-only nonescaping captures when possible.
2023-06-21 09:36:18 -07:00
Joe Groff
8f30a0097a MoveOnlyChecker: Look through convert_function of nonescaping closures.
Like a nested partial_apply reabstraction, but without the thunk, these change
the representation of the function but can't escape it without breaking the
nonescaping closure promotion. rdar://111060678
2023-06-20 18:20:45 -07:00
Michael Gottesman
b4092c4572 [move-only] Remove use after move in CopiedLoadBorrowEliminationVisitor.
Specifically, we were calling process on a visitor that was already moved. To
fix this I created a separate state structure that the visitor initializes and
moved the post-processing step onto the state data structure.

This seems to not be causing any problems today, but could in the future.

rdar://111060475
2023-06-20 13:36:10 -07:00
Joe Groff
ed2cbca04f ClosureLifetimeFixup: Remove copy of borrowed move-only nonescaping captures when possible.
SILGen introduces a copy of the capture, because the semantics of escaping partial_apply's
requires the closure to take ownership of the parameters. We don't know when a closure is
strictly nonescaping or its final lifetime until ClosureLifetimeFixup runs, but that replaces
the consume of the copy with a borrow of the copy normally, hoping later passes fix it up.
We can't wait that long for move-only types, which can't be copied, so try to remove the
copy up front when the copy lives long enough and has no interfering uses other than the
partial_apply. rdar://110137169
2023-06-20 12:10:31 -07:00
Andrew Trick
a8c45c55c4 Fix MoveOnlyAddressChecker to handle value deinits.
Track liveness of self so we don't accidentally think that such types
can be memberwise reinitialized.

Fixes rdar://110232973 ([move-only] Checker should distinguish in
between field of single field struct vs parent field itself (was:
mutation of field in noncopyable struct should not trigger deinit))
2023-06-19 18:38:03 -07:00
Nate Chandler
66867c02d1 [MoveOnlyAddressChecker] Fix used fields repr.
The address checker records uses in its livenessUses map.  Previously,
that map mapped from an instruction to a range of fields of the type.
But an instruction can use multiple discontiguous fields of a single
value.  Here, such instructions are properly recorded by fixing the map
to store a bit vector for each instruction.

rdar://110676577
2023-06-17 16:04:43 -07:00
Nate Chandler
2bfa723951 [MoveOnlyAddressChecker] Added extension flag.
Passing

```
-Xllvm -move-only-address-checker-disable-lifetime-extension=true
```

will skip the maximization of unconsumed field lifetimes.
2023-06-16 21:13:10 -07:00
Nate Chandler
eaf4560cd7 [MoveOnlyAddressChecker] Maximize lifetimes.
Previously, the checker inserted destroys after each last use.  Here,
extend the lifetimes of fields as far as possible within their original
(unchecked) limits.

rdar://99681073
2023-06-16 21:13:09 -07:00
Nate Chandler
b97712c422 [MoveOnlyAddressChecker] NFC: Promoted assertion.
Dumped more info and called llvm_unreachable on bad state.
2023-06-16 21:13:09 -07:00
Nate Chandler
f4e3292a2f [FieldSensitivePL] Fix vectorization.
FieldSensitivePrunedLiveness is used as a vectorization of
PrunedLiveness.  An instance of FSPL with N elements needs to be able to
represent the same states as N instances of PL.

Previously, it failed to do that in two significant ways:

(1) It attempted to save space for which elements were live by using
    a range.  This failed to account for instructions which are users of
    non-contiguous fields of an aggregate.

    apply(
      @owned (struct_element_addr %s, #S.f1),
      @owned (struct_element_addr %s, #S.f3)
    )

(2) It used a single bit to represent whether the instruction was
    consuming.  This failed to account for instructions which consumed
    some fields and borrowed others.

    apply(
      @owned (struct_element_addr %s, #S.f1),
      @guaranteed (struct_element_addr %s, #S.f2)
    )

The fix for (1) is to use a bit vector to represent which elements
are used by the instruction.  The fix for (2) is to use a second bit
vector to represent which elements are _consumed_ by the instruction.

Adapted the move-checker to use the new representation.

rdar://110909290
2023-06-16 21:13:07 -07:00
Michael Gottesman
59c8cff917 [borrowing] Add support for borrowing/consuming copyable types to be a noimplicitcopy type.
rdar://108383660
2023-06-06 18:12:29 -04:00
Kavon Farvardin
bd253c602f prevent reinitialization of self after discard
The value `self` is mutable (i.e., var-bound) in
a `consuming` method. Since you're allowed to
reinitialize a var after consuming, that means
you were also naturally allowed to reinitialize
self after `discard self`. But that capability was
not intended; after you discard self you shouldn't
be reinitializing it, as that's probably a mistake.

This change makes reinitialization of `self`
reachable from a `discard self` statement an error.

rdar://106098163
2023-06-05 19:25:50 -07:00
Kavon Farvardin
88d35a00b3 emit error on implicit destruction of self in discard context
As part of SE-390, you're required to write either:

  - `consume self`
  - pass self as a `consuming` parameter to a function
  - `discard self`

before the function ends in a context that contains a
`discard self` somewhere. This prevents people from accidentally
invoking the deinit due to implicit destruction of `self` before
exiting the function.

rdar://106099027
2023-06-04 18:45:22 -07:00
Michael Gottesman
c9edaee18c [move-only] Make sure that we handle load [take] that are actually borrows correctly.
Before the previous commit, we didn't see load [take] very often since it occurs
mostly on temporaries where we treat the copy_addr as the relevant take. Now
that we are checking temporaries though, we need to support this behavior.
2023-05-26 12:01:37 -07:00
Joe Groff
9db359985d Emit updated debug info when inout parameters are consumed and reinitialized.
Change SILGen to emit the `debug_value` instruction using the original inout
parameter address, instead of the `mark_must_check` inserted for move-only
parameters, because code in the MoveOnlyAddressChecker did not expect to
find the debug_value anywhere but on the original address. Update move-only
diagnostics so that they pick up the declaration name for a memory location
from any debug_value instruction if there are more than one. rdar://109740281
2023-05-24 12:15:53 -07:00
Michael Gottesman
ec28aa4949 [move-only] Ban destructuring of noncopyable address only types like we do for loadable types.
rdar://109686285
2023-05-23 16:26:16 -07:00
Joe Groff
31032b9cae Merge pull request #65992 from jckarter/debug-info-for-move-only-reinitialization
MoveOnlyAddressChecker: Reintroduce debug info for variables after reassignment.
2023-05-19 09:51:42 -07:00
Joe Groff
51f75c99a4 MoveOnlyAddressChecker: Reintroduce debug info for variables after reassignment.
After a value is consumed, we emit a `debug_value undef` to indicate that the
variable value is no longer valid to the debugger. However, once a value is
reassigned, it becomes valid again, so emit a `debug_value %original_address` to
reassociate the variable with the valid memory location. rdar://109218404
2023-05-18 15:08:59 -07:00