Commit Graph

198 Commits

Author SHA1 Message Date
Meghana Gupta ebd4d11225 Merge pull request #88847 from meg-gupta/fixeaborrow
Update SIL utilities for address results from borrow accessors
2026-05-07 20:57:06 -07:00
Ben Cohen 5b411a0afe MoveOnlyChecker: relax partial-consume assertion for restricted imports (#88829)
`shouldEmitPartialMutationErrorForType` asserted that a nominal type
reaching its cross-module-use branch had formal access scope
public-or-package from the calling function's DeclContext:

    assert(nominal
               ->getFormalAccessScope(fn->getDeclContext(),
/*treatUsableFromInlineAsPublic=*/true)
               .isPublicOrPackage());

That check was correct when added (in `da968dbd58d`, "Ban exported
partial consumption"), but breaks whenever a public type from another
module is imported with restricted access. Two cases trip it:

- `internal import Library` (the assertion fires with no feature flags
at all)
- `-enable-upcoming-feature InternalImportsByDefault`, which is the
originally-reported manifestation

In both cases a partial consume of a `@frozen public ~Copyable` field
hits the assertion. The downstream logic
(`hasExplicitFixedLayoutAnnotation` → allow/reject) doesn't depend on
the scope value — the assertion is purely informational. Replace the
over-strict check with a comment explaining the invariant (the type is
visible from `fn`'s DC; access scope may be `Internal` when the client's
import is internal).

Adds
`test/SILOptimizer/moveonly_addresschecker_diagnostics_partial_consume_internal_imports.swift`
which uses a plain `internal import Library` (no feature flags) and
covers both the `@frozen` (compiles cleanly) and non-`@frozen`
(diagnosed as `cannot partially consume ... of non-frozen type ...
imported from 'Library'`) cases. Verified by reverting the relaxation:
the test triggers exactly the original assertion at
MoveOnlyAddressCheckerUtils.cpp:1829.
2026-05-07 05:52:27 -07:00
Meghana Gupta 2868f0bcc1 Update MoveOnlyChecker to handle applies with address results as endpoint uses
Address results from borrow accessors should be treated as endpoint uses
in the move-only checker. The result address has its own mark_unresolved_non_copyable_value
that gets checked separately.
2026-05-05 16:26:08 -07:00
Ben Cohen c48175f63e MoveOnlyChecker: recognize stacked mark_unresolved_non_copyable_value as initialized (#88800)
**Explanation**: Fix a `MoveOnlyChecker` assertion crash on noncopyable
`let`s that have two stacked `mark_unresolved_non_copyable_value`
instructions on the same `alloc_stack` — one gating the init store,
another gating reads.
**Scope**: Defensive fix in the move-only checker. Converts a
user-visible assertion crash into a clean compile. No effect on code
that wasn't already hitting the assertion.
**Risk**: Very low. Single narrow condition added to an existing method;
existing behavior preserved for all other patterns. No SIL output
changes for any test that was previously compiling.
**Testing**: New `.sil` regression test with two variants covering both
admitted outer-mark check kinds, plus existing SILGen and SILOptimizer
tests.

`MoveOnlyAddressCheckerPImpl::addressBeginsInitialized` decides whether
a marked address arrives already-initialized; if not, the use-walk needs
to find an init `store`, and `finishedInitializationOfDefs` later
asserts at least one def was recorded. None of the existing special
cases recognized a `MarkUnresolvedNonCopyableValueInst` whose operand is
itself a `MarkUnresolvedNonCopyableValueInst`. SILGen emits stacked
marks when an outer mark (`[consumable_and_assignable]` or
`[initable_but_not_consumable]`) gates an init store and an inner
`[no_consume_or_assign]` mark layered on top gates the binding's reads.
The inner mark fell through every branch, returned `false`, no
`initializeDef` was ever called, and `finishedInitializationOfDefs`
asserted `(isInitialized())`. This PR adds a branch that treats the
inner mark as beginning-initialized when its operand is an outer mark
whose check kind permits init (`ConsumableAndAssignable` or
`InitableButNotConsumable`); other check kinds fall through to existing
heuristics unchanged.
2026-05-05 05:48:47 -07:00
Ben Cohen f0a8437191 MoveOnlyChecker: look through convert_function when closing an on-stack partial_apply's borrow scope (#88805)
- **Explanation**: Defensive prep for an upcoming SILGen change. Teaches
`CopiedLoadBorrowEliminationVisitor` to recognize a noncopyable
`load_borrow` → on-stack `partial_apply` → `convert_function` →
`destroy_value` chain, instead of hitting `llvm_unreachable("We should
never hit this")`
- **Scope**: Narrow change to one case of one visitor in the move-only
checker. The crash isn't reachable from vanilla Swift source on current
`main` — no code path produces the triggering SIL shape today. Lands
ahead of a SILGen change that will route noncopyable `let` captures into
non-escaping closures through on-stack `partial_apply`, at which point a
`@MainActor`-isolated noescape async closure body introduces the
intervening `convert_function` (stripping `@Sendable`) that this fix
accommodates.

- **Risk**: Very low. The edit is scoped to the
`ForwardingConsume`/`DestroyingConsume` arm of a single `switch` in
`MoveOnlyAddressCheckerUtils.cpp::CopiedLoadBorrowEliminationVisitor::visitUse`.
The original invariant (only `destroy_value` users accepted) is
preserved by an explicit user-type check, but broadened to include
`convert_function` chains back to the on-stack `partial_apply`. Both
`llvm_unreachable`s still fire for anything outside the expected shape.
The broadened path only fires on a SIL shape that current SILGen doesn't
produce, so in principle no existing test should exercise it — this is a
defensive-preparation change whose behavioral effect is required for an
upcoming SILGen PR.

- **Testing**: New `.sil` regression test at
`test/SILOptimizer/moveonly_addresschecker_convert_function_onstack.sil`
with two variants (single `convert_function` between PA and destroy;
chained pair). Verified by reverting the fix — the
single-`convert_function` variant triggers exactly the
`llvm_unreachable` it's designed to catch.

`CopiedLoadBorrowEliminationVisitor` walks forward from a noncopyable
`load_borrow`, tracking uses via `OperandOwnership`. An on-stack
`partial_apply` sees its `load_borrow` operand as
`OperandOwnership::Borrow`; the `Borrow` case then walks the PA's
results. Those PA-result uses can have
`OperandOwnership::ForwardingConsume`/`DestroyingConsume` (on-stack PA
has `OwnershipKind::Owned` in OSSA, and `convert_function` forwards that
ownership). The existing special case only recognized a direct
`destroy_value` of the PA and fired `llvm_unreachable` on any
intermediary.

The fix keeps the original syntactic invariant — the user must be a
`destroy_value` or a `convert_function` — and broadens the operand check
to walk backward through a `convert_function` chain to find the
underlying `PartialApplyInst`. If it's on-stack, the consuming use
closes the borrow scope rather than consuming the captured noncopyable.
When the use is itself a `convert_function` (forwarding consume rather
than terminating), its uses are pushed onto the worklist so the
downstream `destroy_value`/`apply` is visited with the right context.

Mirrors the existing look-through-`convert_function` treatment in the
forwarding traversal earlier in this file. Deliberately does not
generalize to other forwarding owners (e.g., `move_value`,
`mark_dependence`, `convert_escape_to_noescape`) since they are not
produced by SILGen between an on-stack PA and its destroy today.
2026-05-05 05:48:29 -07:00
Joe Groff 097b0d3400 SIL: Split unchecked_*_enum_data_addr according to ownership and effects.
We cannot use spare bits or other overlapping storage layout tricks with fundamentally
address-only enums, and we can take advantage of this to do borrowing switches or other
in-place projections without copying the value. However, for resilient enums, the
implementation may use spare bit packing, but the type must be handled address-only
outside of its defining module, and we didn't have a way to express that with
borrowing switch. Optimization passes have also been running into problems with the
complexity that we were using `unchecked_take_enum_data_addr` sometimes as a pure
operation. This patch splits the instruction into three:

- `unchecked_inplace_enum_data_addr` represents a nondestructive in-place enum
  projection. It is only allowed for enums whose projection operation is
  nondestructive.
- `unchecked_take_enum_data_addr` represents a destructive enum projection,
  invalidating the enum and leaving the payload to be further consumed.
  This matches the current instruction's semantics.
- `unchecked_borrow_enum_data_addr` represents a borrowing enum projection.
  The instruction takes a second operand for "scratch" space, which the
  enum representation may be copied into in order to avoid invalidating the
  enum value, so the result is dependent on the lifetime of both the
  original enum and the scratch buffer. This allows for borrowing switches
  over resilient enums.

`unchecked_borrow_enum_data_addr` is implemented by taking advantage of the
"address-only enums can't do spare bit optimization" property at runtime.
We inspect the operand type's bitwise-borrowability from its metadata. If
the type is bitwise-borrowable, then we are allowed to bitwise-copy the
enum to the scratch space and apply the projection to the scratch space,
preserving the original value. If the type is not bitwise-borrowable, then
we cannot use spare bit optimization in its layout, so we apply the
projection in-place.

Fixes rdar://174952822.
2026-04-27 15:40:37 -07:00
Joe Groff 5d95daae39 Remove unused variable 2026-01-26 12:28:49 -08:00
Alejandro Alonso 632d6f4257 WIP: Dependent borrow layout 2026-01-23 08:02:10 -08:00
Joe Groff ed230a5198 Handle Builtin.Borrow instructions in more SIL switches. 2026-01-23 08:02:09 -08:00
Meghana Gupta b467c5ec3c [NFC] Remove unused DominanceInfo from OSSACompleteLifetime and InteriorLiveness 2025-12-17 13:30:06 -08:00
Meghana Gupta ff486b742e Update MoveOnlyAddressCheckerUtils for mutate accessors 2025-11-06 10:55:44 -08:00
Meghana Gupta 0bd6825aa2 Update SIL utilities for borrow and mutate accessors under opaque values mode 2025-10-20 09:05:38 -07:00
Meghana Gupta d54044c231 Update MoveOnlyObjectChecker for borrow accessors 2025-10-02 07:18:24 -07:00
Meghana Gupta a42511e041 [NFC] Replace ApplyInst::getSubstCalleeConv()::hasGuaranteedAddressResult() with ApplyInst::hasGuaranteedAddressResult() 2025-09-14 23:38:07 -07:00
Meghana Gupta 6665cd5d46 [NFC] hasGuaranteedAddressResults -> hasGuaranteedAddressResult and hasGuaranteedResults -> hasGuaranteedResult 2025-09-14 23:38:06 -07:00
Meghana Gupta 9e4fa8f508 Updates to MoveOnlyChecker 2025-09-09 14:45:45 -07:00
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
Meghana Gupta 35d62a4a36 Introduce end_cow_mutation_addr instruction 2025-04-30 13:39:45 -07:00
nate-chandler e4d3207b40 Revert "MoveOnlyChecker: Treat trivial stores as reinitializations rather than initializations." 2025-04-24 12:10:07 -07:00
Nate Chandler 4786bede68 [MoveOnly] Fix consumption of opened existentials.
Enable walking into `TypeOffsetSizePair`s from an existential into an
archetype.  And set the access kind on `open_existential_addr`
instructions which are the sources of rewritten `copy_addr`s to mutable.

rdar://141279635
2025-04-22 17:59:37 -07:00
Nate Chandler 6669b2497d [NFC] MoveOnly: Add parameter to function.
For now, it is unused.
2025-04-22 17:59:37 -07:00
Joe Groff a1ff2e38dc MoveOnlyChecker: Treat trivial stores as reinitializations rather than initializations.
A trivial store is allowed to occur on an existing live value, and should not
trigger an attempt to destroy the original value completely. Fixes rdar://147791932.
2025-04-15 13:40:22 -07:00
Michael Gottesman 3ff9463957 Make Feature a struct enum so we can put methods on it.
Just noticed this as I was looking at making other changes.
2025-04-05 10:08:29 +01:00
Joe Groff b5d242ad2c MoveOnlyChecker: Don't follow trivial transitive uses of borrows.
Trivial values don't have ownership tracked, so their uses can't affect the
lifetime of the original borrow. Fixes rdar://148457155.
2025-04-02 13:25:46 -07:00
Andrew Trick 19c8bd625f Add FIXMEs for calls to liveness that fail to check pointer escapes. 2025-03-02 23:51:34 -08:00
Saleem Abdulrasool 4097255ea5 SILOptimizer: address C5030
i```
swift\lib\SILOptimizer\Mandatory\MoveOnlyAddressCheckerUtils.cpp(2981): warning C5030: attribute [[clang::fallthrough]] is not recognized
```

Replace the use of `clang::fallthrough` with `LLVM_FALLTHROUGH` which
properly uses the C++ standard spelling (`[[fallthrough]]`) depending on
the compiler version.
2025-02-07 15:04:38 -08:00
Andrew Trick e705a6d7c3 Temporarily introduce AnyInteriorPointer operand ownership.
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.
2025-02-05 16:23:02 -08:00
Anthony Latsis a84dfc8387 [Gardening] Fix some set but not used variables 2025-01-30 21:34:38 +00:00
Gabor Horvath 1601564342 [cxx-interop] Import rvalue references as consuming parameters
Unfortunately, importing them as is results in ambiguous call sites.
E.g., std::vector::push_back has overloads for lvalue reference and
rvalue reference and we have no way to distinguish them at the call site
in Swift. To overcome this issue, functions with rvalue reference
parameters are imported with 'consuming:' argument labels.

Note that, in general, move only types and consuming is not properly
supported in Swift yet. We do not invoke the dtor for the moved-from
objects. This is a preexisting problem that can be observed with move
only types before this PR, so the fix will be done in a separate PR.
Fortunately, for most types, the moved-from objects do not require
additional cleanups.

rdar://125816354
2024-12-02 13:09:21 +00:00
Andrew Trick 4612728581 [NFC] Add BeginApplyInst::getEndApplyUses() API.
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.
2024-11-18 01:37:00 -08:00
Andrew Trick 17a3b8a8a3 [MoveAddrChecker] load from borrowed value looks through mark_depend
Required to add dependencies to unsafe addressors.
2024-10-22 09:27:02 -07:00
Nate Chandler 9c887a1ab1 [MoveAddrChecker] Init'd looks thru mark_depend.
Extend the hack to determine whether an address begins initialized to
look through mark_dependence instructions.
2024-10-21 09:50:02 -07:00
Nate Chandler 0b47442068 [NFC] MoveAddrChecker: Extract reused expression.
To enable changing its definition.
2024-10-21 09:49:59 -07:00
Nate Chandler 062d063764 [NFC] MoveAddrChecker: Extracted function.
While the FIXME to derive whether an address begins initialized requires
auditing all sites where the instruction is emitted to begin with,
making this a predicate that depends only on the instruction can be done
now.
2024-10-21 09:49:38 -07:00
Joe Groff de687db20f Disallow consuming self in a noncopyable deinit again.
The changes to allow for partial consumption unintentionally also allowed for
`self` to be consumed as a whole during `deinit`, which we don't yet want to
allow because it could lead to accidental "resurrection" and/or accidental
infinite recursion if the consuming method lets `deinit` be implicitly run
again. This makes it an error again. The experimental feature
`ConsumeSelfInDeinit` will allow it for test coverage or experimentation
purposes. rdar://132761460
2024-07-29 21:20:14 -07:00
Nate Chandler 042241af55 [NFC] MoveOnlyAddressChecker: Use isWithinBoundary
Switch back to the API meant for a single instruction now that it
properly handles dead-end regions.
2024-07-23 13:38:35 -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 3eb288f92e [MoveOnlyAddressChecker] Exclusivity handles DEs.
Switch to the areUsesWithinBoundary API which takes dead-ends into
account.

rdar://131960619
2024-07-22 14:03:49 -07:00
Nate Chandler dd730b849c [LifetimeCompletion] Flag instructions dead_end. 2024-07-03 16:44:35 -07:00
Nate Chandler 91fe12aab4 [NFC] SIL: Typed debug_value.poisonRefs. 2024-07-03 14:53:30 -07:00
Akira Hatanaka 42bc49d3fe Add a new parameter convention @in_cxx for non-trivial C++ classes that are passed indirectly and destructed by the caller (#73019)
This corresponds to the parameter-passing convention of the Itanium C++
ABI, in which the argument is passed indirectly and possibly modified,
but not destroyed, by the callee.

@in_cxx is handled the same way as @in in callers and @in_guaranteed in
callees. OwnershipModelEliminator emits the call to destroy_addr that is
needed to destroy the argument in the caller.

rdar://122707697
2024-06-27 09:44:04 -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
Tim Kientzle 1098054291 Merge branch 'main' into tbkka-assertions2 2024-06-18 17:52:00 -07:00
Akira Hatanaka d92f181ace Create two versions (for caller and callee) of the functions that answer questions about parameter convention (#74124)
Create two versions of the following functions:

isConsumedParameter
isGuaranteedParameter
SILParameterInfo::isConsumed
SILParameterInfo::isGuaranteed
SILArgumentConvention::isOwnedConvention
SILArgumentConvention::isGuaranteedConvention

These changes will be needed when we add a new convention for
non-trivial C++ types as the functions will return different answers
depending on whether they are called for the caller or the callee. This
commit doesn't change any functionality.
2024-06-18 09:06:09 -07:00
Joe Groff bb4c0d3d59 MoveOnlyAddressChecker: Turn assertion into early exit.
This condition can occur in practice if, while doing the walk back to find the liveness
reason for a consume-without-reinitialization of an `inout` binding through conditional
control flow, we visit a block that reinitializes the binding before any branch that
leaves the binding uninitialized. Fixes rdar://123604613.
2024-06-12 18:40:04 -07:00
nate-chandler 033fc2354f Merge pull request #74157 from nate-chandler/rdar128710064
[SILGen] Store_borrow into in_guaranteed.
2024-06-07 06:47:16 -07:00
Nate Chandler 000a33f04f [MoveOnlyAddressChecker] Don't destroy borrows.
If a marked location is used by `store_borrow`s, then all its users are
`store_borrow`s or `dealloc_stack`s, so there's nothing to destroy.
2024-06-06 11:20:16 -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