Skip to content

Commit c3d2276

Browse files
committed
[silgen] Eliminate two more cases around subscripts where we were not borrowing.
Also, the store_borrow work in the previous patch caused some additional issues to crop up. I fixed them in this PR and added some tests in the process.
1 parent 26081ff commit c3d2276

11 files changed

+215
-38
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4392,8 +4392,18 @@ class StoreBorrowInst
43924392

43934393
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
43944394
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
4395+
4396+
using EndBorrowRange =
4397+
decltype(std::declval<ValueBase>().getUsersOfType<EndBorrowInst>());
4398+
4399+
/// Return a range over all EndBorrow instructions for this BeginBorrow.
4400+
EndBorrowRange getEndBorrows() const;
43954401
};
43964402

4403+
inline auto StoreBorrowInst::getEndBorrows() const -> EndBorrowRange {
4404+
return getUsersOfType<EndBorrowInst>();
4405+
}
4406+
43974407
/// Represents the end of a borrow scope of a value %val from a
43984408
/// value or address %src.
43994409
///

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ SubElementOffset::computeForAddress(SILValue projectionDerivedFromRoot,
129129
continue;
130130
}
131131

132+
if (auto *sbi = dyn_cast<StoreBorrowInst>(projectionDerivedFromRoot)) {
133+
projectionDerivedFromRoot = sbi->getDest();
134+
continue;
135+
}
136+
132137
if (auto *m = dyn_cast<MoveOnlyWrapperToCopyableAddrInst>(
133138
projectionDerivedFromRoot)) {
134139
projectionDerivedFromRoot = m->getOperand();

lib/SILGen/SILGenApply.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3124,6 +3124,21 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly(
31243124
if (kind == StorageReferenceOperationKind::Consume && !sawLoad)
31253125
return nullptr;
31263126

3127+
// If we did not see a load or a subscript expr and our argExpr is a
3128+
// declref_expr, return nullptr. We have an object not something that will be
3129+
// in memory. This can happen with classes or with values captured by a
3130+
// closure.
3131+
//
3132+
// NOTE: If we see a member_ref_expr from a decl_ref_expr, we still process it
3133+
// since the declref_expr could be from a class.
3134+
if (!sawLoad && !subscriptExpr) {
3135+
if (auto *declRef = dyn_cast<DeclRefExpr>(argExpr)) {
3136+
assert(!declRef->getType()->is<LValueType>() &&
3137+
"Shouldn't ever have an lvalue type here!");
3138+
return nullptr;
3139+
}
3140+
}
3141+
31273142
auto result = ::findStorageReferenceExprForBorrow(argExpr);
31283143

31293144
if (!result)
@@ -3143,31 +3158,18 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly(
31433158
}
31443159

31453160
if (!storage)
3146-
return nullptr;
3161+
return nullptr;
31473162
assert(type);
31483163

31493164
SILType ty =
31503165
SGF.getLoweredType(type->getWithoutSpecifierType()->getCanonicalType());
31513166
bool isMoveOnly = ty.isPureMoveOnly();
31523167
if (auto *pd = dyn_cast<ParamDecl>(storage)) {
3153-
isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Borrowing;
3154-
isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Consuming;
3168+
isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Borrowing;
3169+
isMoveOnly |= pd->getSpecifier() == ParamSpecifier::Consuming;
31553170
}
31563171
if (!isMoveOnly)
3157-
return nullptr;
3158-
3159-
// It makes sense to borrow any kind of storage we refer to at this stage,
3160-
// but SILGenLValue does not currently handle some kinds of references well.
3161-
//
3162-
// When rejecting to do the LValue-style borrow here, it'll end up going thru
3163-
// the RValue-style emission, after which the extra copy will get eliminated.
3164-
//
3165-
// If we did not see a LoadExpr around the argument expression, then only
3166-
// do the borrow if the storage is non-local.
3167-
// FIXME: I don't have a principled reason for why this matters and hope that
3168-
// we can fix the AST we're working with.
3169-
if (!sawLoad && storage->getDeclContext()->isLocalContext())
3170-
return nullptr;
3172+
return nullptr;
31713173

31723174
// Claim the value of this argument since we found a storage reference that
31733175
// has a move only base.

lib/SILGen/SILGenLValue.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
29182918
return m->getType()->isPureMoveOnly() ||
29192919
m->getBase()->getType()->isPureMoveOnly();
29202920
}
2921+
if (auto *d = dyn_cast<DeclRefExpr>(e))
2922+
return e->getType()->isPureMoveOnly();
29212923
return false;
29222924
}
29232925

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@
280280
using namespace swift;
281281
using namespace swift::siloptimizer;
282282

283+
#pragma clang optimize off
284+
283285
llvm::cl::opt<bool> DisableMoveOnlyAddressCheckerLifetimeExtension(
284286
"move-only-address-checker-disable-lifetime-extension",
285287
llvm::cl::init(false),
@@ -342,7 +344,7 @@ static void convertMemoryReinitToInitForm(SILInstruction *memInst,
342344
break;
343345
}
344346
}
345-
347+
346348
// Insert a new debug_value instruction after the reinitialization, so that
347349
// the debugger knows that the variable is in a usable form again.
348350
insertDebugValueBefore(memInst->getNextInstruction(), debugVar,
@@ -931,6 +933,7 @@ void UseState::initializeLiveness(
931933
// We begin by initializing all of our init uses.
932934
for (auto initInstAndValue : initInsts) {
933935
LLVM_DEBUG(llvm::dbgs() << "Found def: " << *initInstAndValue.first);
936+
934937
liveness.initializeDef(initInstAndValue.first, initInstAndValue.second);
935938
}
936939

@@ -944,7 +947,7 @@ void UseState::initializeLiveness(
944947
reinitInstAndValue.second);
945948
}
946949
}
947-
950+
948951
// Then check if our markedValue is from an argument that is in,
949952
// in_guaranteed, inout, or inout_aliasable, consider the marked address to be
950953
// the initialization point.
@@ -1050,6 +1053,26 @@ void UseState::initializeLiveness(
10501053
LLVM_DEBUG(llvm::dbgs() << "Liveness with just inits:\n";
10511054
liveness.print(llvm::dbgs()));
10521055

1056+
for (auto initInstAndValue : initInsts) {
1057+
// If our init inst is a store_borrow, treat the end_borrow as liveness
1058+
// uses.
1059+
//
1060+
// NOTE: We do not need to check for access scopes here since store_borrow
1061+
// can only apply to alloc_stack today.
1062+
if (auto *sbi = dyn_cast<StoreBorrowInst>(initInstAndValue.first)) {
1063+
// We can only store_borrow if our mark_must_check is a
1064+
// no_consume_or_assign.
1065+
assert(address->getCheckKind() ==
1066+
MarkMustCheckInst::CheckKind::NoConsumeOrAssign &&
1067+
"store_borrow implies no_consume_or_assign since we cannot "
1068+
"consume a borrowed inited value");
1069+
for (auto *ebi : sbi->getEndBorrows()) {
1070+
liveness.updateForUse(ebi, initInstAndValue.second,
1071+
false /*lifetime ending*/);
1072+
}
1073+
}
1074+
}
1075+
10531076
// Now at this point, we have defined all of our defs so we can start adding
10541077
// uses to the liveness.
10551078
for (auto reinitInstAndValue : reinitInsts) {
@@ -1979,6 +2002,22 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
19792002
if (isa<EndAccessInst>(user))
19802003
return true;
19812004

2005+
// This visitor looks through store_borrow instructions but does visit the
2006+
// end_borrow of the store_borrow. If we see such an end_borrow, register the
2007+
// store_borrow instead. Since we use sets, if we visit multiple end_borrows,
2008+
// we will only record the store_borrow once.
2009+
if (auto *ebi = dyn_cast<EndBorrowInst>(user)) {
2010+
if (auto *sbi = dyn_cast<StoreBorrowInst>(ebi->getOperand())) {
2011+
LLVM_DEBUG(llvm::dbgs() << "Found store_borrow: " << *sbi);
2012+
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
2013+
if (!leafRange)
2014+
return false;
2015+
2016+
useState.recordInitUse(user, op->get(), *leafRange);
2017+
return true;
2018+
}
2019+
}
2020+
19822021
if (auto *di = dyn_cast<DebugValueInst>(user)) {
19832022
// Save the debug_value if it is attached directly to this mark_must_check.
19842023
// If the underlying storage we're checking is immutable, then the access

lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ bool noncopyable::memInstMustInitialize(Operand *memOper) {
220220
case SILInstructionKind::Store##Name##Inst: \
221221
return cast<Store##Name##Inst>(memInst)->isInitializationOfDest();
222222
#include "swift/AST/ReferenceStorage.def"
223+
224+
case SILInstructionKind::StoreBorrowInst:
225+
return true;
223226
}
224227
}
225228

test/SILGen/moveonly.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,10 @@ func enumSwitchTest1(_ e: borrowing EnumSwitchTests.E) {
818818
//
819819
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly9letGlobalAA16NonTrivialStructVvp :
820820
// CHECK: [[MARKED_GLOBAL:%.*]] = mark_must_check [no_consume_or_assign] [[GLOBAL]]
821-
// FIXME: this copy probably shouldn't be here when accessing through the letGlobal, but maybe it's cleaned up?
822-
// CHECK: [[LOADED_VAL:%.*]] = load [copy] [[MARKED_GLOBAL]] : $*NonTrivialStruct
823-
// CHECK: [[LOADED_BORROWED_VAL:%.*]] = begin_borrow [[LOADED_VAL]]
824-
// CHECK: [[LOADED_GEP:%.*]] = struct_extract [[LOADED_BORROWED_VAL]] : $NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
821+
// CHECK: [[LOADED_VAL:%.*]] = load_borrow [[MARKED_GLOBAL]] : $*NonTrivialStruct
822+
// CHECK: [[LOADED_GEP:%.*]] = struct_extract [[LOADED_VAL]] : $NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
825823
// CHECK: apply {{%.*}}([[LOADED_GEP]])
826-
// CHECK: end_borrow [[LOADED_BORROWED_VAL]]
827-
// CHECK: destroy_value [[LOADED_VAL]]
824+
// CHECK: end_borrow [[LOADED_VAL]]
828825
// CHECK: } // end sil function '$s8moveonly16testGlobalBorrowyyF'
829826
func testGlobalBorrow() {
830827
borrowVal(varGlobal)
@@ -856,13 +853,11 @@ func testGlobalBorrow() {
856853
//
857854
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly9letGlobalAA16NonTrivialStructVvp :
858855
// CHECK: [[MARKED_GLOBAL:%.*]] = mark_must_check [no_consume_or_assign] [[GLOBAL]]
859-
// CHECK: [[LOADED_VAL:%.*]] = load [copy] [[MARKED_GLOBAL]]
860-
// CHECK: [[LOADED_BORROWED_VAL:%.*]] = begin_borrow [[LOADED_VAL]]
861-
// CHECK: [[LOADED_GEP:%.*]] = struct_extract [[LOADED_BORROWED_VAL]]
856+
// CHECK: [[LOADED_VAL:%.*]] = load_borrow [[MARKED_GLOBAL]]
857+
// CHECK: [[LOADED_GEP:%.*]] = struct_extract [[LOADED_VAL]]
862858
// CHECK: [[LOADED_GEP_COPY:%.*]] = copy_value [[LOADED_GEP]]
863-
// CHECK: end_borrow [[LOADED_BORROWED_VAL]]
864-
// CHECK: destroy_value [[LOADED_VAL]]
865859
// CHECK: apply {{%.*}}([[LOADED_GEP_COPY]])
860+
// CHECK: end_borrow [[LOADED_VAL]]
866861
//
867862
// CHECK: } // end sil function '$s8moveonly17testGlobalConsumeyyF'
868863
func testGlobalConsume() {
@@ -1833,11 +1828,8 @@ public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Var() {
18331828
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]]
18341829
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
18351830
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
1836-
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
1837-
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[TEMP]]
1831+
// CHECK: apply {{%.*}}([[CORO_RESULT]])
18381832
// CHECK: end_apply [[CORO_TOKEN]]
1839-
// CHECK: apply {{%.*}}([[TEMP]])
1840-
// CHECK: destroy_addr [[TEMP]]
18411833
// CHECK: end_borrow [[LOAD_BORROW]]
18421834
// CHECK: } // end sil function '$s8moveonly58testSubscriptReadModify_BaseLoadable_ResultAddressOnly_LetyyF'
18431835
public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Let() {

test/SILOptimizer/moveonly_addresschecker.sil

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,3 +844,18 @@ bb0(%0 : $Int, %1a : $*NonCopyableNativeObjectPair):
844844
%16 = tuple ()
845845
return %16 : $()
846846
}
847+
848+
sil [ossa] @testSupportStoreBorrow : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
849+
bb0(%0 : @guaranteed $NonTrivialStruct):
850+
%1 = alloc_stack $NonTrivialStruct
851+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
852+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
853+
%f = function_ref @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
854+
%l = load_borrow %borrow : $*NonTrivialStruct
855+
apply %f(%l) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
856+
end_borrow %l : $NonTrivialStruct
857+
end_borrow %borrow : $*NonTrivialStruct
858+
dealloc_stack %1 : $*NonTrivialStruct
859+
%9999 = tuple ()
860+
return %9999 : $()
861+
}

test/SILOptimizer/moveonly_addresschecker_diagnostics.sil

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// RUN: %target-sil-opt -sil-move-only-address-checker -enable-experimental-feature MoveOnlyPartialConsumption -enable-experimental-feature MoveOnlyClasses -enable-sil-verify-all %s -verify
22
// RUN: %target-sil-opt -sil-move-only-address-checker -enable-experimental-feature MoveOnlyPartialConsumption -enable-experimental-feature MoveOnlyClasses -enable-sil-verify-all -move-only-diagnostics-silently-emit-diagnostics %s | %FileCheck %s
33

4-
// TODO: Add FileCheck
5-
64
// This file contains specific SIL test cases that we expect to emit
75
// diagnostics. These are cases where we want to make it easy to validate
86
// independent of potential changes in the frontend's emission that this
@@ -77,6 +75,7 @@ sil @get_aggstruct : $@convention(thin) () -> @owned AggStruct
7775
sil @nonConsumingUseKlass : $@convention(thin) (@guaranteed Klass) -> ()
7876
sil @nonConsumingUseNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
7977
sil @consumingUseNonTrivialStruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
78+
sil @inUseNonTrivialStruct : $@convention(thin) (@in NonTrivialStruct) -> ()
8079
sil @classConsume : $@convention(thin) (@owned Klass) -> () // user: %18
8180
sil @copyableClassConsume : $@convention(thin) (@owned CopyableKlass) -> () // user: %24
8281
sil @copyableClassUseMoveOnlyWithoutEscaping : $@convention(thin) (@guaranteed CopyableKlass) -> () // user: %16
@@ -529,3 +528,115 @@ bb0(%0 : @owned $NonTrivialStruct):
529528
%9999 = tuple()
530529
return %9999 : $()
531530
}
531+
532+
// CHECK-LABEL: sil [ossa] @testSupportStoreBorrow1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
533+
// CHECK: bb0([[ARG:%.*]] : @guaranteed
534+
// CHECK: [[STACK:%.*]] = alloc_stack
535+
// CHECK: [[BORROW:%.*]] = store_borrow [[ARG]] to [[STACK]]
536+
// CHECK: [[LOAD:%.*]] = load_borrow [[BORROW]]
537+
// CHECK: apply {{%.*}}([[LOAD]])
538+
// CHECK: end_borrow [[LOAD]]
539+
// CHECK: end_borrow [[BORROW]]
540+
// CHECK: dealloc_stack [[STACK]]
541+
// CHECK: } // end sil function 'testSupportStoreBorrow1'
542+
sil [ossa] @testSupportStoreBorrow1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
543+
bb0(%0 : @guaranteed $NonTrivialStruct):
544+
%1 = alloc_stack $NonTrivialStruct
545+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
546+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
547+
%f = function_ref @nonConsumingUseNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
548+
%l = load_borrow %borrow : $*NonTrivialStruct
549+
apply %f(%l) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
550+
end_borrow %l : $NonTrivialStruct
551+
end_borrow %borrow : $*NonTrivialStruct
552+
dealloc_stack %1 : $*NonTrivialStruct
553+
%9999 = tuple ()
554+
return %9999 : $()
555+
}
556+
557+
// CHECK-LABEL: sil [ossa] @testSupportStoreBorrow2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
558+
// CHECK: bb0([[ARG:%.*]] : @guaranteed
559+
// CHECK: [[STACK:%.*]] = alloc_stack
560+
// CHECK: [[BORROW:%.*]] = store_borrow [[ARG]] to [[STACK]]
561+
// CHECK: [[LOAD:%.*]] = load_borrow [[BORROW]]
562+
// CHECK: apply {{%.*}}([[LOAD]])
563+
// CHECK: end_borrow [[LOAD]]
564+
// CHECK: end_borrow [[BORROW]]
565+
// CHECK: dealloc_stack [[STACK]]
566+
// CHECK: } // end sil function 'testSupportStoreBorrow2'
567+
sil [ossa] @testSupportStoreBorrow2 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
568+
bb0(%0 : @guaranteed $NonTrivialStruct):
569+
%1 = alloc_stack $NonTrivialStruct
570+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
571+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
572+
%f = function_ref @nonConsumingUseNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
573+
%l = load [copy] %borrow : $*NonTrivialStruct
574+
apply %f(%l) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
575+
destroy_value %l : $NonTrivialStruct
576+
end_borrow %borrow : $*NonTrivialStruct
577+
dealloc_stack %1 : $*NonTrivialStruct
578+
%9999 = tuple ()
579+
return %9999 : $()
580+
}
581+
582+
// CHECK-LABEL: sil [ossa] @testSupportStoreBorrow3 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
583+
// CHECK: bb0([[ARG:%.*]] : @guaranteed
584+
// CHECK: [[STACK:%.*]] = alloc_stack
585+
// CHECK: [[BORROW:%.*]] = store_borrow [[ARG]] to [[STACK]]
586+
// CHECK: [[LOAD:%.*]] = load_borrow [[BORROW]]
587+
// CHECK: apply {{%.*}}([[LOAD]])
588+
// CHECK: end_borrow [[LOAD]]
589+
// CHECK: end_borrow [[BORROW]]
590+
// CHECK: dealloc_stack [[STACK]]
591+
// CHECK: } // end sil function 'testSupportStoreBorrow3'
592+
sil [ossa] @testSupportStoreBorrow3 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
593+
bb0(%0 : @guaranteed $NonTrivialStruct):
594+
%1 = alloc_stack $NonTrivialStruct
595+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
596+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
597+
%f = function_ref @nonConsumingUseNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
598+
%l = load_borrow %borrow : $*NonTrivialStruct
599+
%l2 = copy_value %l : $NonTrivialStruct
600+
apply %f(%l2) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
601+
destroy_value %l2 : $NonTrivialStruct
602+
end_borrow %l : $NonTrivialStruct
603+
end_borrow %borrow : $*NonTrivialStruct
604+
dealloc_stack %1 : $*NonTrivialStruct
605+
%9999 = tuple ()
606+
return %9999 : $()
607+
}
608+
609+
sil [ossa] @testSupportStoreBorrow4 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
610+
bb0(%0 : @guaranteed $NonTrivialStruct):
611+
%1 = alloc_stack $NonTrivialStruct
612+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
613+
// expected-error @-1 {{noncopyable 'unknown' cannot be consumed when captured by an escaping closure}}
614+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
615+
%f = function_ref @consumingUseNonTrivialStruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
616+
%l = load_borrow %borrow : $*NonTrivialStruct
617+
%l2 = copy_value %l : $NonTrivialStruct
618+
apply %f(%l2) : $@convention(thin) (@owned NonTrivialStruct) -> ()
619+
end_borrow %l : $NonTrivialStruct
620+
end_borrow %borrow : $*NonTrivialStruct
621+
dealloc_stack %1 : $*NonTrivialStruct
622+
%9999 = tuple ()
623+
return %9999 : $()
624+
}
625+
626+
sil [ossa] @testSupportStoreBorrow5 : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
627+
bb0(%0 : @guaranteed $NonTrivialStruct):
628+
%1 = alloc_stack $NonTrivialStruct
629+
%1a = mark_must_check [no_consume_or_assign] %1 : $*NonTrivialStruct
630+
// expected-error @-1 {{'unknown' is borrowed and cannot be consumed}}
631+
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
632+
%f = function_ref @consumingUseNonTrivialStruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
633+
%a = alloc_stack $NonTrivialStruct
634+
copy_addr %borrow to [init] %a : $*NonTrivialStruct
635+
// expected-note @-1 {{consumed here}}
636+
destroy_addr %a : $*NonTrivialStruct
637+
dealloc_stack %a : $*NonTrivialStruct
638+
end_borrow %borrow : $*NonTrivialStruct
639+
dealloc_stack %1 : $*NonTrivialStruct
640+
%9999 = tuple ()
641+
return %9999 : $()
642+
}

test/SILOptimizer/moveonly_addressonly_subscript_diagnostics.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Var() {
203203
public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_Let() {
204204
let m = LoadableSubscriptReadModifyTester()
205205
m[0].nonMutatingFunc()
206-
// expected-error @-1 {{copy of noncopyable typed value}}
207206
}
208207

209208
public func testSubscriptReadModify_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadModifyTester) {

0 commit comments

Comments
 (0)