Skip to content

Commit 9f0f8c8

Browse files
committed
add move(expr) syntax
1 parent 17517fd commit 9f0f8c8

13 files changed

Lines changed: 77 additions & 4 deletions

File tree

compiler/rustc_ast/src/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,7 @@ impl Expr {
15951595
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
15961596
// but we need to print `(let _ = a) < b` as-is with parens.
15971597
| ExprKind::Let(..)
1598+
| ExprKind::Move(..)
15981599
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
15991600

16001601
// Need parens if and only if there are prefix attributes.
@@ -1764,6 +1765,8 @@ pub enum ExprKind {
17641765
Binary(BinOp, Box<Expr>, Box<Expr>),
17651766
/// A unary operation (e.g., `!x`, `*x`).
17661767
Unary(UnOp, Box<Expr>),
1768+
/// A `move(expr)` expression.
1769+
Move(Box<Expr>, Span),
17671770
/// A literal (e.g., `1`, `"foo"`).
17681771
Lit(token::Lit),
17691772
/// A cast (e.g., `foo as f64`).

compiler/rustc_ast/src/util/classify.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
108108
Assign(e, _, _)
109109
| AssignOp(_, e, _)
110110
| Await(e, _)
111+
| Move(e, _)
111112
| Use(e, _)
112113
| Binary(_, e, _)
113114
| Call(e, _)
@@ -183,6 +184,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
183184
| Ret(Some(e))
184185
| Unary(_, e)
185186
| Yeet(Some(e))
187+
| Move(e, _)
186188
| Become(e) => {
187189
expr = e;
188190
}

compiler/rustc_ast/src/visit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,9 @@ macro_rules! common_visitor_and_walkers {
10231023
visit_visitable!($($mut)? vis, block, opt_label),
10241024
ExprKind::Gen(capt, body, kind, decl_span) =>
10251025
visit_visitable!($($mut)? vis, capt, body, kind, decl_span),
1026-
ExprKind::Await(expr, span) | ExprKind::Use(expr, span) =>
1026+
ExprKind::Await(expr, span)
1027+
| ExprKind::Move(expr, span)
1028+
| ExprKind::Use(expr, span) =>
10271029
visit_visitable!($($mut)? vis, expr, span),
10281030
ExprKind::Assign(lhs, rhs, span) =>
10291031
visit_visitable!($($mut)? vis, lhs, rhs, span),

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ pub(crate) struct ClosureCannotBeStatic {
136136
pub fn_decl_span: Span,
137137
}
138138

139+
#[derive(Diagnostic)]
140+
#[diag("`move(expr)` is only supported in plain closures")]
141+
pub(crate) struct MoveExprOnlyInPlainClosures {
142+
#[primary_span]
143+
pub span: Span,
144+
}
145+
139146
#[derive(Diagnostic)]
140147
#[diag("functional record updates are not allowed in destructuring assignments")]
141148
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use visit::{Visitor, walk_expr};
2020
use super::errors::{
2121
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic,
2222
CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment,
23-
InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard,
24-
UnderscoreExprLhsAssign,
23+
InclusiveRangeWithNoEnd, MatchArmWithNoBody, MoveExprOnlyInPlainClosures, NeverPatternWithBody,
24+
NeverPatternWithGuard, UnderscoreExprLhsAssign,
2525
};
2626
use super::{
2727
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
@@ -212,6 +212,18 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
212212
},
213213
),
214214
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
215+
ExprKind::Move(_, move_kw_span) => {
216+
if !self.tcx.features().move_expr() {
217+
return self.expr_err(
218+
*move_kw_span,
219+
self.dcx().span_delayed_bug(*move_kw_span, "invalid move(expr)"),
220+
);
221+
}
222+
self.dcx().emit_err(MoveExprOnlyInPlainClosures { span: *move_kw_span });
223+
hir::ExprKind::Err(
224+
self.dcx().span_delayed_bug(*move_kw_span, "invalid move(expr)"),
225+
)
226+
}
215227
ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),
216228
ExprKind::Closure(box Closure {
217229
binder,

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
352352
}
353353
_ => (),
354354
},
355+
ast::ExprKind::Move(_, move_kw_span) => {
356+
gate!(&self, move_expr, move_kw_span, "`move(expr)` syntax is experimental");
357+
}
355358
_ => {}
356359
}
357360
visit::walk_expr(self, e)

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,11 @@ impl<'a> State<'a> {
630630
);
631631
self.word(".await");
632632
}
633+
ast::ExprKind::Move(expr, _) => {
634+
self.word("move(");
635+
self.print_expr(expr, FixupContext::default());
636+
self.word(")");
637+
}
633638
ast::ExprKind::Use(expr, _) => {
634639
self.print_expr_cond_paren(
635640
expr,

compiler/rustc_builtin_macros/src/assert/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
248248
self.manage_cond_expr(arg);
249249
}
250250
}
251+
ExprKind::Move(local_expr, _) => {
252+
self.manage_cond_expr(local_expr);
253+
}
251254
ExprKind::Path(_, Path { segments, .. }) if let [path_segment] = &segments[..] => {
252255
let path_ident = path_segment.ident;
253256
self.manage_initial_capture(expr, path_ident);

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,12 @@ impl<'a> Parser<'a> {
563563
token::Ident(..) if this.token.is_keyword(kw::Box) => {
564564
make_it!(this, attrs, |this, _| this.parse_expr_box(lo))
565565
}
566+
token::Ident(..)
567+
if this.token.is_keyword(kw::Move)
568+
&& this.look_ahead(1, |t| *t == token::OpenParen) =>
569+
{
570+
make_it!(this, attrs, |this, _| this.parse_expr_move(lo))
571+
}
566572
token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
567573
make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
568574
}
@@ -606,6 +612,16 @@ impl<'a> Parser<'a> {
606612
Ok((span, ExprKind::Err(guar)))
607613
}
608614

615+
fn parse_expr_move(&mut self, move_kw: Span) -> PResult<'a, (Span, ExprKind)> {
616+
self.bump();
617+
self.psess.gated_spans.gate(sym::move_expr, move_kw);
618+
self.expect(exp!(OpenParen))?;
619+
let expr = self.parse_expr()?;
620+
self.expect(exp!(CloseParen))?;
621+
let span = move_kw.to(self.prev_token.span);
622+
Ok((span, ExprKind::Move(expr, move_kw)))
623+
}
624+
609625
fn is_mistaken_not_ident_negation(&self) -> bool {
610626
let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
611627
// These tokens can start an expression after `!`, but
@@ -4387,6 +4403,7 @@ impl MutVisitor for CondChecker<'_> {
43874403
}
43884404
ExprKind::Unary(_, _)
43894405
| ExprKind::Await(_, _)
4406+
| ExprKind::Move(_, _)
43904407
| ExprKind::Use(_, _)
43914408
| ExprKind::AssignOp(_, _, _)
43924409
| ExprKind::Range(_, _, _)

compiler/rustc_passes/src/input_stats.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
657657
(self, e, e.kind, None, ast, Expr, ExprKind),
658658
[
659659
Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
660-
If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign,
660+
If, While, ForLoop, Loop, Match, Closure, Block, Await, Move, Use, TryBlock, Assign,
661661
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
662662
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
663663
Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy

0 commit comments

Comments
 (0)