Skip to content

Commit b2fe8dc

Browse files
committed
[move-only] Fix class setters of address only move only types.
We were not properly propagating along cleanups in SILGenProlog. I went through SILGenProlog and fixed this. rdar://109287977 (cherry picked from commit 42b4b9a)
1 parent 86dd40f commit b2fe8dc

File tree

5 files changed

+103
-73
lines changed

5 files changed

+103
-73
lines changed

lib/SILGen/SILGenBuilder.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -980,11 +980,12 @@ ManagedValue SILGenBuilder::createBeginBorrow(SILLocation loc,
980980
return ManagedValue::forUnmanaged(newValue);
981981
}
982982

983-
ManagedValue SILGenBuilder::createMoveValue(SILLocation loc,
984-
ManagedValue value) {
983+
ManagedValue SILGenBuilder::createMoveValue(SILLocation loc, ManagedValue value,
984+
bool isLexical) {
985985
assert(value.isPlusOne(SGF) && "Must be +1 to be moved!");
986986
CleanupCloner cloner(*this, value);
987-
auto *mdi = createMoveValue(loc, value.forward(getSILGenFunction()));
987+
auto *mdi =
988+
createMoveValue(loc, value.forward(getSILGenFunction()), isLexical);
988989
return cloner.clone(mdi);
989990
}
990991

@@ -1027,8 +1028,9 @@ ManagedValue SILGenBuilder::createGuaranteedCopyableToMoveOnlyWrapperValue(
10271028
ManagedValue
10281029
SILGenBuilder::createMarkMustCheckInst(SILLocation loc, ManagedValue value,
10291030
MarkMustCheckInst::CheckKind kind) {
1030-
assert((value.isPlusOne(SGF) || value.isLValue()) &&
1031-
"Argument must be at +1 or be an inout!");
1031+
assert((value.isPlusOne(SGF) || value.isLValue() ||
1032+
value.getType().isAddress()) &&
1033+
"Argument must be at +1 or be an address!");
10321034
CleanupCloner cloner(*this, value);
10331035
auto *mdi = SILBuilder::createMarkMustCheckInst(
10341036
loc, value.forward(getSILGenFunction()), kind);

lib/SILGen/SILGenBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ class SILGenBuilder : public SILBuilder {
441441
bool isLexical = false);
442442

443443
using SILBuilder::createMoveValue;
444-
ManagedValue createMoveValue(SILLocation loc, ManagedValue value);
444+
ManagedValue createMoveValue(SILLocation loc, ManagedValue value,
445+
bool isLexical = false);
445446

446447
using SILBuilder::createOwnedMoveOnlyWrapperToCopyableValue;
447448
ManagedValue createOwnedMoveOnlyWrapperToCopyableValue(SILLocation loc,

lib/SILGen/SILGenProlog.cpp

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -631,23 +631,23 @@ class ArgumentInitHelper {
631631
}
632632

633633
void updateArgumentValueForBinding(ManagedValue argrv, SILLocation loc,
634-
ParamDecl *pd, SILValue value,
634+
ParamDecl *pd,
635635
const SILDebugVariable &varinfo) {
636636
bool calledCompletedUpdate = false;
637637
SWIFT_DEFER {
638638
assert(calledCompletedUpdate && "Forgot to call completed update along "
639639
"all paths or manually turn it off");
640640
};
641-
auto completeUpdate = [&](SILValue value) -> void {
642-
SGF.B.createDebugValue(loc, value, varinfo);
643-
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
641+
auto completeUpdate = [&](ManagedValue value) -> void {
642+
SGF.B.createDebugValue(loc, value.getValue(), varinfo);
643+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value.getValue());
644644
calledCompletedUpdate = true;
645645
};
646646

647647
// If we do not need to support lexical lifetimes, just return value as the
648648
// updated value.
649649
if (!SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule()))
650-
return completeUpdate(value);
650+
return completeUpdate(argrv);
651651

652652
// Look for the following annotations on the function argument:
653653
// - @noImplicitCopy
@@ -659,15 +659,15 @@ class ArgumentInitHelper {
659659
// we need to use copyable to move only to convert it to its move only
660660
// form.
661661
if (!isNoImplicitCopy) {
662-
if (!value->getType().isMoveOnly()) {
662+
if (!argrv.getType().isMoveOnly()) {
663663
// Follow the normal path. The value's lifetime will be enforced based
664664
// on its ownership.
665-
return completeUpdate(value);
665+
return completeUpdate(argrv);
666666
}
667667

668668
// At this point, we have a noncopyable type. If it is owned, create an
669669
// alloc_box for it.
670-
if (value->getOwnershipKind() == OwnershipKind::Owned) {
670+
if (argrv.getOwnershipKind() == OwnershipKind::Owned) {
671671
// TODO: Once owned values are mutable, this needs to become mutable.
672672
auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture(
673673
pd,
@@ -696,17 +696,18 @@ class ArgumentInitHelper {
696696
// misleading consuming message. We still are able to pass it to
697697
// non-escaping closures though since the onstack partial_apply does not
698698
// consume the value.
699-
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
700-
value = SGF.B.createCopyValue(loc, value);
701-
value = SGF.B.createMarkMustCheckInst(
702-
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
703-
SGF.emitManagedRValueWithCleanup(value);
704-
return completeUpdate(value);
699+
assert(argrv.getOwnershipKind() == OwnershipKind::Guaranteed);
700+
argrv = argrv.copy(SGF, loc);
701+
argrv = SGF.B.createMarkMustCheckInst(
702+
loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
703+
return completeUpdate(argrv);
705704
}
706705

707-
if (value->getType().isTrivial(SGF.F)) {
708-
value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(loc, value);
709-
value = SGF.B.createMoveValue(loc, value, /*isLexical=*/true);
706+
if (argrv.getType().isTrivial(SGF.F)) {
707+
SILValue value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(
708+
loc, argrv.getValue());
709+
argrv = SGF.emitManagedRValueWithCleanup(value);
710+
argrv = SGF.B.createMoveValue(loc, argrv, /*isLexical=*/true);
710711

711712
// If our argument was owned, we use no implicit copy. Otherwise, we
712713
// use no copy.
@@ -723,40 +724,35 @@ class ArgumentInitHelper {
723724
break;
724725
}
725726

726-
value = SGF.B.createMarkMustCheckInst(loc, value, kind);
727-
SGF.emitManagedRValueWithCleanup(value);
728-
return completeUpdate(value);
727+
argrv = SGF.B.createMarkMustCheckInst(loc, argrv, kind);
728+
return completeUpdate(argrv);
729729
}
730730

731-
if (value->getOwnershipKind() == OwnershipKind::Guaranteed) {
732-
value = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(loc, value);
733-
value = SGF.B.createCopyValue(loc, value);
734-
value = SGF.B.createMarkMustCheckInst(
735-
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
736-
SGF.emitManagedRValueWithCleanup(value);
737-
return completeUpdate(value);
731+
if (argrv.getOwnershipKind() == OwnershipKind::Guaranteed) {
732+
argrv = SGF.B.createGuaranteedCopyableToMoveOnlyWrapperValue(loc, argrv);
733+
argrv = argrv.copy(SGF, loc);
734+
argrv = SGF.B.createMarkMustCheckInst(
735+
loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
736+
return completeUpdate(argrv);
738737
}
739738

740-
if (value->getOwnershipKind() == OwnershipKind::Owned) {
739+
if (argrv.getOwnershipKind() == OwnershipKind::Owned) {
741740
// If we have an owned value, forward it into the mark_must_check to
742741
// avoid an extra destroy_value.
743-
value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(
744-
loc, argrv.forward(SGF));
745-
value = SGF.B.createMoveValue(loc, value, true /*is lexical*/);
746-
value = SGF.B.createMarkMustCheckInst(
747-
loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
748-
SGF.emitManagedRValueWithCleanup(value);
749-
return completeUpdate(value);
742+
argrv = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(loc, argrv);
743+
argrv = SGF.B.createMoveValue(loc, argrv, true /*is lexical*/);
744+
argrv = SGF.B.createMarkMustCheckInst(
745+
loc, argrv, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
746+
return completeUpdate(argrv);
750747
}
751748

752-
return completeUpdate(value);
749+
return completeUpdate(argrv);
753750
}
754751

755752
/// Create a SILArgument and store its value into the given Initialization,
756753
/// if not null.
757754
void makeArgumentIntoBinding(SILLocation loc, ParamDecl *pd) {
758755
ManagedValue argrv = makeArgument(loc, pd);
759-
SILValue value = argrv.getValue();
760756
if (pd->isInOut()) {
761757
assert(argrv.getType().isAddress() && "expected inout to be address");
762758
} else if (!pd->isImmutableInFunctionBody()) {
@@ -774,33 +770,34 @@ class ArgumentInitHelper {
774770
SILDebugVariable varinfo(pd->isImmutableInFunctionBody(), ArgNo);
775771
if (!argrv.getType().isAddress()) {
776772
// NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding.
777-
updateArgumentValueForBinding(argrv, loc, pd, value, varinfo);
773+
updateArgumentValueForBinding(argrv, loc, pd, varinfo);
778774
return;
779775
}
780776

781-
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
777+
if (auto *allocStack = dyn_cast<AllocStackInst>(argrv.getValue())) {
782778
allocStack->setArgNo(ArgNo);
783779
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
784780
SGF.getModule()) &&
785-
SGF.F.getLifetime(pd, value->getType()).isLexical())
781+
SGF.F.getLifetime(pd, allocStack->getType()).isLexical())
786782
allocStack->setIsLexical();
787-
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
783+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(allocStack);
788784
return;
789785
}
790786

791-
SILValue debugOperand = value;
792-
if (value->getType().isMoveOnly()) {
787+
SILValue debugOperand = argrv.getValue();
788+
789+
if (argrv.getType().isMoveOnly()) {
793790
switch (pd->getValueOwnership()) {
794791
case ValueOwnership::Default:
795792
if (pd->isSelfParameter()) {
796-
assert(!isa<MarkMustCheckInst>(value) &&
793+
assert(!isa<MarkMustCheckInst>(argrv.getValue()) &&
797794
"Should not have inserted mark must check inst in EmitBBArgs");
798795
if (!pd->isInOut()) {
799-
value = SGF.B.createMarkMustCheckInst(
800-
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
796+
argrv = SGF.B.createMarkMustCheckInst(
797+
loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
801798
}
802799
} else {
803-
if (auto *fArg = dyn_cast<SILFunctionArgument>(value)) {
800+
if (auto *fArg = dyn_cast<SILFunctionArgument>(argrv.getValue())) {
804801
switch (fArg->getArgumentConvention()) {
805802
case SILArgumentConvention::Direct_Guaranteed:
806803
case SILArgumentConvention::Direct_Owned:
@@ -814,51 +811,51 @@ class ArgumentInitHelper {
814811
case SILArgumentConvention::Pack_Out:
815812
llvm_unreachable("Should have been handled elsewhere");
816813
case SILArgumentConvention::Indirect_In:
817-
value = SGF.B.createMarkMustCheckInst(
818-
loc, value,
814+
argrv = SGF.B.createMarkMustCheckInst(
815+
loc, argrv,
819816
MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
820817
break;
821818
case SILArgumentConvention::Indirect_In_Guaranteed:
822-
value = SGF.B.createMarkMustCheckInst(
823-
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
819+
argrv = SGF.B.createMarkMustCheckInst(
820+
loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
824821
}
825822
} else {
826-
assert(isa<MarkMustCheckInst>(value) &&
823+
assert(isa<MarkMustCheckInst>(argrv.getValue()) &&
827824
"Should have inserted mark must check inst in EmitBBArgs");
828825
}
829826
}
830827
break;
831828
case ValueOwnership::InOut: {
832-
assert(isa<MarkMustCheckInst>(value)
833-
&& "Expected mark must check inst with inout to be handled in "
834-
"emitBBArgs earlier");
835-
auto mark = cast<MarkMustCheckInst>(value);
829+
assert(isa<MarkMustCheckInst>(argrv.getValue()) &&
830+
"Expected mark must check inst with inout to be handled in "
831+
"emitBBArgs earlier");
832+
auto mark = cast<MarkMustCheckInst>(argrv.getValue());
836833
debugOperand = mark->getOperand();
837834
break;
838835
}
839836
case ValueOwnership::Owned:
840-
value = SGF.B.createMarkMustCheckInst(
841-
loc, value, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
837+
argrv = SGF.B.createMarkMustCheckInst(
838+
loc, argrv, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
842839
break;
843840
case ValueOwnership::Shared:
844-
value = SGF.B.createMarkMustCheckInst(
845-
loc, value, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
841+
argrv = SGF.B.createMarkMustCheckInst(
842+
loc, argrv, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
846843
break;
847844
}
848845
}
849846

850847
DebugValueInst *debugInst
851848
= SGF.B.createDebugValueAddr(loc, debugOperand, varinfo);
852-
853-
if (value != debugOperand) {
854-
if (auto valueInst = dyn_cast<MarkMustCheckInst>(value)) {
849+
850+
if (argrv.getValue() != debugOperand) {
851+
if (auto valueInst = dyn_cast<MarkMustCheckInst>(argrv.getValue())) {
855852
// Move the debug instruction outside of any marker instruction that might
856853
// have been applied to the value, so that analysis doesn't move the
857854
// debug_value anywhere it shouldn't be.
858855
debugInst->moveBefore(valueInst);
859856
}
860857
}
861-
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
858+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(argrv.getValue());
862859
}
863860

864861
void emitParam(ParamDecl *PD) {

test/SILGen/moveonly.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -988,9 +988,9 @@ func testConditionallyInitializedLet() {
988988
consumeVal(x)
989989
}
990990

991-
/////////////////////////////
992-
// MARK: AddressOnlySetter //
993-
/////////////////////////////
991+
////////////////////////
992+
// MARK: Setter Tests //
993+
////////////////////////
994994

995995
struct AddressOnlySetterTester : ~Copyable {
996996
var a: AddressOnlyProtocol {
@@ -1005,6 +1005,24 @@ struct AddressOnlySetterTester : ~Copyable {
10051005
}
10061006
}
10071007

1008+
public class NonFinalClassTest {
1009+
// CHECK: sil hidden [transparent] [ossa] @$s8moveonly17NonFinalClassTestC1xAA19AddressOnlyProtocolVvs : $@convention(method) (@in AddressOnlyProtocol, @guaranteed NonFinalClassTest) -> () {
1010+
// CHECK: bb0([[INPUT:%.*]] : $*AddressOnlyProtocol, [[SELF:%.*]] : @guaranteed
1011+
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[INPUT]]
1012+
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
1013+
// CHECK: copy_addr [[MARK]] to [init] [[TEMP]]
1014+
// CHECK: [[REF:%.*]] = ref_element_addr [[SELF]]
1015+
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[REF]]
1016+
// CHECK: [[MARK2:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
1017+
// CHECK: copy_addr [take] [[TEMP]] to [[MARK2]]
1018+
// CHECK: end_access [[ACCESS]]
1019+
// CHECK: dealloc_stack [[TEMP]]
1020+
// CHECK: destroy_addr [[MARK]]
1021+
// CHECK: } // end sil function '$s8moveonly17NonFinalClassTestC1xAA19AddressOnlyProtocolVvs'
1022+
var x: AddressOnlyProtocol
1023+
init(y: consuming AddressOnlyProtocol) { self.x = y }
1024+
}
1025+
10081026
/////////////////////
10091027
// MARK: Subscript //
10101028
/////////////////////
@@ -3071,3 +3089,4 @@ public func testSubscriptGetModifyThroughParentClass_BaseLoadable_ResultAddressO
30713089
m.computedTester2[0].nonMutatingFunc()
30723090
m.computedTester2[0].mutatingFunc()
30733091
}
3092+

test/SILOptimizer/moveonly_addresschecker_diagnostics.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4486,3 +4486,14 @@ func testMyEnum() {
44864486
_ = consume x // expected-note {{consumed again here}}
44874487
}
44884488
}
4489+
4490+
////////////////////////
4491+
// MARK: Setter Tests //
4492+
////////////////////////
4493+
4494+
public class NonFinalCopyableKlassWithMoveOnlyField {
4495+
var moveOnlyVarStruct = NonTrivialStruct()
4496+
let moveOnlyLetStruct = NonTrivialStruct()
4497+
var moveOnlyVarProt = AddressOnlyProtocol()
4498+
let moveOnlyLetProt = AddressOnlyProtocol()
4499+
}

0 commit comments

Comments
 (0)