Auto merge of #117585 - dnbln:feat/move-kw-span, r=cjgillot
Add the `Span` of the `move` keyword to the HIR. This is required to implement a lint like the one described here: https://github.com/rust-lang/rust-clippy/issues/11721
This commit is contained in:
commit
152a4e90d1
14 changed files with 49 additions and 20 deletions
|
@ -1548,7 +1548,10 @@ pub struct QSelf {
|
||||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub enum CaptureBy {
|
pub enum CaptureBy {
|
||||||
/// `move |x| y + x`.
|
/// `move |x| y + x`.
|
||||||
Value,
|
Value {
|
||||||
|
/// The span of the `move` keyword.
|
||||||
|
move_kw: Span,
|
||||||
|
},
|
||||||
/// `move` keyword was not specified.
|
/// `move` keyword was not specified.
|
||||||
Ref,
|
Ref,
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,10 @@ pub trait MutVisitor: Sized {
|
||||||
fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
|
fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
|
||||||
noop_visit_format_args(fmt, self)
|
noop_visit_format_args(fmt, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
|
||||||
|
noop_visit_capture_by(capture_by, self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
||||||
|
@ -1397,7 +1401,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||||
}
|
}
|
||||||
ExprKind::Closure(box Closure {
|
ExprKind::Closure(box Closure {
|
||||||
binder,
|
binder,
|
||||||
capture_clause: _,
|
capture_clause,
|
||||||
constness,
|
constness,
|
||||||
asyncness,
|
asyncness,
|
||||||
movability: _,
|
movability: _,
|
||||||
|
@ -1409,6 +1413,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||||
vis.visit_closure_binder(binder);
|
vis.visit_closure_binder(binder);
|
||||||
visit_constness(constness, vis);
|
visit_constness(constness, vis);
|
||||||
vis.visit_asyncness(asyncness);
|
vis.visit_asyncness(asyncness);
|
||||||
|
vis.visit_capture_by(capture_clause);
|
||||||
vis.visit_fn_decl(fn_decl);
|
vis.visit_fn_decl(fn_decl);
|
||||||
vis.visit_expr(body);
|
vis.visit_expr(body);
|
||||||
vis.visit_span(fn_decl_span);
|
vis.visit_span(fn_decl_span);
|
||||||
|
@ -1562,6 +1567,15 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
|
||||||
vis.visit_span(&mut visibility.span);
|
vis.visit_span(&mut visibility.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mut T) {
|
||||||
|
match capture_by {
|
||||||
|
CaptureBy::Ref => {}
|
||||||
|
CaptureBy::Value { move_kw } => {
|
||||||
|
vis.visit_span(move_kw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Some value for the AST node that is valid but possibly meaningless.
|
/// Some value for the AST node that is valid but possibly meaningless.
|
||||||
pub trait DummyAstNode {
|
pub trait DummyAstNode {
|
||||||
fn dummy() -> Self;
|
fn dummy() -> Self;
|
||||||
|
|
|
@ -251,6 +251,9 @@ pub trait Visitor<'ast>: Sized {
|
||||||
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
|
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
|
||||||
walk_inline_asm_sym(self, sym)
|
walk_inline_asm_sym(self, sym)
|
||||||
}
|
}
|
||||||
|
fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -857,7 +860,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||||
}
|
}
|
||||||
ExprKind::Closure(box Closure {
|
ExprKind::Closure(box Closure {
|
||||||
binder,
|
binder,
|
||||||
capture_clause: _,
|
capture_clause,
|
||||||
asyncness: _,
|
asyncness: _,
|
||||||
constness: _,
|
constness: _,
|
||||||
movability: _,
|
movability: _,
|
||||||
|
@ -866,6 +869,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||||
fn_decl_span: _,
|
fn_decl_span: _,
|
||||||
fn_arg_span: _,
|
fn_arg_span: _,
|
||||||
}) => {
|
}) => {
|
||||||
|
visitor.visit_capture_by(capture_clause);
|
||||||
visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id)
|
visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id)
|
||||||
}
|
}
|
||||||
ExprKind::Block(block, opt_label) => {
|
ExprKind::Block(block, opt_label) => {
|
||||||
|
|
|
@ -1201,7 +1201,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let async_expr = this.make_async_expr(
|
let async_expr = this.make_async_expr(
|
||||||
CaptureBy::Value,
|
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||||
closure_id,
|
closure_id,
|
||||||
None,
|
None,
|
||||||
body.span,
|
body.span,
|
||||||
|
|
|
@ -673,7 +673,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
|
fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
|
||||||
match capture_clause {
|
match capture_clause {
|
||||||
ast::CaptureBy::Value => self.word_space("move"),
|
ast::CaptureBy::Value { .. } => self.word_space("move"),
|
||||||
ast::CaptureBy::Ref => {}
|
ast::CaptureBy::Ref => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2017,7 +2017,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
|
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
|
||||||
match capture_clause {
|
match capture_clause {
|
||||||
hir::CaptureBy::Value => self.word_space("move"),
|
hir::CaptureBy::Value { .. } => self.word_space("move"),
|
||||||
hir::CaptureBy::Ref => {}
|
hir::CaptureBy::Ref => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
origin = updated.1;
|
origin = updated.1;
|
||||||
|
|
||||||
let (place, capture_kind) = match capture_clause {
|
let (place, capture_kind) = match capture_clause {
|
||||||
hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind),
|
hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
|
||||||
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
|
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -958,7 +958,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
|
let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
|
||||||
|
|
||||||
let ty = match closure_clause {
|
let ty = match closure_clause {
|
||||||
hir::CaptureBy::Value => ty, // For move closure the capture kind should be by value
|
hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value
|
||||||
hir::CaptureBy::Ref => {
|
hir::CaptureBy::Ref => {
|
||||||
// For non move closure the capture kind is the max capture kind of all captures
|
// For non move closure the capture kind is the max capture kind of all captures
|
||||||
// according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
|
// according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
|
||||||
|
@ -1073,7 +1073,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
match closure_clause {
|
match closure_clause {
|
||||||
// Only migrate if closure is a move closure
|
// Only migrate if closure is a move closure
|
||||||
hir::CaptureBy::Value => {
|
hir::CaptureBy::Value { .. } => {
|
||||||
let mut diagnostics_info = FxIndexSet::default();
|
let mut diagnostics_info = FxIndexSet::default();
|
||||||
let upvars =
|
let upvars =
|
||||||
self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
|
self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
|
||||||
|
@ -1479,10 +1479,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// If the data will be moved out of this place, then the place will be truncated
|
// If the data will be moved out of this place, then the place will be truncated
|
||||||
// at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
|
// at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
|
||||||
// the closure.
|
// the closure.
|
||||||
hir::CaptureBy::Value if !place.deref_tys().any(Ty::is_ref) => {
|
hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => {
|
||||||
ty::UpvarCapture::ByValue
|
ty::UpvarCapture::ByValue
|
||||||
}
|
}
|
||||||
hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow),
|
hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => {
|
||||||
|
ty::UpvarCapture::ByRef(ty::ImmBorrow)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2303,13 +2303,14 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses an optional `move` prefix to a closure-like construct.
|
/// Parses an optional `move` prefix to a closure-like construct.
|
||||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||||
if self.eat_keyword(kw::Move) {
|
if self.eat_keyword(kw::Move) {
|
||||||
|
let move_kw_span = self.prev_token.span;
|
||||||
// Check for `move async` and recover
|
// Check for `move async` and recover
|
||||||
if self.check_keyword(kw::Async) {
|
if self.check_keyword(kw::Async) {
|
||||||
let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
|
let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
|
||||||
Err(errors::AsyncMoveOrderIncorrect { span: move_async_span }
|
Err(errors::AsyncMoveOrderIncorrect { span: move_async_span }
|
||||||
.into_diagnostic(&self.sess.span_diagnostic))
|
.into_diagnostic(&self.sess.span_diagnostic))
|
||||||
} else {
|
} else {
|
||||||
Ok(CaptureBy::Value)
|
Ok(CaptureBy::Value { move_kw: move_kw_span })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(CaptureBy::Ref)
|
Ok(CaptureBy::Ref)
|
||||||
|
|
|
@ -2938,7 +2938,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
else {
|
else {
|
||||||
bug!("expected closure in SizedClosureCapture obligation");
|
bug!("expected closure in SizedClosureCapture obligation");
|
||||||
};
|
};
|
||||||
if let hir::CaptureBy::Value = closure.capture_clause
|
if let hir::CaptureBy::Value { .. } = closure.capture_clause
|
||||||
&& let Some(span) = closure.fn_arg_span
|
&& let Some(span) = closure.fn_arg_span
|
||||||
{
|
{
|
||||||
err.span_label(span, "this closure captures all values by move");
|
err.span_label(span, "this closure captures all values by move");
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_ast::LitIntType;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
|
ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, CaptureBy
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
@ -479,6 +479,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
movability,
|
movability,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
let capture_clause = match capture_clause {
|
||||||
|
CaptureBy::Value { .. } => "Value { .. }",
|
||||||
|
CaptureBy::Ref => "Ref",
|
||||||
|
};
|
||||||
|
|
||||||
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
|
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
|
||||||
|
|
||||||
let ret_ty = match fn_decl.output {
|
let ret_ty = match fn_decl.output {
|
||||||
|
@ -487,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
bind!(self, fn_decl, body_id);
|
bind!(self, fn_decl, body_id);
|
||||||
kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})");
|
kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})");
|
||||||
chain!(self, "let {ret_ty} = {fn_decl}.output");
|
chain!(self, "let {ret_ty} = {fn_decl}.output");
|
||||||
self.body(body_id);
|
self.body(body_id);
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind
|
||||||
{
|
{
|
||||||
// report your lint here
|
// report your lint here
|
||||||
}
|
}
|
||||||
if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
|
if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind
|
||||||
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
||||||
&& expr1 = &cx.tcx.hir().body(body_id).value
|
&& expr1 = &cx.tcx.hir().body(body_id).value
|
||||||
&& let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
|
&& let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
|
||||||
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
|
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
|
||||||
&& expr2 = &cx.tcx.hir().body(body_id1).value
|
&& expr2 = &cx.tcx.hir().body(body_id1).value
|
||||||
&& let ExprKind::Block(block, None) = expr2.kind
|
&& let ExprKind::Block(block, None) = expr2.kind
|
||||||
|
|
|
@ -264,7 +264,7 @@ fn rewrite_closure_fn_decl(
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
let is_async = if asyncness.is_async() { "async " } else { "" };
|
let is_async = if asyncness.is_async() { "async " } else { "" };
|
||||||
let mover = if capture == ast::CaptureBy::Value {
|
let mover = if matches!(capture, ast::CaptureBy::Value { .. }) {
|
||||||
"move "
|
"move "
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
|
|
|
@ -368,7 +368,7 @@ pub(crate) fn format_expr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprKind::Gen(capture_by, ref block, ref kind) => {
|
ast::ExprKind::Gen(capture_by, ref block, ref kind) => {
|
||||||
let mover = if capture_by == ast::CaptureBy::Value {
|
let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) {
|
||||||
"move "
|
"move "
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
|
|
|
@ -130,7 +130,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
||||||
iter_exprs(depth - 1, &mut |e| {
|
iter_exprs(depth - 1, &mut |e| {
|
||||||
g(ExprKind::Closure(Box::new(Closure {
|
g(ExprKind::Closure(Box::new(Closure {
|
||||||
binder: ClosureBinder::NotPresent,
|
binder: ClosureBinder::NotPresent,
|
||||||
capture_clause: CaptureBy::Value,
|
capture_clause: CaptureBy::Value { move_kw: DUMMY_SP },
|
||||||
constness: Const::No,
|
constness: Const::No,
|
||||||
asyncness: Async::No,
|
asyncness: Async::No,
|
||||||
movability: Movability::Movable,
|
movability: Movability::Movable,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue