Skip to content

Commit 3d53d73

Browse files
committed
[move-only-object] Use closureCapture to emit more informative diagnostic on lets being captured in a closure.
Specifically, previously we said something along the lines of... 'x' has guaranteed ownership but was consumed even for lets. This is pretty misleading. Using @closureCapture, we can now emit a much better diagnostic: 'x' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations. I am also going to use this technique to emit a similar diagnostic for vars that are captured by a closure. It will be slightly different since vars will behave like inout parameters.
1 parent 6ee4c17 commit 3d53d73

File tree

4 files changed

+66
-48
lines changed

4 files changed

+66
-48
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,8 @@ ERROR(sil_moveonlychecker_guaranteed_value_consumed, none,
733733
"'%0' has guaranteed ownership but was consumed", (StringRef))
734734
ERROR(sil_moveonlychecker_guaranteed_value_captured_by_closure, none,
735735
"'%0' has guaranteed ownership but was consumed due to being captured by a closure", (StringRef))
736+
ERROR(sil_moveonlychecker_let_value_consumed_in_closure, none,
737+
"'%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))
736738
ERROR(sil_moveonlychecker_inout_not_reinitialized_before_end_of_function, none,
737739
"'%0' consumed but not reinitialized before end of function", (StringRef))
738740
ERROR(sil_moveonlychecker_value_consumed_in_a_loop, none,

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,25 @@ void DiagnosticEmitter::emitGuaranteedDiagnostic(
211211
if (!canonicalizer.hasNonPartialApplyConsumingUse())
212212
return;
213213

214+
// Check if this value is closure captured. In such a case, emit a special
215+
// error.
216+
if (auto *fArg = dyn_cast<SILFunctionArgument>(
217+
lookThroughCopyValueInsts(markedValue->getOperand()))) {
218+
if (fArg->isClosureCapture()) {
219+
diagnose(astContext,
220+
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
221+
diag::sil_moveonlychecker_let_value_consumed_in_closure,
222+
varName);
223+
emitDiagnosticsForFoundUses(true /*ignore partial apply uses*/);
224+
valuesWithDiagnostics.insert(markedValue);
225+
return;
226+
}
227+
}
228+
214229
diagnose(astContext,
215230
markedValue->getDefiningInstruction()->getLoc().getSourceLoc(),
216231
diag::sil_moveonlychecker_guaranteed_value_consumed, varName);
232+
217233
emitDiagnosticsForFoundUses(true /*ignore partial apply uses*/);
218234
valuesWithDiagnostics.insert(markedValue);
219235
}

test/SILOptimizer/moveonly_objectchecker_diagnostics.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,7 @@ public func enumPatternMatchSwitch2WhereClause2OwnedArg(_ x2: __owned EnumTy) {
20482048

20492049
public func closureClassUseAfterConsume1(_ x: Klass) {
20502050
// expected-error @-1 {{'x' has guaranteed ownership but was consumed}}
2051-
// expected-error @-2 {{'x' has guaranteed ownership but was consumed due to being captured by a closure}}
2051+
// expected-error @-2 {{'x' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
20522052
let f = { // expected-note {{closure capture}}
20532053
let x2 = x // expected-error {{'x2' consumed more than once}}
20542054
// expected-note @-1 {{consuming use}}
@@ -2082,7 +2082,7 @@ public func closureClassUseAfterConsumeArg(_ argX: Klass) {
20822082

20832083
public func closureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
20842084
let x2 = x // expected-note {{consuming use}}
2085-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2085+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
20862086
let f = {
20872087
classUseMoveOnlyWithoutEscaping(x2)
20882088
classConsume(x2) // expected-note {{consuming use}}
@@ -2094,7 +2094,7 @@ public func closureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {
20942094
public func closureCaptureClassUseAfterConsumeError(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
20952095
let x2 = x
20962096
// expected-error @-1 {{'x2' consumed more than once}}
2097-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2097+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
20982098
// expected-note @-3 {{consuming use}}
20992099
let f = { // expected-note {{consuming use}}
21002100
classUseMoveOnlyWithoutEscaping(x2)
@@ -2107,7 +2107,7 @@ public func closureCaptureClassUseAfterConsumeError(_ x: Klass) { // expected-er
21072107
}
21082108

21092109
public func closureCaptureClassArgUseAfterConsume(_ x2: Klass) {
2110-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2110+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21112111
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
21122112
let f = { // expected-note {{closure capture}}
21132113
classUseMoveOnlyWithoutEscaping(x2)
@@ -2118,7 +2118,7 @@ public func closureCaptureClassArgUseAfterConsume(_ x2: Klass) {
21182118
}
21192119

21202120
public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
2121-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2121+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21222122
let f = {
21232123
classUseMoveOnlyWithoutEscaping(x2)
21242124
classConsume(x2) // expected-note {{consuming use}}
@@ -2129,7 +2129,7 @@ public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
21292129

21302130
public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
21312131
// expected-error @-1 {{'x2' consumed more than once}}
2132-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2132+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21332133
let f = { // expected-note {{consuming use}}
21342134
classUseMoveOnlyWithoutEscaping(x2)
21352135
classConsume(x2) // expected-note {{consuming use}}
@@ -2142,7 +2142,7 @@ public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
21422142

21432143
public func deferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
21442144
let x2 = x // expected-note {{consuming use}}
2145-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2145+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21462146
defer {
21472147
classUseMoveOnlyWithoutEscaping(x2)
21482148
classConsume(x2) // expected-note {{consuming use}}
@@ -2154,7 +2154,7 @@ public func deferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'
21542154
public func deferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
21552155
let x2 = x // expected-error {{'x2' consumed more than once}}
21562156
// expected-note @-1 {{consuming use}}
2157-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2157+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21582158
defer {
21592159
classUseMoveOnlyWithoutEscaping(x2)
21602160
classConsume(x2) // expected-note {{consuming use}}
@@ -2165,7 +2165,7 @@ public func deferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{
21652165
}
21662166

21672167
public func deferCaptureClassArgUseAfterConsume(_ x2: Klass) {
2168-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2168+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21692169
classUseMoveOnlyWithoutEscaping(x2)
21702170
defer {
21712171
classUseMoveOnlyWithoutEscaping(x2)
@@ -2176,7 +2176,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: Klass) {
21762176
}
21772177

21782178
public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
2179-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2179+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21802180
defer {
21812181
classUseMoveOnlyWithoutEscaping(x2)
21822182
classConsume(x2) // expected-note {{consuming use}}
@@ -2187,7 +2187,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
21872187

21882188
public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
21892189
// expected-error @-1 {{'x2' consumed more than once}}
2190-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2190+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
21912191
defer {
21922192
classUseMoveOnlyWithoutEscaping(x2)
21932193
classConsume(x2) // expected-note {{consuming use}}
@@ -2198,7 +2198,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
21982198

21992199
public func closureAndDeferCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
22002200
let x2 = x // expected-note {{consuming use}}
2201-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2201+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22022202
let f = {
22032203
defer {
22042204
classUseMoveOnlyWithoutEscaping(x2)
@@ -2212,8 +2212,8 @@ public func closureAndDeferCaptureClassUseAfterConsume(_ x: Klass) { // expected
22122212

22132213
public func closureAndDeferCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
22142214
let x2 = x // expected-note {{consuming use}}
2215-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2216-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2215+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
2216+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22172217
let f = {
22182218
classConsume(x2) // expected-note {{consuming use}}
22192219
defer {
@@ -2229,8 +2229,8 @@ public func closureAndDeferCaptureClassUseAfterConsume2(_ x: Klass) { // expecte
22292229
public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
22302230
let x2 = x // expected-error {{'x2' consumed more than once}}
22312231
// expected-note @-1 {{consuming use}}
2232-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2233-
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed}}
2232+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
2233+
// expected-error @-3 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22342234
let f = { // expected-note {{consuming use}}
22352235
classConsume(x2) // expected-note {{consuming use}}
22362236
defer {
@@ -2245,7 +2245,7 @@ public func closureAndDeferCaptureClassUseAfterConsume3(_ x: Klass) { // expecte
22452245
}
22462246

22472247
public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: Klass) {
2248-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2248+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22492249
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
22502250
let f = { // expected-note {{closure capture}}
22512251
defer {
@@ -2259,7 +2259,7 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: Klass) {
22592259
}
22602260

22612261
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
2262-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2262+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22632263
let f = {
22642264
defer {
22652265
classUseMoveOnlyWithoutEscaping(x2)
@@ -2273,7 +2273,7 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Kla
22732273

22742274
public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
22752275
// expected-error @-1 {{'x2' consumed more than once}}
2276-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2276+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22772277
let f = { // expected-note {{consuming use}}
22782278
defer {
22792279
classUseMoveOnlyWithoutEscaping(x2)
@@ -2288,7 +2288,7 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Kl
22882288

22892289
public func closureAndClosureCaptureClassUseAfterConsume(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
22902290
let x2 = x // expected-note {{consuming use}}
2291-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2291+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
22922292
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
22932293
let f = {
22942294
let g = { // expected-note {{closure capture}}
@@ -2304,7 +2304,7 @@ public func closureAndClosureCaptureClassUseAfterConsume(_ x: Klass) { // expect
23042304
public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { // expected-error {{'x' has guaranteed ownership but was consumed}}
23052305
let x2 = x // expected-error {{'x2' consumed more than once}}
23062306
// expected-note @-1 {{consuming use}}
2307-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2307+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
23082308
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
23092309
let f = { // expected-note {{consuming use}}
23102310
let g = { // expected-note {{closure capture}}
@@ -2320,7 +2320,7 @@ public func closureAndClosureCaptureClassUseAfterConsume2(_ x: Klass) { // expec
23202320

23212321

23222322
public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: Klass) {
2323-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2323+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
23242324
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
23252325
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
23262326
let f = { // expected-note {{closure capture}}
@@ -2335,7 +2335,7 @@ public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: Klass) {
23352335
}
23362336

23372337
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) {
2338-
// expected-error @-1 {{'x2' has guaranteed ownership but was consumed}}
2338+
// expected-error @-1 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
23392339
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
23402340
let f = {
23412341
let g = { // expected-note {{closure capture}}
@@ -2350,7 +2350,7 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned K
23502350

23512351
public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: __owned Klass) {
23522352
// expected-error @-1 {{'x2' consumed more than once}}
2353-
// expected-error @-2 {{'x2' has guaranteed ownership but was consumed}}
2353+
// expected-error @-2 {{'x2' consumed in closure. This is illegal since if the closure is invoked more than once the binding will be uninitialized on later invocations}}
23542354
// expected-error @-3 {{'x2' has guaranteed ownership but was consumed due to being captured by a closure}}
23552355
let f = { // expected-note {{consuming use}}
23562356
let g = { // expected-note {{closure capture}}

0 commit comments

Comments
 (0)