Commit Graph

33 Commits

Author SHA1 Message Date
Andrew Trick 1ed083be0c LifetimeDependenceDiagnostics: add Builtin.makeBorrow support
Code like this currently looks like a lifetime escape:

  struct Ref<T: ~Copyable & ~Escapable>: ~Escapable {
    private let ref: Builtin.Borrow<T>

    @_lifetime(borrow target)
    init(_ target: borrowing T) {
      self.ref = Builtin.makeBorrow(target)
    }
  }

This is blocking the implementation of `Ref<~Escapable>`.

Fixes rdar://176564359 ([nonescapable] support Builtin.makeBorrow in
lifetime diagnostics)
2026-05-08 12:26:42 -07:00
Andrew Trick 6a9875c73e LifetimeDependenceUtils: add support for mutable captures
A mutable capture is always escaping. Naturally, you can't mutably capture a
non-Escapable value. Nonetheless, code may override the lifetime of the captured
value as immortal, knowing that the closure does not actually escape.

'_overrideLifetime(capturedThing, copying: ())' quiets the diagnostics
on the caller side. But, when diagnosing the closure body itself, lifetime
analysis is upset by the boxed non-Escaping value. Simply add a case
to LocalVariableAccessMap to recognize this as a valid case so that diagnostics
can ignore it.

Fixes rdar://170592353 (error: lifetime-dependent variable 'overriddenLifetime'
escapes its scope)
2026-02-20 09:12:38 -08:00
Andrew Trick 5943d40edf LifetimeDependenceDiagnostics: handle dynamic casting of Span<T>
Add a special case for checked_cast_addr_br instruction. If it conformed to
SourceDestAddrInstruction, then the diagnostics would already have handled it
naturally, but the instruction's conditional semantics are strange enough that
such a conformance might confuse other passes.

rdar://159793739 (Using `as?` with non-escapable types emits faulty lifetime
diagnostics)
2025-10-30 23:28:25 -07:00
Andrew Trick 305d75187a LocalVariableUtils: precisely handle function live-out
Only record an outgoingArgument access when the current allocation is an
outgoing argument and the function exiting instruction is ReturnInst.

This avoids invalid SIL where we attempt to extend end_access up to an `unwind` but
fail to actually materialize that end_access.
2025-10-23 23:34:26 -07:00
Andrew Trick 62b04caaa7 LocalVariableUtils add non-escaping closure capture support
Don't always consider an inout_aliasable argument to have
escaped. AccessEnforcementSelection has already done that analysis and left
begin_access [dynamic] artifacts if the argument has escaped in any meaningful
way. Use that information to

Essential for supporting autoclosures that call mutating methods on span-like
things. Such as UTF8Span.UnicodeScalarIterator.skipForward():

e.g. while numSkipped < n && skipForward() != 0 { ... }
2025-10-23 23:34:25 -07:00
Andrew Trick 77ee27a0e7 [NFC] LocalVariableAccessInfo.description 2025-10-23 23:34:25 -07:00
Andrew Trick de34abe3e5 Fix LocalVariableReachableAccess to handle potential reassignment.
Define LocalAccessInfo._isFullyAssigned to mean that the access does not read
the incoming value. Then treat any assignment that isn't full as a potential read.
2025-10-23 23:34:25 -07:00
Andrew Trick 6e0eeb00e3 Fix LifetimeDependenceDefUseWalker for @inout reassignment 2025-10-23 23:34:24 -07:00
Andrew Trick ff4d053a44 [NFC] LifetimeDependenceDefUseWalker.inoutDependence entry point
Handle cases where there's no relevant operand.
2025-10-23 23:34:24 -07:00
Andrew Trick 239255b8bc Improve LocalVariableUtils.gatherKnownLifetimeUses; dead ends
Add a fake use for dead-end blocks. This allows gatherKnownLifetimeUses to be
used for local liveness by considering an "unreachable" instruction to generate
liveness. This is important when liveness is used as a boundary within which
access scopes may be extended. Otherwise, we are unable to extend access scopes
into dead-end blocks.

Fixes rdar://154406790 (Lifetime-dependent variable 'X' escapes its
scope but only if actor/class is final)
2025-07-03 21:30:37 -07:00
Andrew Trick fe9c0dd735 Fix LocalVariableUtils switch_enum_addr.
switch_enum_addr was being treated like a store instruction, which killed
the local enum's liveness. This could result local variable analysis reporting a
shorter lifetime for the local.

This showed up as a missing exclusivity diagnostic because an access scope was
not fully extended across a dependent local variable of Optional type.

This prevents the following pattern from miscompiling. It should report an exclusivity violation:

  var mutableView = getOpaqueOptionalView(holder: &holder)!
  mutate(&holder)
  mutableView.modify()

Fixes rdar://151231236 ([~Escapable] Missing 'overlapping acceses' error when
called from client code, but exact same code produces error in same module)
2025-06-28 09:30:17 -07:00
Valeriy Van 949c2bad67 Fix some typos in SwiftCompilerSources/Sources 2025-06-08 11:22:45 +03:00
Andrew Trick 3b08592ed2 Fix LifetimeDependenceDiagnostics: handle drop_deinit unsafeAddress
This adds support to handle unsafe addressors, which generate mark_dependence
instructions with an address base. This case does not arise with lifetime
dependencies. Nonetheless, the lifetime dependence diagnostics kick in to
attempt to promote the unsafe addressor's mark_dependence to noescape, so we
need to handle it.

rdar://149784450 (Compiler crash with non-escapable deinit dereferencing)
2025-04-22 22:35:09 -07:00
Andrew Trick 4e35d255ad LocalVariableUtils: add store_borrow access tracking.
We sometimes use LocalVariableUtils to analyze temporary storage in which the
store_borrow is not already enclosed by an access scope.
2025-04-16 16:46:38 -07:00
Andrew Trick c9279d9899 Fix AddressOwnershipLiveRange to include the full range.
This allows further extension of access scopes.

Fixes rdar://143992296 (Use of `RawSpan` in switch context causes compiler crash
in AddressOwnershipLiveRange)
2025-04-11 23:49:07 -07:00
Andrew Trick ccb26bcd89 LocalVariableUtils: add unit tests 2025-04-10 23:27:55 -07:00
Andrew Trick 37ecd0e9bd LocalVariableUtils: fix data flow propagation of escapes.
This is only used for lifetime dependence diagnostics.

Fix a couple of obvious problems with data flow propagation that crept in during
"cleanup" because no unit tests existed.
2025-04-10 23:27:55 -07:00
Andrew Trick 69b6b1d309 LifetimeDependenceDefUseWalker: handle addressable dependencies 2025-03-25 23:02:45 -07:00
Andrew Trick d9dd93560d Support mark_dependence_addr in SIL passes. 2025-03-25 23:02:45 -07:00
Andrew Trick 8b39b6d16a LocalVariableUtils: record mark_dependence bad address operands
Avoid bailing out when something depends on the local variable.
2025-02-10 09:11:22 -08:00
Andrew Trick cc07b4ba11 Fix LifetimeDependenceDiagnostics for @out dependencies.
Record a forwarding mark_dependence as a local access. This is necessary because
we now emit a mark_dependence for @out arguments, which will be the starting
point for diagnostics:

  %out = alloc_stack
  apply %f(%owned, %out) : $(Owner) -> @lifetime(borrow 0) @out View
  %unused = mark_dependence [unresolved] %out on %owner
  %dependentValue = load %out

This mark_dependence has no uses. Instead, it simply records the dependency of
the in-memory value on the owner. Consequently, simply walking the uses of
LifetimeDependence.dependentValue does fails to diagnose any escapes. Instead,
if the dependentValue is an address-type mark_dependence, treat it as a local
access to the address that it forwards. Then we find any reachable uses of that
local variable as a potential escape.

Fixes rdar://143040479
(Borrow diagnostics not triggered for @out return values)
2025-01-17 11:19:04 -08:00
Andrew Trick afda6453a5 Improve LocalVariableAccessInfo: recognize more full-assignments.
Ignore marker instructions for the purpose of determining whether a store is a
full assignment:

  %a = alloc_stack
  %m = moveonlywrapper_to_copyable_addr %a
  store %0 to [init] %m // <=== full assignemt
2025-01-17 11:19:04 -08:00
Erik Eckstein 701a7f7275 SwiftCompilerSources: don't make anything public in the Optimizer module
The Optimizer module is a leave module. No other modules depend on it. Therefore nothing must be public in this module.
2024-10-02 07:10:28 +02:00
Andrew Trick e4036b970b Improve LocalVariableAccessWalker to handle switch_enum_addr. 2024-08-19 18:01:49 -07:00
Alexander Cyon c18a24e499 [SwiftCompilerSources] Fix typos 2024-08-08 22:22:39 -07:00
Andrew Trick 11ba799cd4 LifetimeDependence: diagnose yield and store-to-yield. 2024-07-30 16:27:48 -07:00
Andrew Trick c41dc33c10 LocalVariableUtils: handle projections inside initializers.
These projections don't have access scopes, so the utility was treating them
like escapes.

Fixes: rdar://131499478 (Difficulties composing non-escapable types)
2024-07-12 19:58:14 -07:00
Andrew Trick fc60925a38 LocalVariableUtils: add support for temporary enum initialization. 2024-04-12 14:11:37 -07:00
Andrew Trick e77fff3d23 LocalVariableUtils logging 2024-03-18 17:45:33 -07:00
Andrew Trick f1fbbcd438 Handle escaping addresses in LocalVariableAccessWalker
Fixes rdar://124564951 (Compiler crash when evaluating pointer escape
in autoclosure; LifetimeDepenenceScopeFixup; Fatal error: check
findPointerEscape() before computing interior liveness.)
2024-03-18 17:45:33 -07:00
Andrew Trick 00fbf4f1af LocalVariableUtils logging 2024-03-18 17:45:33 -07:00
Andrew Trick aa208bbf91 Add SILType::containsNoEscapeFunction()
Add PartialApplyInst.hasNoescapeCapture
Add PartialApplyInst.mayEscape

Refactor DiagnoseInvalidEscapingCaptures. This may change functionality because tuples containing a noescape closure are now correctly recognized. Although I'm not sure such tupes can ever be captured directly.
2024-03-18 17:38:12 -07:00
Andrew Trick ffe9c48976 Add LocalVariableUtils
This includes a reaching-def analysis that can be used by diagnostic passes. Diagnostics should be flow-sensitive.
2024-03-05 18:08:16 -08:00