Skip to content

Commit 2860a0d

Browse files
authored
Merge pull request swiftlang#40789 from gottesmm/pr-c08df4932418337dc441a39a68c787e659dcb6ec
[move-function] Make sure we error if code reinitializes a var's fields separately instead of the var all at once.
2 parents 91966de + 7059fea commit 2860a0d

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,12 +917,26 @@ bool GatherClosureUseVisitor::visitUse(Operand *op, AccessUseType useTy) {
917917
return true;
918918

919919
if (memInstMustInitialize(op)) {
920+
if (stripAccessMarkers(op->get()) != useState.address) {
921+
LLVM_DEBUG(llvm::dbgs()
922+
<< "!!! Error! Found init use not on base address: "
923+
<< *op->getUser());
924+
return false;
925+
}
926+
920927
LLVM_DEBUG(llvm::dbgs() << "ClosureUse: Found init: " << *op->getUser());
921928
useState.inits.insert(op->getUser());
922929
return true;
923930
}
924931

925932
if (memInstMustReinitialize(op)) {
933+
if (stripAccessMarkers(op->get()) != useState.address) {
934+
LLVM_DEBUG(llvm::dbgs()
935+
<< "!!! Error! Found reinit use not on base address: "
936+
<< *op->getUser());
937+
return false;
938+
}
939+
926940
LLVM_DEBUG(llvm::dbgs() << "ClosureUse: Found reinit: " << *op->getUser());
927941
useState.insertReinit(op->getUser());
928942
return true;
@@ -1279,12 +1293,26 @@ bool GatherLexicalLifetimeUseVisitor::visitUse(Operand *op,
12791293
}
12801294

12811295
if (memInstMustInitialize(op)) {
1296+
if (stripAccessMarkers(op->get()) != useState.address) {
1297+
LLVM_DEBUG(llvm::dbgs()
1298+
<< "!!! Error! Found init use not on base address: "
1299+
<< *op->getUser());
1300+
return false;
1301+
}
1302+
12821303
LLVM_DEBUG(llvm::dbgs() << "Found init: " << *op->getUser());
12831304
useState.inits.insert(op->getUser());
12841305
return true;
12851306
}
12861307

12871308
if (memInstMustReinitialize(op)) {
1309+
if (stripAccessMarkers(op->get()) != useState.address) {
1310+
LLVM_DEBUG(llvm::dbgs()
1311+
<< "!!! Error! Found reinit use not on base address: "
1312+
<< *op->getUser());
1313+
return false;
1314+
}
1315+
12881316
LLVM_DEBUG(llvm::dbgs() << "Found reinit: " << *op->getUser());
12891317
useState.insertReinit(op->getUser());
12901318
return true;
@@ -1308,6 +1336,14 @@ bool GatherLexicalLifetimeUseVisitor::visitUse(Operand *op,
13081336
// are going to try and extend move checking into the partial apply using
13091337
// cloning to eliminate destroys or reinits.
13101338
if (auto fas = FullApplySite::isa(op->getUser())) {
1339+
if (stripAccessMarkers(op->get()) != useState.address) {
1340+
LLVM_DEBUG(
1341+
llvm::dbgs()
1342+
<< "!!! Error! Found consuming closure use not on base address: "
1343+
<< *op->getUser());
1344+
return false;
1345+
}
1346+
13111347
if (fas.getArgumentOperandConvention(*op) ==
13121348
SILArgumentConvention::Indirect_InoutAliasable) {
13131349
// If we don't find the function, we can't handle this, so bail.

test/SILOptimizer/move_function_kills_copyable_addressonly_vars.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,62 @@ extension MiscTests {
631631
}
632632
}
633633

634+
//////////////////////////////////
635+
// Multiple Captures from Defer //
636+
//////////////////////////////////
637+
638+
func multipleCapture1<T : P>(_ k: T) -> () {
639+
let kType = type(of: k)
640+
var k2 = k
641+
var k3 = k
642+
let _ = _move(k2)
643+
let _ = _move(k3)
644+
var k4 = k
645+
k4 = k
646+
defer {
647+
k2 = kType.getP()
648+
print(k4)
649+
k3 = kType.getP()
650+
}
651+
print("foo bar")
652+
}
653+
654+
func multipleCapture2<T : P>(_ k: T) -> () {
655+
let kType = type(of: k)
656+
var k2 = k // expected-error {{'k2' used after being moved}}
657+
k2 = k
658+
var k3 = k
659+
let _ = _move(k2) // expected-note {{move here}}
660+
let _ = _move(k3)
661+
var k4 = k
662+
k4 = k
663+
defer {
664+
print(k2) // expected-note {{use here}}
665+
print(k4)
666+
k3 = kType.getP()
667+
}
668+
print("foo bar")
669+
}
670+
671+
//////////////////////
672+
// Reinit in pieces //
673+
//////////////////////
674+
675+
// These tests exercise the diagnostic to see how we error if we re-initialize a
676+
// var in pieces. Eventually we should teach either this diagnostic pass how to
677+
// handle this or teach DI how to combine the initializations into one large
678+
// reinit.
679+
struct ProtPair<T : P> {
680+
var lhs: T
681+
var rhs: T
682+
}
683+
684+
func reinitInPieces1<T : P>(_ k: ProtPair<T>) {
685+
let selfType = type(of: k.lhs)
686+
var k2 = k
687+
k2 = k
688+
689+
let _ = _move(k2) // expected-error {{_move applied to value that the compiler does not support checking}}
690+
k2.lhs = selfType.getP()
691+
k2.rhs = selfType.getP()
692+
}

test/SILOptimizer/move_function_kills_copyable_loadable_vars.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,3 +674,60 @@ extension KlassWrapper {
674674
print("foo bar")
675675
}
676676
}
677+
678+
//////////////////////////////////
679+
// Multiple Captures from Defer //
680+
//////////////////////////////////
681+
682+
func multipleCapture1(_ k: Klass) -> () {
683+
var k2 = k
684+
var k3 = k
685+
let _ = _move(k2)
686+
let _ = _move(k3)
687+
var k4 = k
688+
k4 = k
689+
defer {
690+
k2 = Klass()
691+
print(k4)
692+
k3 = Klass()
693+
}
694+
print("foo bar")
695+
}
696+
697+
func multipleCapture2(_ k: Klass) -> () {
698+
var k2 = k // expected-error {{'k2' used after being moved}}
699+
k2 = k
700+
var k3 = k
701+
let _ = _move(k2) // expected-note {{move here}}
702+
let _ = _move(k3)
703+
var k4 = k
704+
k4 = k
705+
defer {
706+
print(k2) // expected-note {{use here}}
707+
print(k4)
708+
k3 = Klass()
709+
}
710+
print("foo bar")
711+
}
712+
713+
//////////////////////
714+
// Reinit in pieces //
715+
//////////////////////
716+
717+
// These tests exercise the diagnostic to see how we error if we re-initialize a
718+
// var in pieces. Eventually we should teach either this diagnostic pass how to
719+
// handle this or teach DI how to combine the initializations into one large
720+
// reinit.
721+
struct KlassPair {
722+
var lhs: Klass
723+
var rhs: Klass
724+
}
725+
726+
func reinitInPieces1(_ k: KlassPair) {
727+
var k2 = k
728+
k2 = k
729+
730+
let _ = _move(k2) // expected-error {{_move applied to value that the compiler does not support checking}}
731+
k2.lhs = Klass()
732+
k2.rhs = Klass()
733+
}

0 commit comments

Comments
 (0)