Repository: apple/swift
File: lib/SILOptimizer/Utils/OSSACanonicalizeOwned.cpp (C++)

Code before:
  OSSACompleteLifetime::visitAvailabilityBoundary(
      getCurrentDef(), completeLiveness, [&](auto *unreachable, auto end) {
        if (end == OSSACompleteLifetime::LifetimeEnd::Boundary) {
          recordUnreachableLifetimeEnd(unreachable);
        }
        unreachable->visitPriorInstructions([&](auto *inst) {
          liveness->extendToNonUse(inst);
          return true;
        });
      });
}

void OSSACanonicalizeOwned::extendLivenessToDeinitBarriers() {
  SmallVector<SILInstruction *, 8> ends;
  if (endingLifetimeAtExplicitEnds()) {
    visitExtendedUnconsumedBoundary(
        explicitLifetimeEnds, [&ends](auto *instruction, auto lifetimeEnding) {
          instruction->visitSubsequentInstructions([&](auto *next) {
            ends.push_back(next);
            return true;
          });
        });
  } else {
    for (auto destroy : destroys) {
      if (destroy->getOperand(0) != getCurrentDef())
        continue;
      ends.push_back(destroy);
    }
  }

  auto *def = getCurrentDef()->getDefiningInstruction();
  using InitialBlocks = ArrayRef<SILBasicBlock *>;
  auto *defBlock = getCurrentDef()->getParentBlock();
  auto initialBlocks = defBlock ? InitialBlocks(defBlock) : InitialBlocks();
  ReachableBarriers barriers;
  findBarriersBackward(
      ends, initialBlocks, *getCurrentDef()->getFunction(), barriers,
      [&](auto *inst) {
        if (inst == def)
          return true;
        if (!isDeinitBarrier(inst, calleeAnalysis))
          return false;
        // For the most part, instructions that are deinit
        // barriers in the abstract are also deinit barriers
        // for the purposes of canonicalizing def's lifetime.
        //
        // There is an important exception: transferring an
        // owned lexical lifetime into a callee.  If the
        // instruction is a full apply which consumes def,
        // then it isn't a deinit barrier.  Keep looking for
        // barriers above it.

Review comment (security):
IIRC copy propagation checks if `getCurrentDef()` has a pointer escaper and bails out. For your test: 

```
sil [ossa] @dont_hoist_destroy_over_deinit_barrier : $@convention(thin) (@owned B, @guaranteed D) -> @owned Optional<B> {
bb0(%0 : @owned $B, %1 : @guaranteed $D):
  %2 = copy_value %0
  destroy_value %0
  %4 = ref_element_addr %1, #D.c
  %5 = load_weak %4
  destroy_value %2
  return %5
}
```

It should have walked through the interior pointer use `ref_element_addr`, then walked through it's address use `load_weak` and bailed out because it is a pointer escape. 

I am not sure why that is not happening in this case. 

Code after:
  OSSACompleteLifetime::visitAvailabilityBoundary(
      getCurrentDef(), completeLiveness, [&](auto *unreachable, auto end) {
        if (end == OSSACompleteLifetime::LifetimeEnd::Boundary) {
          recordUnreachableLifetimeEnd(unreachable);
        }
        unreachable->visitPriorInstructions([&](auto *inst) {
          liveness->extendToNonUse(inst);
          return true;
        });
      });
}

void OSSACanonicalizeOwned::extendLivenessToDeinitBarriers() {
  SmallVector<SILInstruction *, 8> ends;
  if (endingLifetimeAtExplicitEnds()) {
    visitExtendedUnconsumedBoundary(
        explicitLifetimeEnds, [&ends](auto *instruction, auto lifetimeEnding) {
          instruction->visitSubsequentInstructions([&](auto *next) {
            ends.push_back(next);
            return true;
          });
        });
  } else {
    for (auto destroy : destroys) {
      ends.push_back(destroy);
    }
  }

  auto *def = getCurrentDef()->getDefiningInstruction();
  using InitialBlocks = ArrayRef<SILBasicBlock *>;
  auto *defBlock = getCurrentDef()->getParentBlock();
  auto initialBlocks = defBlock ? InitialBlocks(defBlock) : InitialBlocks();
  ReachableBarriers barriers;
  findBarriersBackward(
      ends, initialBlocks, *getCurrentDef()->getFunction(), barriers,
      [&](auto *inst) {
        if (inst == def)
          return true;
        if (!isDeinitBarrier(inst, calleeAnalysis))
          return false;
        // For the most part, instructions that are deinit
        // barriers in the abstract are also deinit barriers
        // for the purposes of canonicalizing def's lifetime.
        //
        // There is an important exception: transferring an
        // owned lexical lifetime into a callee.  If the
        // instruction is a full apply which consumes def,
        // then it isn't a deinit barrier.  Keep looking for
        // barriers above it.
        auto apply = FullApplySite::isa(inst);
        if (!apply)