Skip to content

Commit 0d6c184

Browse files
authored
Merge pull request swiftlang#40080 from gottesmm/pr-2c0bf8e9d711154314533be4df5e1779ec9b15ab
[moveOnly] Emit an error diagnostic if a user applies _move to a value that the compiler doesn't know how to check (non-let, non-param today).
2 parents 65c90cf + 97b1920 commit 0d6c184

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,9 @@ NOTE(sil_movekillscopyablevalue_use_here, none,
740740
"use here", ())
741741
NOTE(sil_movekillscopyablevalue_value_consumed_in_loop, none,
742742
"cyclic move here. move will occur multiple times in the loop", ())
743+
ERROR(sil_movekillscopyablevalue_move_applied_to_unsupported_move, none,
744+
"_move applied to value that the compiler does not know how to check. "
745+
"Please file a bug or an enhancement request!", ())
743746

744747
#define UNDEFINE_DIAGNOSTIC_MACROS
745748
#include "DefineDiagnosticMacros.h"

lib/SILOptimizer/Mandatory/MoveKillsCopyableValuesChecker.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929

3030
using namespace swift;
3131

32+
static llvm::cl::opt<bool>
33+
DisableUnhandledMoveDiagnostic("sil-disable-unknown-move-diagnostic");
34+
3235
//===----------------------------------------------------------------------===//
3336
// Diagnostic Utilities
3437
//===----------------------------------------------------------------------===//
@@ -383,6 +386,12 @@ bool MoveKillsCopyableValuesChecker::check() {
383386
// Only emit diagnostics if our move value allows us to.
384387
if (!mvi->getAllowDiagnostics())
385388
continue;
389+
390+
// Now that we know we may emit diagnostics for this, unset allows
391+
// diagnostics so that we skip these when we search at the end for
392+
// unvisited move_value [allows_diagnostics].
393+
mvi->setAllowsDiagnostics(false);
394+
386395
LLVM_DEBUG(llvm::dbgs() << "Move Value: " << *mvi);
387396
if (livenessInfo.liveness.isWithinBoundary(mvi)) {
388397
LLVM_DEBUG(llvm::dbgs() << " WithinBoundary: Yes!\n");
@@ -412,6 +421,12 @@ namespace {
412421
class MoveKillsCopyableValuesCheckerPass : public SILFunctionTransform {
413422
void run() override {
414423
auto *fn = getFunction();
424+
auto &astContext = fn->getASTContext();
425+
426+
// If we do not have experimental move only enabled, do not emit
427+
// diagnostics.
428+
if (!astContext.LangOpts.EnableExperimentalMoveOnly)
429+
return;
415430

416431
// Don't rerun diagnostics on deserialized functions.
417432
if (getFunction()->wasDeserializedCanonical())
@@ -425,6 +440,26 @@ class MoveKillsCopyableValuesCheckerPass : public SILFunctionTransform {
425440
if (MoveKillsCopyableValuesChecker(getFunction()).check()) {
426441
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
427442
}
443+
444+
// Now search through our function one last time and any move_value
445+
// [allows_diagnostics] that remain are ones that we did not know how to
446+
// check so emit a diagnostic so the user doesn't assume that they have
447+
// guarantees.
448+
//
449+
// TODO: Emit specific diagnostics here (e.x.: _move of global).
450+
if (DisableUnhandledMoveDiagnostic)
451+
return;
452+
for (auto &block : *fn) {
453+
for (auto &inst : block) {
454+
if (auto *mvi = dyn_cast<MoveValueInst>(&inst)) {
455+
if (mvi->getAllowDiagnostics()) {
456+
auto diag = diag::
457+
sil_movekillscopyablevalue_move_applied_to_unsupported_move;
458+
diagnose(astContext, mvi->getLoc().getSourceLoc(), diag);
459+
}
460+
}
461+
}
462+
}
428463
}
429464
};
430465

test/SILOptimizer/move_operator_kills_copyable_values.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,27 @@ public class KlassPair {
231231
var y = Klass()
232232
}
233233

234-
// No error since we are not moving p itself, but are moving a copy of x that we
235-
// loaded from p and then destroying that.
234+
// TODO: Emit a better error here! We should state that we are applying _move to
235+
// a class field and that is illegal.
236236
public func performMoveOnOneEltOfKlassPair(_ p: KlassPair) {
237-
let _ = _move(p.x)
237+
let _ = _move(p.x) // expected-error {{_move applied to value that the compiler does not know how to check. Please file a bug or an enhancement request!}}
238238
nonConsumingUse(p.y)
239239
}
240+
241+
let myLetGlobal = Klass()
242+
var myVarGlobal = Klass()
243+
244+
public func performMoveOnVarGlobalError() {
245+
let _ = _move(myVarGlobal) // expected-error {{_move applied to value that the compiler does not know how to check. Please file a bug or an enhancement request!}}
246+
}
247+
248+
// TODO: Support vars
249+
public func performMoveOnVarError() {
250+
var k = myVarGlobal
251+
let _ = _move(k) // expected-error {{_move applied to value that the compiler does not know how to check. Please file a bug or an enhancement request!}}
252+
k = myVarGlobal
253+
}
254+
255+
public func performMoveOnLetGlobalError() {
256+
let _ = _move(myVarGlobal) // expected-error {{_move applied to value that the compiler does not know how to check. Please file a bug or an enhancement request!}}
257+
}

test/stdlib/LifetimeManagement.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ suite.test("copy") {
1515

1616
suite.test("move") {
1717
let k = Klass()
18-
expectTrue(k === _move(k))
18+
let k2 = k
19+
expectTrue(k2 === _move(k))
1920
}
2021

2122
runAllTests()

0 commit comments

Comments
 (0)