Skip to content

Commit bf077f9

Browse files
committed
Fix AllocBoxToStack to handle mark_dependence[_addr]
Handle the easy case in which the promoted box is the base operand of a mark_dep. This requires nothing more than setting the base operand to the new stack address. Required for move-only checking. Otherwise, we get an incredibly bizarre compiler error: noncopyable 'foo' cannot be consumed when captured by an escaping closure Fixes rdar://154519148 (Returning non-copyable type after accessing borrowed field emits incorrect error about escaped closure capturing the noncopyable)
1 parent 5528cf1 commit bf077f9

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8964,6 +8964,21 @@ class MarkDependenceInstruction {
89648964
return SILValue();
89658965
}
89668966

8967+
void setBase(SILValue newVal) {
8968+
if (inst) {
8969+
switch (inst->getKind()) {
8970+
case SILInstructionKind::MarkDependenceInst:
8971+
cast<MarkDependenceInst>(inst)->setBase(newVal);
8972+
break;
8973+
case SILInstructionKind::MarkDependenceAddrInst:
8974+
cast<MarkDependenceAddrInst>(inst)->setBase(newVal);
8975+
break;
8976+
default:
8977+
break;
8978+
}
8979+
}
8980+
}
8981+
89678982
SILValue getDependent() const {
89688983
if (inst) {
89698984
switch (inst->getKind()) {

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,13 @@ static SILInstruction *recursivelyFindBoxOperandsPromotableToAddress(
400400
isa<EndBorrowInst>(User))
401401
continue;
402402

403+
// mark_dependence base value uses will be directly converted to base
404+
// address uses.
405+
if (auto mdi = MarkDependenceInstruction(User)) {
406+
if (Op->get() == mdi.getBase())
407+
continue;
408+
}
409+
403410
// If our user instruction is a copy_value or a mark_uninitialized, visit
404411
// the users recursively.
405412
if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User) ||
@@ -738,6 +745,12 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
738745
Inst->eraseFromParent();
739746
continue;
740747
}
748+
// mark_dependence base value uses will be directly converted to base
749+
// address uses.
750+
if (auto mdi = MarkDependenceInstruction(User)) {
751+
mdi.setBase(StackBox);
752+
continue;
753+
}
741754

742755
assert(isa<StrongReleaseInst>(User) || isa<StrongRetainInst>(User) ||
743756
isa<DeallocBoxInst>(User) || isa<ProjectBoxInst>(User) ||
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %target-sil-opt -enable-experimental-feature LifetimeDependence -allocbox-to-stack %s | %FileCheck %s
2+
3+
import Swift
4+
import Builtin
5+
6+
public struct View : ~Escapable {
7+
let _ptr: UnsafeRawPointer
8+
}
9+
10+
sil [ossa] @initFn : $@convention(method) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @owned View
11+
sil [ossa] @initFnAddr : $@convention(thin) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @out View
12+
13+
// CHECK-LABEL: sil [ossa] @testBoxedParam :
14+
// CHECK-NOT: alloc_box
15+
// CHECK-LABEL: } // end sil function 'testBoxedParam'
16+
sil [ossa] @testBoxedParam : $@convention(thin) (@owned View) -> @lifetime(copy 0) @owned View {
17+
bb0(%0 : @noImplicitCopy @_eagerMove @owned $View):
18+
%1 = alloc_box ${ var @moveOnly View }, var, name "that"
19+
%2 = begin_borrow [var_decl] %1
20+
%3 = project_box %2, 0
21+
%4 = moveonlywrapper_to_copyable_addr %3
22+
store %0 to [init] %4
23+
%6 = metatype $@thin View.Type
24+
%7 = begin_access [read] [static] %3
25+
%8 = mark_unresolved_non_copyable_value [no_consume_or_assign] %7
26+
%9 = struct_element_addr %8, #View._ptr
27+
%10 = load_borrow %9
28+
%11 = moveonlywrapper_to_copyable [guaranteed] %10
29+
end_borrow %10
30+
end_access %7
31+
%14 = function_ref @initFn : $@convention(method) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @owned View
32+
%15 = apply %14(%11, %6) : $@convention(method) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @owned View
33+
%16 = mark_dependence [unresolved] %15 on %2
34+
end_borrow %2
35+
destroy_value %1
36+
return %16
37+
}
38+
39+
// CHECK-LABEL: sil [ossa] @testBoxedParamAddr :
40+
// CHECK-NOT: alloc_box
41+
// CHECK-LABEL: } // end sil function 'testBoxedParamAddr'
42+
sil [ossa] @testBoxedParamAddr : $@convention(thin) (@owned View) -> () {
43+
bb0(%0 : @noImplicitCopy @_eagerMove @owned $View):
44+
%1 = alloc_box ${ var @moveOnly View }, var, name "that"
45+
%2 = begin_borrow [var_decl] %1
46+
%3 = project_box %2, 0
47+
%4 = moveonlywrapper_to_copyable_addr %3
48+
store %0 to [init] %4
49+
%6 = metatype $@thin View.Type
50+
%7 = begin_access [read] [static] %3
51+
%8 = mark_unresolved_non_copyable_value [no_consume_or_assign] %7
52+
%9 = struct_element_addr %8, #View._ptr
53+
%10 = load_borrow %9
54+
%11 = moveonlywrapper_to_copyable [guaranteed] %10
55+
end_borrow %10
56+
end_access %7
57+
%14 = alloc_stack $View
58+
%15 = function_ref @initFnAddr : $@convention(thin) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @out View
59+
%16 = apply %15(%14, %11, %6) : $@convention(thin) (UnsafeRawPointer, @thin View.Type) -> @lifetime(borrow 0) @out View
60+
mark_dependence_addr [unresolved] %14 on %2
61+
dealloc_stack %14
62+
end_borrow %2
63+
destroy_value %1
64+
%99 = tuple ()
65+
return %99
66+
}

0 commit comments

Comments
 (0)