Skip to content

[SIL] Added borrow scopes to alloc_boxes. #40793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/SIL/IR/SILBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ SILBuilder::emitDestroyAddr(SILLocation Loc, SILValue Operand) {
if (isa<DeallocStackInst>(Inst))
continue;

// end_borrow insts also don't affect take-ability
if (isa<EndBorrowInst>(Inst))
continue;

// An end_access of the same address may be able to be rewritten as a
// [deinit] access.
if (auto endAccess = dyn_cast<EndAccessInst>(Inst)) {
Expand Down
13 changes: 11 additions & 2 deletions lib/SILGen/ResultPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ class IndirectOpenedSelfCleanup final : public Cleanup {
void emit(SILGenFunction &SGF, CleanupLocation loc, ForUnwind_t forUnwind)
override {
assert(box && "buffer never emitted before activating cleanup?!");
SGF.B.createDeallocBox(loc, box);
auto theBox = box;
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
auto *bbi = cast<BeginBorrowInst>(theBox);
SGF.B.createEndBorrow(loc, bbi);
theBox = bbi->getOperand();
}
SGF.B.createDeallocBox(loc, theBox);
}

void dump(SILGenFunction &SGF) const override {
Expand Down Expand Up @@ -160,7 +166,10 @@ class IndirectOpenedSelfResultPlan final : public ResultPlan {
SILBoxType::get(SGF.getASTContext(),
boxLayout,
layoutSubs));

if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
resultBox = SGF.B.createBeginBorrow(loc, resultBox, /*isLexical=*/true);
}

// Complete the cleanup to deallocate this buffer later, after we're
// finished with the argument.
static_cast<IndirectOpenedSelfCleanup&>(SGF.Cleanups.getCleanup(handle))
Expand Down
8 changes: 7 additions & 1 deletion lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3505,7 +3505,13 @@ class DeallocateUninitializedBox : public Cleanup {
DeallocateUninitializedBox(SILValue box) : box(box) {}

void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override {
SGF.B.createDeallocBox(l, box);
auto theBox = box;
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
auto *bbi = cast<BeginBorrowInst>(theBox);
SGF.B.createEndBorrow(l, bbi);
theBox = bbi->getOperand();
}
SGF.B.createDeallocBox(l, theBox);
}

void dump(SILGenFunction &SGF) const override {
Expand Down
22 changes: 20 additions & 2 deletions lib/SILGen/SILGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,13 @@ class DeallocateUninitializedLocalVariable : public Cleanup {

void emit(SILGenFunction &SGF, CleanupLocation l,
ForUnwind_t forUnwind) override {
SGF.B.createDeallocBox(l, Box);
auto box = Box;
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
auto *bbi = cast<BeginBorrowInst>(box);
SGF.B.createEndBorrow(l, bbi);
box = bbi->getOperand();
}
SGF.B.createDeallocBox(l, box);
}

void dump(SILGenFunction &) const override {
Expand Down Expand Up @@ -360,6 +366,10 @@ class LocalVariableInitialization : public SingleBufferInitialization {
if (kind)
Box = SGF.B.createMarkUninitialized(decl, Box, kind.getValue());

if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
Box = SGF.B.createBeginBorrow(decl, Box, /*isLexical=*/true);
}

Addr = SGF.B.createProjectBox(decl, Box, 0);

// Push a cleanup to destroy the local variable. This has to be
Expand Down Expand Up @@ -1751,7 +1761,15 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
// For a heap variable, the box is responsible for the value. We just need
// to give up our retain count on it.
if (loc.box) {
B.emitDestroyValueOperation(silLoc, loc.box);
if (!getASTContext().SILOpts.supportsLexicalLifetimes(getModule())) {
B.emitDestroyValueOperation(silLoc, loc.box);
return;
}

auto *bbi = cast<BeginBorrowInst>(loc.box);
B.createEndBorrow(silLoc, bbi);
B.emitDestroyValueOperation(silLoc, bbi->getOperand());

return;
}

Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static void lifetimeExtendAddressOnlyRValueSubValues(
"addresses must be address only.");
auto boxTy = SILBoxType::get(v->getType().getASTType());
SILValue box = SGF.B.createAllocBox(loc, boxTy);
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
box = SGF.B.createBeginBorrow(loc, box, /*isLexical=*/true);
}
SILValue addr = SGF.B.createProjectBox(loc, box, 0);
SGF.B.createCopyAddr(loc, v, addr, IsTake, IsInitialization);

Expand Down
14 changes: 10 additions & 4 deletions lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ void SelectEnforcement::analyzeUsesOfBox(SingleValueInstruction *source) {
for (auto use : source->getUses()) {
auto user = use->getUser();

if (auto BBI = dyn_cast<BeginBorrowInst>(user)) {
analyzeUsesOfBox(BBI);
continue;
}

if (auto MUI = dyn_cast<MarkUninitializedInst>(user)) {
analyzeUsesOfBox(MUI);
continue;
Expand All @@ -238,10 +243,9 @@ void SelectEnforcement::analyzeUsesOfBox(SingleValueInstruction *source) {
}

// Ignore certain other uses that do not capture the value.
if (isa<StrongRetainInst>(user) ||
isa<StrongReleaseInst>(user) ||
isa<DestroyValueInst>(user) ||
isa<DeallocBoxInst>(user))
if (isa<StrongRetainInst>(user) || isa<StrongReleaseInst>(user) ||
isa<DestroyValueInst>(user) || isa<DeallocBoxInst>(user) ||
isa<EndBorrowInst>(user))
continue;

// Treat everything else as an escape.
Expand Down Expand Up @@ -667,6 +671,8 @@ void AccessEnforcementSelection::processFunction(SILFunction *F) {
SourceAccess
AccessEnforcementSelection::getAccessKindForBox(ProjectBoxInst *projection) {
SILValue source = projection->getOperand();
if (auto *BBI = dyn_cast<BeginBorrowInst>(source))
source = BBI->getOperand();
if (auto *MUI = dyn_cast<MarkUninitializedInst>(source))
source = MUI->getOperand();

Expand Down
4 changes: 3 additions & 1 deletion lib/SILOptimizer/Mandatory/CapturePromotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,7 @@ class NonEscapingUserVisitor
ALWAYS_NON_ESCAPING_INST(Load)
ALWAYS_NON_ESCAPING_INST(StrongRelease)
ALWAYS_NON_ESCAPING_INST(DestroyValue)
ALWAYS_NON_ESCAPING_INST(EndBorrow)
#undef ALWAYS_NON_ESCAPING_INST

bool visitDeallocBoxInst(DeallocBoxInst *dbi) {
Expand Down Expand Up @@ -1213,7 +1214,8 @@ static bool findEscapeOrMutationUses(Operand *op,
// we want to be more conservative around non-top level copies (i.e. a copy
// derived from a projection like instruction). In fact such a thing may not
// even make any sense!
if (isa<CopyValueInst>(user) || isa<MarkUninitializedInst>(user)) {
if (isa<CopyValueInst>(user) || isa<MarkUninitializedInst>(user) ||
isa<BeginBorrowInst>(user)) {
bool foundSomeMutations = false;
for (auto *use : cast<SingleValueInstruction>(user)->getUses()) {
foundSomeMutations |= findEscapeOrMutationUses(use, state);
Expand Down
12 changes: 11 additions & 1 deletion lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ static void gatherDestroysOfContainer(const DIMemoryObjectInfo &memoryInfo,
// TODO: This should really be tracked separately from other destroys so that
// we distinguish the lifetime of the container from the value itself.
assert(isa<ProjectBoxInst>(uninitMemory));
auto *mui = cast<MarkUninitializedInst>(uninitMemory->getOperand(0));
auto value = uninitMemory->getOperand(0);
if (auto *bbi = dyn_cast<BeginBorrowInst>(value)) {
value = bbi->getOperand();
}
auto *mui = cast<MarkUninitializedInst>(value);
for (auto *user : mui->getUsersOfType<DestroyValueInst>()) {
useInfo.trackDestroy(user);
}
Expand Down Expand Up @@ -114,6 +118,12 @@ DIMemoryObjectInfo::DIMemoryObjectInfo(MarkUninitializedInst *MI)
auto &Module = MI->getModule();

SILValue Address = MemoryInst;
if (auto BBI = MemoryInst->getSingleUserOfType<BeginBorrowInst>()) {
if (auto PBI = BBI->getSingleUserOfType<ProjectBoxInst>()) {
IsBox = true;
Address = PBI;
}
}
if (auto PBI = MemoryInst->getSingleUserOfType<ProjectBoxInst>()) {
IsBox = true;
Address = PBI;
Expand Down
10 changes: 7 additions & 3 deletions lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,14 @@ class DIMemoryObjectInfo {
/// with the memory info.
SingleValueInstruction *getUninitializedValue() const {
if (IsBox) {
SILValue inst = MemoryInst;
if (auto *bbi = MemoryInst->getSingleUserOfType<BeginBorrowInst>()) {
inst = bbi;
}
// TODO: consider just storing the ProjectBoxInst in this case.
auto *pbi = MemoryInst->getSingleUserOfType<ProjectBoxInst>();
assert(pbi);
return pbi;
SingleValueInstruction *svi = inst->getSingleUserOfType<ProjectBoxInst>();
assert(svi);
return svi;
}
return MemoryInst;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ const ParamDecl *getParamDeclFromOperand(SILValue value) {

bool isUseOfSelfInInitializer(Operand *oper) {
if (auto *PBI = dyn_cast<ProjectBoxInst>(oper->get())) {
if (auto *MUI = dyn_cast<MarkUninitializedInst>(PBI->getOperand())) {
SILValue value = PBI->getOperand();
if (auto *bbi = dyn_cast<BeginBorrowInst>(value)) {
value = bbi->getOperand();
}
if (auto *MUI = dyn_cast<MarkUninitializedInst>(value)) {
switch (MUI->getMarkUninitializedKind()) {
case MarkUninitializedInst::Kind::Var:
return false;
Expand Down
27 changes: 17 additions & 10 deletions lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ static bool getFinalReleases(SILValue Box,

// If we have a copy value or a mark_uninitialized, add its uses to the work
// list and continue.
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User) ||
isa<BeginBorrowInst>(User)) {
llvm::copy(cast<SingleValueInstruction>(User)->getUses(),
std::back_inserter(Worklist));
continue;
Expand Down Expand Up @@ -385,12 +386,14 @@ static SILInstruction *recursivelyFindBoxOperandsPromotableToAddress(
// Projections are fine as well.
if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) ||
isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) ||
(!inAppliedFunction && isa<DeallocBoxInst>(User)))
(!inAppliedFunction && isa<DeallocBoxInst>(User)) ||
isa<EndBorrowInst>(User))
continue;

// If our user instruction is a copy_value or a mark_uninitialized, visit
// the users recursively.
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User) ||
isa<BeginBorrowInst>(User)) {
llvm::copy(cast<SingleValueInstruction>(User)->getUses(),
std::back_inserter(Worklist));
continue;
Expand Down Expand Up @@ -502,10 +505,12 @@ static void replaceProjectBoxUsers(SILValue HeapBox, SILValue StackBox) {
continue;
}

auto *CVI = dyn_cast<CopyValueInst>(Op->getUser());
if (!CVI)
continue;
llvm::copy(CVI->getUses(), std::back_inserter(Worklist));
auto *User = Op->getUser();
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User) ||
isa<BeginBorrowInst>(User)) {
llvm::copy(cast<SingleValueInstruction>(User)->getUses(),
std::back_inserter(Worklist));
}
}
}

Expand Down Expand Up @@ -578,8 +583,9 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
while (!Worklist.empty()) {
auto *User = Worklist.pop_back_val();

// Look through any mark_uninitialized, copy_values.
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
// Look through any mark_uninitialized, copy_values, begin_borrow.
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User) ||
isa<BeginBorrowInst>(User)) {
auto Inst = cast<SingleValueInstruction>(User);
llvm::transform(Inst->getUses(), std::back_inserter(Worklist),
[](Operand *Op) -> SILInstruction * {
Expand All @@ -592,7 +598,7 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {

assert(isa<StrongReleaseInst>(User) || isa<StrongRetainInst>(User) ||
isa<DeallocBoxInst>(User) || isa<ProjectBoxInst>(User) ||
isa<DestroyValueInst>(User));
isa<DestroyValueInst>(User) || isa<EndBorrowInst>(User));

User->eraseFromParent();
}
Expand Down Expand Up @@ -934,6 +940,7 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply,
assert((isa<SingleValueInstruction>(Box) && isa<AllocBoxInst>(Box) ||
isa<CopyValueInst>(Box) ||
isa<MarkUninitializedInst>(Box) ||
isa<BeginBorrowInst>(Box) ||
isa<SILFunctionArgument>(Box)) &&
"Expected either an alloc box or a copy of an alloc box or a "
"function argument");
Expand Down
6 changes: 4 additions & 2 deletions test/SILGen/access_marker_gen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public struct S {
// CHECK: bb0(%0 : @guaranteed $Optional<AnyObject>):
// CHECK: [[BOX:%.*]] = alloc_box ${ var S }, var, name "s"
// CHECK: [[MARKED_BOX:%.*]] = mark_uninitialized [var] [[BOX]] : ${ var S }
// CHECK: [[ADDR:%.*]] = project_box [[MARKED_BOX]] : ${ var S }, 0
// CHECK: [[BOX_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[MARKED_BOX]]
// CHECK: [[ADDR:%.*]] = project_box [[BOX_LIFETIME]] : ${ var S }, 0
// CHECK: cond_br %{{.*}}, bb1, bb2
// CHECK: bb1:
// CHECK: [[ACCESS1:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*S
Expand Down Expand Up @@ -45,7 +46,8 @@ func takeS(_ s: S) {}
// CHECK-LABEL: sil [ossa] @$s17access_marker_gen14modifyAndReadSyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: %[[BOX:.*]] = alloc_box ${ var S }, var, name "s"
// CHECK: %[[ADDRS:.*]] = project_box %[[BOX]] : ${ var S }, 0
// CHECK: %[[BOX_LIFETIME:[^,]+]] = begin_borrow [lexical] %[[BOX]]
// CHECK: %[[ADDRS:.*]] = project_box %[[BOX_LIFETIME]] : ${ var S }, 0
// CHECK: %[[ACCESS1:.*]] = begin_access [modify] [unknown] %[[ADDRS]] : $*S
// CHECK: %[[ADDRI:.*]] = struct_element_addr %[[ACCESS1]] : $*S, #S.i
// CHECK: assign %{{.*}} to %[[ADDRI]] : $*Int
Expand Down
6 changes: 4 additions & 2 deletions test/SILGen/address_only_types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ func address_only_assignment_from_lv(_ dest: inout Unloadable, v: Unloadable) {
var v = v
// CHECK: bb0([[DEST:%[0-9]+]] : $*Unloadable, [[VARG:%[0-9]+]] : $*Unloadable):
// CHECK: [[VBOX:%.*]] = alloc_box ${ var Unloadable }
// CHECK: [[PBOX:%[0-9]+]] = project_box [[VBOX]]
// CHECK: [[V_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[VBOX]]
// CHECK: [[PBOX:%[0-9]+]] = project_box [[V_LIFETIME]]
// CHECK: copy_addr [[VARG]] to [initialization] [[PBOX]] : $*Unloadable
dest = v
// CHECK: [[READBOX:%.*]] = begin_access [read] [unknown] [[PBOX]] :
Expand Down Expand Up @@ -211,7 +212,8 @@ func address_only_var() -> Unloadable {
// CHECK: bb0([[RET:%[0-9]+]] : $*Unloadable):
var x = some_address_only_function_1()
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Unloadable }
// CHECK: [[XPB:%.*]] = project_box [[XBOX]]
// CHECK: [[XBOX_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[XBOX]]
// CHECK: [[XPB:%.*]] = project_box [[XBOX_LIFETIME]]
// CHECK: apply {{%.*}}([[XPB]])
return x
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XPB]] :
Expand Down
1 change: 1 addition & 0 deletions test/SILGen/auto_generated_super_init_call.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class SomeDerivedClass : Parent {
// CHECK-NEXT: [[SELFAGAIN:%.*]] = unchecked_ref_cast [[PARENT]]
// CHECK-NEXT: store [[SELFAGAIN]] to [init] [[SELF]]
// CHECK-NEXT: [[SELFLOAD:%.*]] = load [copy] [[SELF]]
// CHECK-NEXT: end_borrow
// CHECK-NEXT: destroy_value
// CHECK-NEXT: return [[SELFLOAD]]
}
Expand Down
4 changes: 3 additions & 1 deletion test/SILGen/borrow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func useD(_ d: D) {}
// CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[BOX:%.*]] = alloc_box ${ var C }, var, name "c"
// CHECK: [[PB_BOX:%.*]] = project_box [[BOX]]
// CHECK: [[BOX_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PB_BOX:%.*]] = project_box [[BOX_LIFETIME]]
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB_BOX]] : $*C
// CHECK: [[CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: [[BORROWED_CLASS:%.*]] = begin_borrow [[CLASS]]
Expand All @@ -29,6 +30,7 @@ func useD(_ d: D) {}
// CHECK: destroy_value [[CLASS]]
// CHECK: [[FUNC:%.*]] = function_ref @$s6borrow4useD{{.*}} : $@convention(thin) (@guaranteed D) -> ()
// CHECK: apply [[FUNC]]([[LOADED_VALUE]])
// CHECK: end_borrow [[BOX_LIFETIME]]
// CHECK: destroy_value [[BOX]]
// CHECK: } // end sil function '$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}}'
func lvalueBorrowShouldBeAtEndOfFormalAccessScope() {
Expand Down
13 changes: 9 additions & 4 deletions test/SILGen/boxed_existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ func test_property_of_lvalue(_ x: Error) -> String {
// CHECK-LABEL: sil hidden [ossa] @$s18boxed_existentials23test_property_of_lvalueySSs5Error_pF :
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
// CHECK: [[VAR:%.*]] = alloc_box ${ var Error }
// CHECK: [[PVAR:%.*]] = project_box [[VAR]]
// CHECK: [[VAR_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[VAR]]
// CHECK: [[PVAR:%.*]] = project_box [[VAR_LIFETIME]]
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]] : $Error
// CHECK: store [[ARG_COPY]] to [init] [[PVAR]]
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PVAR]] : $*Error
Expand All @@ -98,6 +99,7 @@ func test_property_of_lvalue(_ x: Error) -> String {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[BORROW]])
// CHECK: destroy_addr [[COPY]]
// CHECK: dealloc_stack [[COPY]]
// CHECK: end_borrow [[VAR_LIFETIME]]
// CHECK: destroy_value [[VAR]]
// CHECK-NOT: destroy_value [[ARG]]
// CHECK: return [[RESULT]]
Expand Down Expand Up @@ -131,9 +133,11 @@ func test_open_existential_semantics(_ guaranteed: Error,
_ immediate: Error) {
var immediate = immediate
// CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
// CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
// CHECK: [[IMMEDIATE_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[IMMEDIATE_BOX]]
// CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_LIFETIME]]
// GUARANTEED: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
// GUARANTEED: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
// GUARANTEED: [[IMMEDIATE_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[IMMEDIATE_BOX]]
// GUARANTEED: [[PB:%.*]] = project_box [[IMMEDIATE_LIFETIME]]

// CHECK-NOT: copy_value [[ARG0]]
// CHECK: [[VALUE:%.*]] = open_existential_box [[ARG0]]
Expand Down Expand Up @@ -200,7 +204,8 @@ func test_open_existential_semantics(_ guaranteed: Error,
func erasure_to_any(_ guaranteed: Error, _ immediate: Error) -> Any {
var immediate = immediate
// CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
// CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
// CHECK: [[IMMEDIATE_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[IMMEDIATE_BOX]]
// CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_LIFETIME]]
if true {
// CHECK-NOT: copy_value [[GUAR]]
// CHECK: [[FROM_VALUE:%.*]] = open_existential_box [[GUAR:%.*]]
Expand Down
Loading