Skip to content

Commit 4901529

Browse files
committed
[move-only-addr] Teach move only address checker that captured vars should be treated like inout arguments.
rdar://103313357
1 parent c33b9ee commit 4901529

File tree

5 files changed

+126
-21
lines changed

5 files changed

+126
-21
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,8 @@ ERROR(sil_moveonlychecker_let_value_consumed_in_closure, none,
737737
"'%0' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations", (StringRef))
738738
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_function, none,
739739
"'%0' consumed but not reinitialized before end of function", (StringRef))
740+
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_closure, none,
741+
"'%0' consumed in closure but not reinitialized before end of closure", (StringRef))
740742
ERROR(sil_moveonlychecker_value_consumed_in_a_loop, none,
741743
"'%0' consumed by a use in a loop", (StringRef))
742744
ERROR(sil_moveonlychecker_exclusivity_violation, none,

lib/SILGen/SILGenProlog.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,9 @@ static void emitCaptureArguments(SILGenFunction &SGF,
581581
SILType::getPrimitiveObjectType(boxTy), VD);
582582
box->setClosureCapture(true);
583583
SILValue addr = SGF.B.createProjectBox(VD, box, 0);
584+
if (addr->getType().isMoveOnly())
585+
addr = SGF.B.createMarkMustCheckInst(
586+
VD, addr, MarkMustCheckInst::CheckKind::NoImplicitCopy);
584587
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box);
585588
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
586589
SGF.B.createDebugValueAddr(Loc, addr, DbgVar);

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/AST/DiagnosticsSIL.h"
1818
#include "swift/SIL/DebugUtils.h"
19+
#include "swift/SIL/SILArgument.h"
1920
#include "llvm/Support/Debug.h"
2021

2122
using namespace swift;
@@ -282,6 +283,19 @@ void DiagnosticEmitter::emitAddressDiagnostic(MarkMustCheckInst *markedValue,
282283
}
283284

284285
if (isInOutEndOfFunction) {
286+
if (auto *fArg = dyn_cast<SILFunctionArgument>(markedValue->getOperand())) {
287+
if (fArg->isClosureCapture()) {
288+
diagnose(
289+
astContext,
290+
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
291+
diag::
292+
sil_moveonlychecker_inout_not_reinitialized_before_end_of_closure,
293+
varName);
294+
diagnose(astContext, violatingUse->getLoc().getSourceLoc(),
295+
diag::sil_moveonlychecker_consuming_use_here);
296+
return;
297+
}
298+
}
285299
diagnose(
286300
astContext,
287301
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
@@ -321,6 +335,8 @@ void DiagnosticEmitter::emitInOutEndOfFunctionDiagnostic(
321335
if (!useWithDiagnostic.insert(violatingUse).second)
322336
return;
323337

338+
valuesWithDiagnostics.insert(markedValue);
339+
324340
assert(cast<SILFunctionArgument>(markedValue->getOperand())
325341
->getArgumentConvention()
326342
.isInoutConvention() &&
@@ -335,14 +351,26 @@ void DiagnosticEmitter::emitInOutEndOfFunctionDiagnostic(
335351

336352
// Otherwise, we need to do no implicit copy semantics. If our last use was
337353
// consuming message:
354+
if (auto *fArg = dyn_cast<SILFunctionArgument>(markedValue->getOperand())) {
355+
if (fArg->isClosureCapture()) {
356+
diagnose(
357+
astContext,
358+
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
359+
diag::
360+
sil_moveonlychecker_inout_not_reinitialized_before_end_of_closure,
361+
varName);
362+
diagnose(astContext, violatingUse->getLoc().getSourceLoc(),
363+
diag::sil_moveonlychecker_consuming_use_here);
364+
return;
365+
}
366+
}
338367
diagnose(
339368
astContext,
340369
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
341370
diag::sil_moveonlychecker_inout_not_reinitialized_before_end_of_function,
342371
varName);
343372
diagnose(astContext, violatingUse->getLoc().getSourceLoc(),
344373
diag::sil_moveonlychecker_consuming_use_here);
345-
valuesWithDiagnostics.insert(markedValue);
346374
}
347375

348376
void DiagnosticEmitter::emitAddressDiagnosticNoCopy(

test/SILOptimizer/moveonly_addresschecker_diagnostics.swift

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,23 +1883,39 @@ public func closureClassUseAfterConsumeArg(_ argX: inout Klass) {
18831883
public func closureCaptureClassUseAfterConsume() {
18841884
var x2 = Klass()
18851885
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1886+
// expected-error @-2 {{'x2' consumed in closure but not reinitialized before end of closure}}
1887+
// expected-error @-3 {{'x2' consumed more than once}}
1888+
// expected-error @-4 {{'x2' consumed more than once}}
18861889
x2 = Klass()
18871890
let f = {
18881891
classUseMoveOnlyWithoutEscaping(x2)
18891892
classConsume(x2)
1893+
// expected-note @-1 {{consuming use}}
1894+
// expected-note @-2 {{consuming use}}
18901895
print(x2)
1896+
// expected-note @-1 {{consuming use}}
1897+
// expected-note @-2 {{consuming use}}
1898+
// expected-note @-3 {{consuming use}}
18911899
}
18921900
f()
18931901
}
18941902

18951903
public func closureCaptureClassUseAfterConsumeError() {
18961904
var x2 = Klass()
18971905
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1906+
// expected-error @-2 {{'x2' consumed more than once}}
1907+
// expected-error @-3 {{'x2' consumed more than once}}
1908+
// expected-error @-4 {{'x2' consumed in closure but not reinitialized before end of closure}}
18981909
x2 = Klass()
18991910
let f = {
19001911
classUseMoveOnlyWithoutEscaping(x2)
19011912
classConsume(x2)
1913+
// expected-note @-1 {{consuming use}}
1914+
// expected-note @-2 {{consuming use}}
19021915
print(x2)
1916+
// expected-note @-1 {{consuming use}}
1917+
// expected-note @-2 {{consuming use}}
1918+
// expected-note @-3 {{consuming use}}
19031919
}
19041920
f()
19051921
let x3 = x2
@@ -1908,7 +1924,7 @@ public func closureCaptureClassUseAfterConsumeError() {
19081924

19091925
public func closureCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
19101926
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
1911-
// expected-error @-2 {{'x2' consumed but not reinitialized before end of function}}
1927+
// expected-error @-2 {{'x2' consumed in closure but not reinitialized before end of closure}}
19121928
// expected-error @-3 {{'x2' consumed more than once}}
19131929
// expected-note @-4 {{'x2' is declared 'inout'}}
19141930
let f = { // expected-note {{consuming use}}
@@ -1926,7 +1942,7 @@ public func closureCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
19261942
// TODO: Improve error msg here to make it clear the use is due to the defer.
19271943
public func deferCaptureClassUseAfterConsume() {
19281944
var x2 = Klass()
1929-
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
1945+
// expected-error @-1 {{'x2' consumed in closure but not reinitialized before end of closure}}
19301946
// expected-error @-2 {{'x2' consumed more than once}}
19311947
x2 = Klass()
19321948
defer {
@@ -1940,7 +1956,7 @@ public func deferCaptureClassUseAfterConsume() {
19401956

19411957
public func deferCaptureClassUseAfterConsume2() {
19421958
var x2 = Klass()
1943-
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
1959+
// expected-error @-1 {{'x2' consumed in closure but not reinitialized before end of closure}}
19441960
// expected-error @-2 {{'x2' consumed more than once}}
19451961
x2 = Klass()
19461962
defer {
@@ -1955,7 +1971,7 @@ public func deferCaptureClassUseAfterConsume2() {
19551971
}
19561972

19571973
public func deferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
1958-
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
1974+
// expected-error @-1 {{'x2' consumed in closure but not reinitialized before end of closure}}
19591975
// expected-error @-2 {{'x2' consumed more than once}}
19601976
classUseMoveOnlyWithoutEscaping(x2)
19611977
defer {
@@ -1970,7 +1986,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
19701986
public func closureAndDeferCaptureClassUseAfterConsume() {
19711987
var x2 = Klass()
19721988
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
1973-
// expected-error @-2 {{'x2' consumed but not reinitialized before end of function}}
1989+
// expected-error @-2 {{'x2' consumed in closure but not reinitialized before end of closure}}
19741990
// expected-error @-3 {{'x2' consumed more than once}}
19751991
x2 = Klass()
19761992
let f = {
@@ -1988,7 +2004,7 @@ public func closureAndDeferCaptureClassUseAfterConsume() {
19882004

19892005
public func closureAndDeferCaptureClassUseAfterConsume2() {
19902006
var x2 = Klass()
1991-
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
2007+
// expected-error @-1 {{'x2' consumed in closure but not reinitialized before end of closure}}
19922008
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
19932009
// expected-error @-3 {{'x2' consumed more than once}}
19942010
x2 = Klass()
@@ -2008,7 +2024,7 @@ public func closureAndDeferCaptureClassUseAfterConsume2() {
20082024

20092025
public func closureAndDeferCaptureClassUseAfterConsume3() {
20102026
var x2 = Klass()
2011-
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
2027+
// expected-error @-1 {{'x2' consumed in closure but not reinitialized before end of closure}}
20122028
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
20132029
// expected-error @-3 {{'x2' consumed more than once}}
20142030
x2 = Klass()
@@ -2029,7 +2045,7 @@ public func closureAndDeferCaptureClassUseAfterConsume3() {
20292045

20302046
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
20312047
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
2032-
// expected-error @-2 {{'x2' consumed but not reinitialized before end of function}}
2048+
// expected-error @-2 {{'x2' consumed in closure but not reinitialized before end of closure}}
20332049
// expected-error @-3 {{'x2' consumed more than once}}
20342050
// expected-note @-4 {{'x2' is declared 'inout'}}
20352051
let f = { // expected-error {{escaping closure captures 'inout' parameter 'x2'}}
@@ -2050,12 +2066,22 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
20502066
public func closureAndClosureCaptureClassUseAfterConsume() {
20512067
var x2 = Klass()
20522068
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
2069+
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
2070+
// expected-error @-3 {{'x2' consumed more than once}}
2071+
// expected-error @-4 {{'x2' consumed in closure but not reinitialized before end of closure}}
2072+
// expected-error @-5 {{Usage of a move only type that the move checker does not know how to check!}}
2073+
// expected-error @-6 {{'x2' consumed more than once}}
20532074
x2 = Klass()
20542075
let f = {
20552076
let g = {
20562077
classUseMoveOnlyWithoutEscaping(x2)
20572078
classConsume(x2)
2079+
// expected-note @-1 {{consuming use}}
2080+
// expected-note @-2 {{consuming use}}
20582081
print(x2)
2082+
// expected-note @-1 {{consuming use}}
2083+
// expected-note @-2 {{consuming use}}
2084+
// expected-note @-3 {{consuming use}}
20592085
}
20602086
g()
20612087
}
@@ -2065,12 +2091,22 @@ public func closureAndClosureCaptureClassUseAfterConsume() {
20652091
public func closureAndClosureCaptureClassUseAfterConsume2() {
20662092
var x2 = Klass()
20672093
// expected-error @-1 {{Usage of a move only type that the move checker does not know how to check!}}
2094+
// expected-error @-2 {{Usage of a move only type that the move checker does not know how to check!}}
2095+
// expected-error @-3 {{'x2' consumed in closure but not reinitialized before end of closure}}
2096+
// expected-error @-4 {{'x2' consumed more than once}}
2097+
// expected-error @-5 {{'x2' consumed more than once}}
2098+
// expected-error @-6 {{Usage of a move only type that the move checker does not know how to check!}}
20682099
x2 = Klass()
20692100
let f = {
20702101
let g = {
20712102
classUseMoveOnlyWithoutEscaping(x2)
20722103
classConsume(x2)
2104+
// expected-note @-1 {{consuming use}}
2105+
// expected-note @-2 {{consuming use}}
20732106
print(x2)
2107+
// expected-note @-1 {{consuming use}}
2108+
// expected-note @-2 {{consuming use}}
2109+
// expected-note @-3 {{consuming use}}
20742110
}
20752111
g()
20762112
}
@@ -2081,8 +2117,8 @@ public func closureAndClosureCaptureClassUseAfterConsume2() {
20812117

20822118
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: inout Klass) {
20832119
// expected-error @-1 {{'x2' consumed but not reinitialized before end of function}}
2084-
// expected-error @-2 {{'x2' consumed but not reinitialized before end of function}}
2085-
// expected-error @-3 {{'x2' consumed but not reinitialized before end of function}}
2120+
// expected-error @-2 {{'x2' consumed in closure but not reinitialized before end of closure}}
2121+
// expected-error @-3 {{'x2' consumed in closure but not reinitialized before end of closure}}
20862122
// expected-error @-4 {{'x2' consumed more than once}}
20872123
// expected-note @-5 {{'x2' is declared 'inout'}}
20882124
// expected-note @-6 {{'x2' is declared 'inout'}}

0 commit comments

Comments
 (0)