Skip to content

Commit ef570f0

Browse files
committed
[move-function] Ban move being passed non-declref expr values.
I did this by requiring this in the typechecker. This will ensure that when we emit a move, we are guaranteed to have a value decl ref that we can evaluate. It also ensures that we can't _move fields. auto
1 parent a78ef08 commit ef570f0

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6421,6 +6421,8 @@ ERROR(concurrency_task_to_thread_model_global_actor_annotation,none,
64216421

64226422
ERROR(moveOnly_not_allowed_here,none,
64236423
"'moveOnly' may only be applied to classes, structs, and enums", ())
6424+
ERROR(move_expression_not_passed_lvalue,none,
6425+
"'move' can only be applied to lvalues", ())
64246426

64256427
#define UNDEFINE_DIAGNOSTIC_MACROS
64266428
#include "DefineDiagnosticMacros.h"

lib/Sema/MiscDiagnostics.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
#include "TypeCheckConcurrency.h"
2020
#include "TypeChecker.h"
2121
#include "swift/AST/ASTWalker.h"
22+
#include "swift/AST/DiagnosticsSema.h"
2223
#include "swift/AST/ExistentialLayout.h"
24+
#include "swift/AST/Expr.h"
2325
#include "swift/AST/NameLookup.h"
2426
#include "swift/AST/NameLookupRequests.h"
2527
#include "swift/AST/Pattern.h"
2628
#include "swift/AST/SourceFile.h"
2729
#include "swift/AST/Stmt.h"
2830
#include "swift/AST/TypeCheckRequests.h"
31+
#include "swift/AST/Types.h"
2932
#include "swift/Basic/Defer.h"
3033
#include "swift/Basic/SourceManager.h"
3134
#include "swift/Basic/Statistic.h"
@@ -97,6 +100,7 @@ bool BaseDiagnosticWalker::shouldWalkIntoDeclInClosureContext(Decl *D) {
97100
/// invalid positions.
98101
/// - Marker protocols cannot occur as the type of an as? or is expression.
99102
/// - KeyPath expressions cannot refer to effectful properties / subscripts
103+
/// - Move expressions must have a declref expr subvalue.
100104
///
101105
static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
102106
bool isExprStmt) {
@@ -317,7 +321,13 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
317321
if (auto cast = dyn_cast<CheckedCastExpr>(E)) {
318322
checkCheckedCastExpr(cast);
319323
}
320-
324+
325+
// Diagnose move expression uses where the sub expression is not a declref
326+
// expr.
327+
if (auto *moveExpr = dyn_cast<MoveExpr>(E)) {
328+
checkMoveExpr(moveExpr);
329+
}
330+
321331
return { true, E };
322332
}
323333

@@ -357,6 +367,13 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
357367
}
358368
}
359369

370+
void checkMoveExpr(MoveExpr *moveExpr) {
371+
if (!isa<DeclRefExpr>(moveExpr->getSubExpr())) {
372+
Ctx.Diags.diagnose(moveExpr->getLoc(),
373+
diag::move_expression_not_passed_lvalue);
374+
}
375+
}
376+
360377
static Expr *lookThroughArgument(Expr *arg) {
361378
while (1) {
362379
if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))

test/Sema/move_expr.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
class Klass {
4+
var k: Klass? = nil
5+
}
6+
7+
var global: Int = 5
8+
func testGlobal() {
9+
let _ = _move global
10+
}
11+
12+
func testLet() {
13+
let t = String()
14+
let _ = _move t
15+
}
16+
17+
func testVar() {
18+
var t = String()
19+
t = String()
20+
let _ = _move t
21+
}
22+
23+
func testExprFailureLet() {
24+
let t = 5
25+
// Next line is parsed as move(t) + t
26+
let _ = _move t + t
27+
// Next line is parsed as move(t+t)
28+
let _ = _move (t+t) // expected-error {{'move' can only be applied to lvalues}}
29+
}
30+
31+
func testExprFailureVar() {
32+
var t = 5
33+
t = 5
34+
// Next line is parsed as move(t) + t
35+
let _ = _move t + t
36+
// Next line is parsed as move(t+t)
37+
let _ = _move (t+t) // expected-error {{'move' can only be applied to lvalues}}
38+
}
39+
40+
func letAddressOnly<T>(_ v: T) {
41+
let t = v
42+
let _ = _move t
43+
}
44+
45+
struct StructWithField {
46+
var k: Klass? = nil
47+
}
48+
49+
func testLetStructAccessField() {
50+
let t = StructWithField()
51+
let _ = _move t.k // expected-error {{'move' can only be applied to lvalues}}
52+
}
53+
54+
func testVarStructAccessField() {
55+
var t = StructWithField()
56+
t = StructWithField()
57+
let _ = _move t.k // expected-error {{'move' can only be applied to lvalues}}
58+
}
59+
60+
func testLetClassAccessField() {
61+
let t = Klass()
62+
let _ = _move t.k // expected-error {{'move' can only be applied to lvalues}}
63+
}
64+
65+
func testVarClassAccessField() {
66+
var t = Klass()
67+
t = Klass()
68+
let _ = _move t.k // expected-error {{'move' can only be applied to lvalues}}
69+
}

0 commit comments

Comments
 (0)