summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs428
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs18
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs86
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs176
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs152
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs38
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs2
8 files changed, 553 insertions, 351 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index ee352e911..9a8f1c97e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
-use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
+use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
@@ -351,7 +351,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
// Check if we are in a situation of `ident @ ident` where we want to suggest
// `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
- if let Some(subpat) = sub && self.pat.is_none() {
+ if let Some(subpat) = sub
+ && self.pat.is_none()
+ {
self.visit_pat(subpat);
if self.pat.is_some() {
self.parent_pat = Some(p);
@@ -370,7 +372,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut finder =
ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
finder.visit_expr(expr);
- if let Some(span) = span && let Some(expr) = finder.expr {
+ if let Some(span) = span
+ && let Some(expr) = finder.expr
+ {
for (_, expr) in hir.parent_iter(expr.hir_id) {
if let hir::Node::Expr(expr) = expr {
if expr.span.contains(span) {
@@ -425,10 +429,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(hir::intravisit::FnKind::Method(..)) => "method",
Some(hir::intravisit::FnKind::Closure) => "closure",
};
- span.push_span_label(
- ident.span,
- format!("in this {descr}"),
- );
+ span.push_span_label(ident.span, format!("in this {descr}"));
err.span_note(
span,
format!(
@@ -441,15 +442,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = place.ty(self.body, self.infcx.tcx).ty;
if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
- && let hir::ExprKind::Path(
- hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _)
- ) = call_expr.kind
+ && let hir::ExprKind::Path(hir::QPath::LangItem(
+ LangItem::IntoIterIntoIter,
+ _,
+ _,
+ )) = call_expr.kind
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
- } else if let UseSpans::FnSelfUse {
- kind: CallKind::Normal { .. },
- ..
- } = move_spans {
+ } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } =
+ move_spans
+ {
// We already suggest cloning for these cases in `explain_captures`.
} else {
self.suggest_cloning(err, ty, expr, move_span);
@@ -602,10 +604,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.sugg_span.is_some() {
return;
}
- if let hir::StmtKind::Local(hir::Local {
- span, ty, init: None, ..
- }) = &ex.kind && span.contains(self.decl_span) {
- self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
+ if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind
+ && span.contains(self.decl_span)
+ {
+ self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
}
hir::intravisit::walk_stmt(self, ex);
}
@@ -743,19 +745,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
".clone()".to_owned()
};
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
- && self.infcx
- .type_implements_trait(
- clone_trait_def,
- [ty],
- self.param_env,
- )
+ && self
+ .infcx
+ .type_implements_trait(clone_trait_def, [ty], self.param_env)
.must_apply_modulo_regions()
{
let msg = if let ty::Adt(def, _) = ty.kind()
- && [
- tcx.get_diagnostic_item(sym::Arc),
- tcx.get_diagnostic_item(sym::Rc),
- ].contains(&Some(def.did()))
+ && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
+ .contains(&Some(def.did()))
{
"clone the value to increment its reference count"
} else {
@@ -851,7 +848,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => MoveUseInGenerator { var_span },
+ Some(_) => MoveUseInCoroutine { var_span },
None => MoveUseInClosure { var_span },
}
});
@@ -897,7 +894,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let desc_place = self.describe_any_place(place.as_ref());
match kind {
Some(_) => {
- BorrowUsePlaceGenerator { place: desc_place, var_span, is_single_var: true }
+ BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
}
None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
}
@@ -929,8 +926,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_spans = self.borrow_spans(span, location);
let span = borrow_spans.args_or_use();
- let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
- "generator"
+ let container_name = if issued_spans.for_coroutine() || borrow_spans.for_coroutine() {
+ "coroutine"
} else {
"closure"
};
@@ -1043,7 +1040,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => BorrowUsePlaceGenerator {
+ Some(_) => BorrowUsePlaceCoroutine {
place: desc_place,
var_span,
is_single_var: true,
@@ -1127,7 +1124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => BorrowUsePlaceGenerator {
+ Some(_) => BorrowUsePlaceCoroutine {
place: desc_place,
var_span,
is_single_var: false,
@@ -1148,7 +1145,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
match kind {
Some(_) => {
- FirstBorrowUsePlaceGenerator { place: borrow_place_desc, var_span }
+ FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
}
None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
}
@@ -1162,7 +1159,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => SecondBorrowUsePlaceGenerator { place: desc_place, var_span },
+ Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span },
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
}
},
@@ -1328,42 +1325,160 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
issue_span: Span,
expr_span: Span,
body_expr: Option<&'hir hir::Expr<'hir>>,
- loop_bind: Option<Symbol>,
+ loop_bind: Option<&'hir Ident>,
+ loop_span: Option<Span>,
+ head_span: Option<Span>,
+ pat_span: Option<Span>,
+ head: Option<&'hir hir::Expr<'hir>>,
}
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
- if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind &&
- let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind &&
- let hir::ExprKind::Call(path, _args) = call.kind &&
- let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind &&
- let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind &&
- let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path &&
- let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field &&
- self.issue_span.source_equal(call.span) {
- self.loop_bind = Some(ident.name);
+ // Try to find
+ // let result = match IntoIterator::into_iter(<head>) {
+ // mut iter => {
+ // [opt_ident]: loop {
+ // match Iterator::next(&mut iter) {
+ // None => break,
+ // Some(<pat>) => <body>,
+ // };
+ // }
+ // }
+ // };
+ // corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
+ if let hir::ExprKind::Call(path, [arg]) = ex.kind
+ && let hir::ExprKind::Path(hir::QPath::LangItem(
+ LangItem::IntoIterIntoIter,
+ _,
+ _,
+ )) = path.kind
+ && arg.span.contains(self.issue_span)
+ {
+ // Find `IntoIterator::into_iter(<head>)`
+ self.head = Some(arg);
+ }
+ if let hir::ExprKind::Loop(
+ hir::Block { stmts: [stmt, ..], .. },
+ _,
+ hir::LoopSource::ForLoop,
+ _,
+ ) = ex.kind
+ && let hir::StmtKind::Expr(hir::Expr {
+ kind: hir::ExprKind::Match(call, [_, bind, ..], _),
+ span: head_span,
+ ..
+ }) = stmt.kind
+ && let hir::ExprKind::Call(path, _args) = call.kind
+ && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) =
+ path.kind
+ && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
+ && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
+ && call.span.contains(self.issue_span)
+ {
+ // Find `<pat>` and the span for the whole `for` loop.
+ if let PatField {
+ pat: hir::Pat { kind: hir::PatKind::Binding(_, _, ident, ..), .. },
+ ..
+ } = field
+ {
+ self.loop_bind = Some(ident);
}
+ self.head_span = Some(*head_span);
+ self.pat_span = Some(pat_span);
+ self.loop_span = Some(stmt.span);
+ }
- if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind &&
- body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) {
- self.body_expr = Some(ex);
+ if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind
+ && body_call.ident.name == sym::next
+ && recv.span.source_equal(self.expr_span)
+ {
+ self.body_expr = Some(ex);
}
hir::intravisit::walk_expr(self, ex);
}
}
- let mut finder =
- ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None };
+ let mut finder = ExprFinder {
+ expr_span: span,
+ issue_span,
+ loop_bind: None,
+ body_expr: None,
+ head_span: None,
+ loop_span: None,
+ pat_span: None,
+ head: None,
+ };
finder.visit_expr(hir.body(body_id).value);
- if let Some(loop_bind) = finder.loop_bind &&
- let Some(body_expr) = finder.body_expr &&
- let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) &&
- let Some(trait_did) = tcx.trait_of_item(def_id) &&
- tcx.is_diagnostic_item(sym::Iterator, trait_did) {
- err.note(format!(
- "a for loop advances the iterator for you, the result is stored in `{loop_bind}`."
+ if let Some(body_expr) = finder.body_expr
+ && let Some(loop_span) = finder.loop_span
+ && let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id)
+ && let Some(trait_did) = tcx.trait_of_item(def_id)
+ && tcx.is_diagnostic_item(sym::Iterator, trait_did)
+ {
+ if let Some(loop_bind) = finder.loop_bind {
+ err.note(format!(
+ "a for loop advances the iterator for you, the result is stored in `{}`",
+ loop_bind.name,
+ ));
+ } else {
+ err.note(
+ "a for loop advances the iterator for you, the result is stored in its pattern",
+ );
+ }
+ let msg = "if you want to call `next` on a iterator within the loop, consider using \
+ `while let`";
+ if let Some(head) = finder.head
+ && let Some(pat_span) = finder.pat_span
+ && loop_span.contains(body_expr.span)
+ && loop_span.contains(head.span)
+ {
+ let sm = self.infcx.tcx.sess.source_map();
+
+ let mut sugg = vec![];
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, _)) = head.kind {
+ // A bare path doesn't need a `let` assignment, it's already a simple
+ // binding access.
+ // As a new binding wasn't added, we don't need to modify the advancing call.
+ sugg.push((loop_span.with_hi(pat_span.lo()), format!("while let Some(")));
+ sugg.push((
+ pat_span.shrink_to_hi().with_hi(head.span.lo()),
+ ") = ".to_string(),
+ ));
+ sugg.push((head.span.shrink_to_hi(), ".next()".to_string()));
+ } else {
+ // Needs a new a `let` binding.
+ let indent = if let Some(indent) = sm.indentation_before(loop_span) {
+ format!("\n{indent}")
+ } else {
+ " ".to_string()
+ };
+ let Ok(head_str) = sm.span_to_snippet(head.span) else {
+ err.help(msg);
+ return;
+ };
+ sugg.push((
+ loop_span.with_hi(pat_span.lo()),
+ format!("let iter = {head_str};{indent}while let Some("),
+ ));
+ sugg.push((
+ pat_span.shrink_to_hi().with_hi(head.span.hi()),
+ ") = iter.next()".to_string(),
));
- err.help("if you want to call `next` on a iterator within the loop, consider using `while let`.");
+ // As a new binding was added, we should change how the iterator is advanced to
+ // use the newly introduced binding.
+ if let hir::ExprKind::MethodCall(_, recv, ..) = body_expr.kind
+ && let hir::ExprKind::Path(hir::QPath::Resolved(None, ..)) = recv.kind
+ {
+ // As we introduced a `let iter = <head>;`, we need to change where the
+ // already borrowed value was accessed from `<recv>.next()` to
+ // `iter.next()`.
+ sugg.push((recv.span, "iter".to_string()));
+ }
+ }
+ err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
+ } else {
+ err.help(msg);
+ }
}
}
@@ -1459,7 +1574,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Get closure's arguments
let ty::Closure(_, args) = typeck_results.expr_ty(closure_expr).kind() else {
- /* hir::Closure can be a generator too */
+ /* hir::Closure can be a coroutine too */
return;
};
let sig = args.as_closure().sig();
@@ -1539,69 +1654,80 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span.contains(self.capture_span) {
if let hir::ExprKind::Closure(&hir::Closure {
- movability: None,
- body,
- fn_arg_span,
- fn_decl: hir::FnDecl{ inputs, .. },
- ..
- }) = e.kind &&
- let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
- self.suggest_arg = "this: &Self".to_string();
- if inputs.len() > 0 {
- self.suggest_arg.push_str(", ");
- }
- self.in_closure = true;
- self.closure_arg_span = fn_arg_span;
- self.visit_expr(body);
- self.in_closure = false;
+ movability: None,
+ body,
+ fn_arg_span,
+ fn_decl: hir::FnDecl { inputs, .. },
+ ..
+ }) = e.kind
+ && let Some(hir::Node::Expr(body)) = self.hir.find(body.hir_id)
+ {
+ self.suggest_arg = "this: &Self".to_string();
+ if inputs.len() > 0 {
+ self.suggest_arg.push_str(", ");
+ }
+ self.in_closure = true;
+ self.closure_arg_span = fn_arg_span;
+ self.visit_expr(body);
+ self.in_closure = false;
}
}
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
- if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
- seg.ident.name == kw::SelfLower && self.in_closure {
- self.closure_change_spans.push(e.span);
+ if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
+ && seg.ident.name == kw::SelfLower
+ && self.in_closure
+ {
+ self.closure_change_spans.push(e.span);
}
}
hir::intravisit::walk_expr(self, e);
}
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
- if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
- let Some(init) = local.init
+ if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } =
+ local.pat
+ && let Some(init) = local.init
{
- if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
- movability: None,
- ..
- }), .. } = init &&
- init.span.contains(self.capture_span) {
- self.closure_local_id = Some(*hir_id);
+ if let hir::Expr {
+ kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
+ ..
+ } = init
+ && init.span.contains(self.capture_span)
+ {
+ self.closure_local_id = Some(*hir_id);
}
}
hir::intravisit::walk_local(self, local);
}
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
- if let hir::StmtKind::Semi(e) = s.kind &&
- let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
- let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
- let Res::Local(hir_id) = seg.res &&
- Some(hir_id) == self.closure_local_id {
- let (span, arg_str) = if args.len() > 0 {
- (args[0].span.shrink_to_lo(), "self, ".to_string())
- } else {
- let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
- (span, "(self)".to_string())
- };
- self.closure_call_changes.push((span, arg_str));
+ if let hir::StmtKind::Semi(e) = s.kind
+ && let hir::ExprKind::Call(
+ hir::Expr { kind: hir::ExprKind::Path(path), .. },
+ args,
+ ) = e.kind
+ && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
+ && let Res::Local(hir_id) = seg.res
+ && Some(hir_id) == self.closure_local_id
+ {
+ let (span, arg_str) = if args.len() > 0 {
+ (args[0].span.shrink_to_lo(), "self, ".to_string())
+ } else {
+ let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
+ (span, "(self)".to_string())
+ };
+ self.closure_call_changes.push((span, arg_str));
}
hir::intravisit::walk_stmt(self, s);
}
}
- if let Some(hir::Node::ImplItem(
- hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
- )) = hir.find(self.mir_hir_id()) &&
- let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
+ if let Some(hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(_fn_sig, body_id),
+ ..
+ })) = hir.find(self.mir_hir_id())
+ && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
+ {
let mut finder = ExpressionFinder {
capture_span: *capture_kind_span,
closure_change_spans: vec![],
@@ -1822,7 +1948,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
- ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
+ ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
@@ -1847,7 +1973,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
..
},
- ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
+ ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
@@ -1950,8 +2076,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.unwrap_or_else(|| {
match &self.infcx.tcx.def_kind(self.mir_def_id()) {
DefKind::Closure => "enclosing closure",
- DefKind::Generator => "enclosing generator",
- kind => bug!("expected closure or generator, found {:?}", kind),
+ DefKind::Coroutine => "enclosing coroutine",
+ kind => bug!("expected closure or coroutine, found {:?}", kind),
}
.to_string()
})
@@ -1985,7 +2111,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
- is_within: borrow_spans.for_generator(),
+ is_within: borrow_spans.for_coroutine(),
args_span,
}
});
@@ -2136,6 +2262,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
current: usize,
found: usize,
prop_expr: Option<&'tcx hir::Expr<'tcx>>,
+ call: Option<&'tcx hir::Expr<'tcx>>,
}
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
@@ -2145,6 +2272,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.current -= 1;
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind {
+ if self.span == rcvr.span.source_callsite() {
+ self.call = Some(expr);
+ }
+ }
if self.span == expr.span.source_callsite() {
self.found = self.current;
if self.prop_expr.is_none() {
@@ -2168,25 +2300,43 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
current: 0,
found: 0,
prop_expr: None,
+ call: None,
};
visitor.visit_stmt(stmt);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
- let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
+ let expr_ty: Option<Ty<'_>> =
+ visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
- let is_format_arguments_item =
- if let Some(expr_ty) = expr_ty
- && let ty::Adt(adt, _) = expr_ty.kind() {
- self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
- } else {
- false
- };
+ let is_format_arguments_item = if let Some(expr_ty) = expr_ty
+ && let ty::Adt(adt, _) = expr_ty.kind()
+ {
+ self.infcx.tcx.lang_items().get(LangItem::FormatArguments)
+ == Some(adt.did())
+ } else {
+ false
+ };
if visitor.found == 0
&& stmt.span.contains(proper_span)
&& let Some(p) = sm.span_to_margin(stmt.span)
&& let Ok(s) = sm.span_to_snippet(proper_span)
{
+ if let Some(call) = visitor.call
+ && let hir::ExprKind::MethodCall(path, _, [], _) = call.kind
+ && path.ident.name == sym::iter
+ && let Some(ty) = expr_ty
+ {
+ err.span_suggestion_verbose(
+ path.ident.span,
+ format!(
+ "consider consuming the `{ty}` when turning it into an \
+ `Iterator`",
+ ),
+ "into_iter".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
if !is_format_arguments_item {
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
err.multipart_suggestion_verbose(
@@ -2224,7 +2374,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
- is_within: borrow_spans.for_generator(),
+ is_within: borrow_spans.for_coroutine(),
args_span,
}
});
@@ -2340,11 +2490,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
Ok(string) => {
- if string.starts_with("async ") {
- let pos = args_span.lo() + BytePos(6);
- (args_span.with_lo(pos).with_hi(pos), "move ")
- } else if string.starts_with("async|") {
- let pos = args_span.lo() + BytePos(5);
+ let coro_prefix = if string.starts_with("async") {
+ // `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` to `u32`
+ Some(5)
+ } else if string.starts_with("gen") {
+ // `gen` is 3 chars long
+ Some(3)
+ } else {
+ None
+ };
+ if let Some(n) = coro_prefix {
+ let pos = args_span.lo() + BytePos(n);
(args_span.with_lo(pos).with_hi(pos), " move")
} else {
(args_span.shrink_to_lo(), "move ")
@@ -2352,14 +2508,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
Err(_) => (args_span, "move |<args>| <body>"),
};
- let kind = match use_span.generator_kind() {
- Some(generator_kind) => match generator_kind {
- GeneratorKind::Async(async_kind) => match async_kind {
- AsyncGeneratorKind::Block => "async block",
- AsyncGeneratorKind::Closure => "async closure",
+ let kind = match use_span.coroutine_kind() {
+ Some(coroutine_kind) => match coroutine_kind {
+ CoroutineKind::Gen(kind) => match kind {
+ CoroutineSource::Block => "gen block",
+ CoroutineSource::Closure => "gen closure",
+ _ => bug!("gen block/closure expected, but gen function found."),
+ },
+ CoroutineKind::Async(async_kind) => match async_kind {
+ CoroutineSource::Block => "async block",
+ CoroutineSource::Closure => "async closure",
_ => bug!("async block/closure expected, but async function found."),
},
- GeneratorKind::Gen => "generator",
+ CoroutineKind::Coroutine => "coroutine",
},
None => "closure",
};
@@ -2388,7 +2549,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
ConstraintCategory::CallArgument(_) => {
fr_name.highlight_region_name(&mut err);
- if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
+ if matches!(use_span.coroutine_kind(), Some(CoroutineKind::Async(_))) {
err.note(
"async blocks are not executed immediately and must either take a \
reference or ownership of outside variables they use",
@@ -2482,9 +2643,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/* Check if the mpi is initialized as an argument */
let mut is_argument = false;
for arg in self.body.args_iter() {
- let path = self.move_data.rev_lookup.find_local(arg);
- if mpis.contains(&path) {
- is_argument = true;
+ if let Some(path) = self.move_data.rev_lookup.find_local(arg) {
+ if mpis.contains(&path) {
+ is_argument = true;
+ }
}
}
@@ -2656,7 +2818,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => BorrowUseInGenerator { var_span },
+ Some(_) => BorrowUseInCoroutine { var_span },
None => BorrowUseInClosure { var_span },
}
});
@@ -2672,7 +2834,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
- Some(_) => BorrowUseInGenerator { var_span },
+ Some(_) => BorrowUseInCoroutine { var_span },
None => BorrowUseInClosure { var_span },
}
});
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index c66a24473..8a930ca59 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -76,10 +76,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
expr_finder.visit_expr(body.value);
if let Some(mut expr) = expr_finder.result {
while let hir::ExprKind::AddrOf(_, _, inner)
- | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
- | hir::ExprKind::Field(inner, _)
- | hir::ExprKind::MethodCall(_, inner, _, _)
- | hir::ExprKind::Index(inner, _, _) = &expr.kind
+ | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
+ | hir::ExprKind::Field(inner, _)
+ | hir::ExprKind::MethodCall(_, inner, _, _)
+ | hir::ExprKind::Index(inner, _, _) = &expr.kind
{
expr = inner;
}
@@ -88,10 +88,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
&& let hir::def::Res::Local(hir_id) = p.res
&& let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
{
- err.span_label(
- pat.span,
- format!("binding `{ident}` declared here"),
- );
+ err.span_label(pat.span, format!("binding `{ident}` declared here"));
}
}
}
@@ -185,7 +182,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
// Otherwise, just report the whole type (and use
// the intentionally fuzzy phrase "destructor")
ty::Closure(..) => ("destructor", "closure".to_owned()),
- ty::Generator(..) => ("destructor", "generator".to_owned()),
+ ty::Coroutine(..) => ("destructor", "coroutine".to_owned()),
_ => ("destructor", format!("type `{}`", local_decl.ty)),
};
@@ -419,7 +416,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.local_names[local].is_some()
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
&& let Some(borrowed_local) = place.as_local()
- && self.local_names[borrowed_local].is_some() && local != borrowed_local
+ && self.local_names[borrowed_local].is_some()
+ && local != borrowed_local
{
should_note_order = true;
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 8d4028de9..c4323fef9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -8,7 +8,7 @@ use itertools::Itertools;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::GeneratorKind;
+use rustc_hir::CoroutineKind;
use rustc_index::IndexSlice;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::tcx::PlaceTy;
@@ -46,6 +46,7 @@ mod mutability_errors;
mod region_errors;
pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
+pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError};
pub(crate) use mutability_errors::AccessKind;
pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
@@ -369,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Array(ty, _) | ty::Slice(ty) => {
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
}
- ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
+ ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
// We won't be borrowck'ing here if the closure came from another crate,
// so it's safe to call `expect_local`.
//
@@ -470,7 +471,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- ty.print(printer).unwrap().into_buffer()
+ ty.print(&mut printer).unwrap();
+ printer.into_buffer()
}
/// Returns the name of the provided `Ty` (that must be a reference)'s region with a
@@ -492,7 +494,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
bug!("ty for annotation of borrow region is not a reference");
};
- region.print(printer).unwrap().into_buffer()
+ region.print(&mut printer).unwrap();
+ printer.into_buffer()
}
}
@@ -501,8 +504,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
pub(super) enum UseSpans<'tcx> {
/// The access is caused by capturing a variable for a closure.
ClosureUse {
- /// This is true if the captured variable was from a generator.
- generator_kind: Option<GeneratorKind>,
+ /// This is true if the captured variable was from a coroutine.
+ coroutine_kind: Option<CoroutineKind>,
/// The span of the args of the closure, including the `move` keyword if
/// it's present.
args_span: Span,
@@ -569,9 +572,9 @@ impl UseSpans<'_> {
}
}
- pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
+ pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
match self {
- UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
+ UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind,
_ => None,
}
}
@@ -596,14 +599,14 @@ impl UseSpans<'_> {
) {
use crate::InitializationRequiringAction::*;
use CaptureVarPathUseCause::*;
- if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
- match generator_kind {
+ if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self {
+ match coroutine_kind {
Some(_) => {
err.subdiagnostic(match action {
- Borrow => BorrowInGenerator { path_span },
- MatchOn | Use => UseInGenerator { path_span },
- Assignment => AssignInGenerator { path_span },
- PartialAssignment => AssignPartInGenerator { path_span },
+ Borrow => BorrowInCoroutine { path_span },
+ MatchOn | Use => UseInCoroutine { path_span },
+ Assignment => AssignInCoroutine { path_span },
+ PartialAssignment => AssignPartInCoroutine { path_span },
});
}
None => {
@@ -624,9 +627,9 @@ impl UseSpans<'_> {
handler: Option<&rustc_errors::Handler>,
err: &mut Diagnostic,
kind: Option<rustc_middle::mir::BorrowKind>,
- f: impl FnOnce(Option<GeneratorKind>, Span) -> CaptureVarCause,
+ f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
) {
- if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
+ if let UseSpans::ClosureUse { coroutine_kind, capture_kind_span, path_span, .. } = self {
if capture_kind_span != path_span {
err.subdiagnostic(match kind {
Some(kd) => match kd {
@@ -642,7 +645,7 @@ impl UseSpans<'_> {
None => CaptureVarKind::Move { kind_span: capture_kind_span },
});
};
- let diag = f(generator_kind, path_span);
+ let diag = f(coroutine_kind, path_span);
match handler {
Some(hd) => err.eager_subdiagnostic(hd, diag),
None => err.subdiagnostic(diag),
@@ -653,15 +656,15 @@ impl UseSpans<'_> {
/// Returns `false` if this place is not used in a closure.
pub(super) fn for_closure(&self) -> bool {
match *self {
- UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
+ UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(),
_ => false,
}
}
- /// Returns `false` if this place is not used in a generator.
- pub(super) fn for_generator(&self) -> bool {
+ /// Returns `false` if this place is not used in a coroutine.
+ pub(super) fn for_coroutine(&self) -> bool {
match *self {
- UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
+ UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_some(),
_ => false,
}
}
@@ -780,19 +783,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
- && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
+ && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) =
+ **kind
{
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
let def_id = def_id.expect_local();
- if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
+ if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
self.closure_span(def_id, moved_place, places)
{
- return ClosureUse {
- generator_kind,
- args_span,
- capture_kind_span,
- path_span,
- };
+ return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
}
}
@@ -804,11 +803,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| FakeReadCause::ForLet(Some(closure_def_id)) => {
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
let places = &[Operand::Move(place)];
- if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
+ if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
{
return ClosureUse {
- generator_kind,
+ coroutine_kind,
args_span,
capture_kind_span,
path_span,
@@ -918,21 +917,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for stmt in statements.chain(maybe_additional_statement) {
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
- let (&def_id, is_generator) = match kind {
+ let (&def_id, is_coroutine) = match kind {
box AggregateKind::Closure(def_id, _) => (def_id, false),
- box AggregateKind::Generator(def_id, _, _) => (def_id, true),
+ box AggregateKind::Coroutine(def_id, _, _) => (def_id, true),
_ => continue,
};
let def_id = def_id.expect_local();
debug!(
- "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
- def_id, is_generator, places
+ "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
+ def_id, is_coroutine, places
);
- if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
+ if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
self.closure_span(def_id, Place::from(target).as_ref(), places)
{
- return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
+ return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
} else {
return OtherUse(use_span);
}
@@ -946,7 +945,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
OtherUse(use_span)
}
- /// Finds the spans of a captured place within a closure or generator.
+ /// Finds the spans of a captured place within a closure or coroutine.
/// The first span is the location of the use resulting in the capture kind of the capture
/// The second span is the location the use resulting in the captured path of the capture
fn closure_span(
@@ -954,7 +953,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id: LocalDefId,
target_place: PlaceRef<'tcx>,
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
- ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
+ ) -> Option<(Span, Option<CoroutineKind>, Span, Span)> {
debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}",
def_id, target_place, places
@@ -972,11 +971,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
{
debug!("closure_span: found captured local {:?}", place);
let body = self.infcx.tcx.hir().body(body);
- let generator_kind = body.generator_kind();
+ let coroutine_kind = body.coroutine_kind();
return Some((
fn_decl_span,
- generator_kind,
+ coroutine_kind,
captured_place.get_capture_kind_span(self.infcx.tcx),
captured_place.get_path_span(self.infcx.tcx),
));
@@ -1123,7 +1122,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
CaptureReasonSuggest::FreshReborrow {
span: move_span.shrink_to_hi(),
- });
+ },
+ );
}
if let Some(clone_trait) = tcx.lang_items().clone_trait()
&& let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
@@ -1191,7 +1191,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// another message for the same span
if !is_loop_message {
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
- Some(_) => CaptureVarCause::PartialMoveUseInGenerator { var_span, is_partial },
+ Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial },
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
})
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index e05c04e11..41d6b98d7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -1,16 +1,50 @@
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::mir::*;
-use rustc_middle::ty;
-use rustc_mir_dataflow::move_paths::{
- IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
-};
-use rustc_span::{BytePos, Span};
+use rustc_middle::ty::{self, Ty};
+use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
+use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
use crate::diagnostics::CapturedMessageOpt;
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
+#[derive(Debug)]
+pub enum IllegalMoveOriginKind<'tcx> {
+ /// Illegal move due to attempt to move from behind a reference.
+ BorrowedContent {
+ /// The place the reference refers to: if erroneous code was trying to
+ /// move from `(*x).f` this will be `*x`.
+ target_place: Place<'tcx>,
+ },
+
+ /// Illegal move due to attempt to move from field of an ADT that
+ /// implements `Drop`. Rust maintains invariant that all `Drop`
+ /// ADT's remain fully-initialized so that user-defined destructor
+ /// can safely read from all of the ADT's fields.
+ InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> },
+
+ /// Illegal move due to attempt to move out of a slice or array.
+ InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool },
+}
+
+#[derive(Debug)]
+pub(crate) struct MoveError<'tcx> {
+ place: Place<'tcx>,
+ location: Location,
+ kind: IllegalMoveOriginKind<'tcx>,
+}
+
+impl<'tcx> MoveError<'tcx> {
+ pub(crate) fn new(
+ place: Place<'tcx>,
+ location: Location,
+ kind: IllegalMoveOriginKind<'tcx>,
+ ) -> Self {
+ MoveError { place, location, kind }
+ }
+}
+
// Often when desugaring a pattern match we may have many individual moves in
// MIR that are all part of one operation from the user's point-of-view. For
// example:
@@ -53,20 +87,18 @@ enum GroupedMoveError<'tcx> {
}
impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
- pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
- let grouped_errors = self.group_move_errors(move_errors);
+ pub(crate) fn report_move_errors(&mut self) {
+ let grouped_errors = self.group_move_errors();
for error in grouped_errors {
self.report(error);
}
}
- fn group_move_errors(
- &self,
- errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
- ) -> Vec<GroupedMoveError<'tcx>> {
+ fn group_move_errors(&mut self) -> Vec<GroupedMoveError<'tcx>> {
let mut grouped_errors = Vec::new();
- for (original_path, error) in errors {
- self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
+ let errors = std::mem::take(&mut self.move_errors);
+ for error in errors {
+ self.append_to_grouped_errors(&mut grouped_errors, error);
}
grouped_errors
}
@@ -74,66 +106,58 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn append_to_grouped_errors(
&self,
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
- original_path: Place<'tcx>,
error: MoveError<'tcx>,
) {
- match error {
- MoveError::UnionMove { .. } => {
- unimplemented!("don't know how to report union move errors yet.")
- }
- MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind } } => {
- // Note: that the only time we assign a place isn't a temporary
- // to a user variable is when initializing it.
- // If that ever stops being the case, then the ever initialized
- // flow could be used.
- if let Some(StatementKind::Assign(box (
- place,
- Rvalue::Use(Operand::Move(move_from)),
- ))) = self.body.basic_blocks[location.block]
- .statements
- .get(location.statement_index)
- .map(|stmt| &stmt.kind)
+ let MoveError { place: original_path, location, kind } = error;
+
+ // Note: that the only time we assign a place isn't a temporary
+ // to a user variable is when initializing it.
+ // If that ever stops being the case, then the ever initialized
+ // flow could be used.
+ if let Some(StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(move_from))))) =
+ self.body.basic_blocks[location.block]
+ .statements
+ .get(location.statement_index)
+ .map(|stmt| &stmt.kind)
+ {
+ if let Some(local) = place.as_local() {
+ let local_decl = &self.body.local_decls[local];
+ // opt_match_place is the
+ // match_span is the span of the expression being matched on
+ // match *x.y { ... } match_place is Some(*x.y)
+ // ^^^^ match_span is the span of *x.y
+ //
+ // opt_match_place is None for let [mut] x = ... statements,
+ // whether or not the right-hand side is a place expression
+ if let LocalInfo::User(BindingForm::Var(VarBindingForm {
+ opt_match_place: Some((opt_match_place, match_span)),
+ binding_mode: _,
+ opt_ty_info: _,
+ pat_span: _,
+ })) = *local_decl.local_info()
{
- if let Some(local) = place.as_local() {
- let local_decl = &self.body.local_decls[local];
- // opt_match_place is the
- // match_span is the span of the expression being matched on
- // match *x.y { ... } match_place is Some(*x.y)
- // ^^^^ match_span is the span of *x.y
- //
- // opt_match_place is None for let [mut] x = ... statements,
- // whether or not the right-hand side is a place expression
- if let LocalInfo::User(BindingForm::Var(VarBindingForm {
- opt_match_place: Some((opt_match_place, match_span)),
- binding_mode: _,
- opt_ty_info: _,
- pat_span: _,
- })) = *local_decl.local_info()
- {
- let stmt_source_info = self.body.source_info(location);
- self.append_binding_error(
- grouped_errors,
- kind,
- original_path,
- *move_from,
- local,
- opt_match_place,
- match_span,
- stmt_source_info.span,
- );
- return;
- }
- }
+ let stmt_source_info = self.body.source_info(location);
+ self.append_binding_error(
+ grouped_errors,
+ kind,
+ original_path,
+ *move_from,
+ local,
+ opt_match_place,
+ match_span,
+ stmt_source_info.span,
+ );
+ return;
}
-
- let move_spans = self.move_spans(original_path.as_ref(), location);
- grouped_errors.push(GroupedMoveError::OtherIllegalMove {
- use_spans: move_spans,
- original_path,
- kind,
- });
}
}
+
+ let move_spans = self.move_spans(original_path.as_ref(), location);
+ grouped_errors.push(GroupedMoveError::OtherIllegalMove {
+ use_spans: move_spans,
+ original_path,
+ kind,
+ });
}
fn append_binding_error(
@@ -464,6 +488,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
args_span,
}
});
+
+ self.add_note_for_packed_struct_derive(err, original_path.local);
}
}
}
@@ -570,4 +596,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
}
}
+
+ /// Adds an explanatory note if the move error occurs in a derive macro
+ /// expansion of a packed struct.
+ /// Such errors happen because derive macro expansions shy away from taking
+ /// references to the struct's fields since doing so would be undefined behaviour
+ fn add_note_for_packed_struct_derive(&self, err: &mut Diagnostic, local: Local) {
+ let local_place: PlaceRef<'tcx> = local.into();
+ let local_ty = local_place.ty(self.body.local_decls(), self.infcx.tcx).ty.peel_refs();
+
+ if let Some(adt) = local_ty.ty_adt_def()
+ && adt.repr().packed()
+ && let ExpnKind::Macro(MacroKind::Derive, name) = self.body.span.ctxt().outer_expn_data().kind
+ {
+ err.note(format!("`#[derive({name})]` triggers a move because taking references to the fields of a packed struct is undefined behaviour"));
+ }
+ }
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 8ca57383e..dde46eef6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -9,9 +9,8 @@ use rustc_middle::{
hir::place::PlaceBase,
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, Span};
use rustc_target::abi::FieldIdx;
use crate::diagnostics::BorrowedContentSource;
@@ -62,7 +61,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
- debug_assert!(is_closure_or_generator(
+ debug_assert!(is_closure_or_coroutine(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
@@ -122,7 +121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
item_msg = access_place_desc;
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
- debug_assert!(is_closure_or_generator(
+ debug_assert!(is_closure_or_coroutine(
the_place_err.ty(self.body, self.infcx.tcx).ty
));
@@ -385,7 +384,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
- debug_assert!(is_closure_or_generator(
+ debug_assert!(is_closure_or_coroutine(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
@@ -396,17 +395,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_hir_id = captured_place.get_root_variable();
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
- && let hir::PatKind::Binding(
- hir::BindingAnnotation::NONE,
- _,
- upvar_ident,
- _,
- ) = pat.kind
+ && let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) =
+ pat.kind
{
if upvar_ident.name == kw::SelfLower {
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
if let Some(fn_decl) = node.fn_decl() {
- if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) {
+ if !matches!(
+ fn_decl.implicit_self,
+ hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
+ ) {
err.span_suggestion(
upvar_ident.span,
"consider changing this to be mutable",
@@ -573,7 +571,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.ty,
),
vec![
- vec![ // val.insert(index, rv);
+ vec![
+ // val.insert(index, rv);
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".insert(".to_string(),
@@ -584,7 +583,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
),
(rv.span.shrink_to_hi(), ")".to_string()),
],
- vec![ // val.get_mut(index).map(|v| { *v = rv; });
+ vec![
+ // val.get_mut(index).map(|v| { *v = rv; });
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(),
@@ -593,12 +593,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
index.span.shrink_to_hi().with_hi(place.span.hi()),
").map(|val| { *val".to_string(),
),
- (
- rv.span.shrink_to_hi(),
- "; })".to_string(),
- ),
+ (rv.span.shrink_to_hi(), "; })".to_string()),
],
- vec![ // let x = val.entry(index).or_insert(rv);
+ vec![
+ // let x = val.entry(index).or_insert(rv);
(val.span.shrink_to_lo(), "let val = ".to_string()),
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
@@ -747,10 +745,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
{
let body = hir_map.body(body_id);
- let mut v = BindingFinder {
- span: pat_span,
- hir_id: None,
- };
+ let mut v = BindingFinder { span: pat_span, hir_id: None };
v.visit_body(body);
v.hir_id
} else {
@@ -766,7 +761,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
..
})) = hir_map.find(hir_id)
- && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
+ && let Ok(name) =
+ self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
{
err.span_suggestion(
pat_span,
@@ -879,12 +875,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
// expression with that span in order to identify potential fixes when encountering a
// read-only iterator that should be mutable.
- let mut v = Finder {
- span,
- expr: None,
- };
+ let mut v = Finder { span, expr: None };
v.visit_block(block);
- if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind {
+ if let Some(expr) = v.expr
+ && let Call(_, [expr]) = expr.kind
+ {
match expr.kind {
MethodCall(path_segment, _, _, span) => {
// We have `for _ in iter.read_only_iter()`, try to
@@ -1032,38 +1027,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let source = self.body.source;
let hir = self.infcx.tcx.hir();
if let InstanceDef::Item(def_id) = source.instance
- && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
- && let ExprKind::Closure(closure) = kind && closure.movability == None
- && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
- let mut cur_expr = expr;
- while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
- if path_segment.ident.name == sym::iter {
- // check `_ty` has `iter_mut` method
- let res = self
- .infcx
- .tcx
- .typeck(path_segment.hir_id.owner.def_id)
- .type_dependent_def_id(cur_expr.hir_id)
- .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
- .map(|def_id| self.infcx.tcx.associated_items(def_id))
- .map(|assoc_items| {
- assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
- });
-
- if let Some(mut res) = res && res.peek().is_some() {
- err.span_suggestion_verbose(
- path_segment.ident.span,
- "you may want to use `iter_mut` here",
- "iter_mut",
- Applicability::MaybeIncorrect,
- );
- }
- break;
- } else {
- cur_expr = recv;
+ && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
+ && let ExprKind::Closure(closure) = kind
+ && closure.movability == None
+ && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
+ {
+ let mut cur_expr = expr;
+ while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
+ if path_segment.ident.name == sym::iter {
+ // check `_ty` has `iter_mut` method
+ let res = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner.def_id)
+ .type_dependent_def_id(cur_expr.hir_id)
+ .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+ .map(|def_id| self.infcx.tcx.associated_items(def_id))
+ .map(|assoc_items| {
+ assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
+ });
+
+ if let Some(mut res) = res
+ && res.peek().is_some()
+ {
+ err.span_suggestion_verbose(
+ path_segment.ident.span,
+ "you may want to use `iter_mut` here",
+ "iter_mut",
+ Applicability::MaybeIncorrect,
+ );
}
+ break;
+ } else {
+ cur_expr = recv;
}
}
+ }
}
fn suggest_make_local_mut(
@@ -1200,14 +1199,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
- let hir_id = if let Some(local_def_id) = def_id.as_local() &&
- let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
+ let hir_id = if let Some(local_def_id) = def_id.as_local()
+ && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
{
let body = hir_map.body(body_id);
- let mut v = BindingFinder {
- span: err_label_span,
- hir_id: None,
- };
+ let mut v = BindingFinder { span: err_label_span, hir_id: None };
v.visit_body(body);
v.hir_id
} else {
@@ -1215,15 +1211,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(hir_id) = hir_id
- && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+ && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
{
let (changing, span, sugg) = match local.ty {
Some(ty) => ("changing", ty.span, message),
- None => (
- "specifying",
- local.pat.span.shrink_to_hi(),
- format!(": {message}"),
- ),
+ None => {
+ ("specifying", local.pat.span.shrink_to_hi(), format!(": {message}"))
+ }
};
err.span_suggestion_verbose(
span,
@@ -1234,9 +1228,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else {
err.span_label(
err_label_span,
- format!(
- "consider changing this binding's type to be: `{message}`"
- ),
+ format!("consider changing this binding's type to be: `{message}`"),
);
}
}
@@ -1359,9 +1351,9 @@ fn suggest_ampmut<'tcx>(
None => (false, decl_span),
};
- // if the binding already exists and is a reference with a explicit
+ // if the binding already exists and is a reference with an explicit
// lifetime, then we can suggest adding ` mut`. this is special-cased from
- // the path without a explicit lifetime.
+ // the path without an explicit lifetime.
if let Ok(src) = tcx.sess.source_map().span_to_snippet(span)
&& src.starts_with("&'")
// note that `& 'a T` is invalid so this is correct.
@@ -1380,16 +1372,12 @@ fn suggest_ampmut<'tcx>(
let ty_mut = decl_ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
- (
- false,
- span,
- format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty)
- )
+ (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty))
}
}
-fn is_closure_or_generator(ty: Ty<'_>) -> bool {
- ty.is_closure() || ty.is_generator()
+fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
+ ty.is_closure() || ty.is_coroutine()
}
/// Given a field that needs to be mutable, returns a span where the " mut " could go.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 27072a60f..a0a809123 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -580,7 +580,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let err = FnMutError {
span: *span,
ty_err: match output_ty.kind() {
- ty::Generator(def, ..) if self.infcx.tcx.generator_is_async(*def) => {
+ ty::Coroutine(def, ..) if self.infcx.tcx.coroutine_is_async(*def) => {
FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
}
_ if output_ty.contains_closure() => {
@@ -1036,7 +1036,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..
}) => {
let body = map.body(*body);
- if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
+ if !matches!(body.coroutine_kind, Some(hir::CoroutineKind::Async(..))) {
closure_span = Some(expr.span.shrink_to_lo());
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 55d581b3a..d38cfbc54 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -41,7 +41,7 @@ pub(crate) enum RegionNameSource {
AnonRegionFromUpvar(Span, Symbol),
/// The region corresponding to the return type of a closure.
AnonRegionFromOutput(RegionNameHighlight, &'static str),
- /// The region from a type yielded by a generator.
+ /// The region from a type yielded by a coroutine.
AnonRegionFromYieldTy(Span, String),
/// An anonymous region from an async fn.
AnonRegionFromAsyncFn(Span),
@@ -322,7 +322,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let def_ty = self.regioncx.universal_regions().defining_ty;
let DefiningTy::Closure(_, args) = def_ty else {
- // Can't have BrEnv in functions, constants or generators.
+ // Can't have BrEnv in functions, constants or coroutines.
bug!("BrEnv outside of closure.");
};
let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) =
@@ -680,16 +680,16 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
}
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
};
- let mir_description = match hir.body(body).generator_kind {
- Some(hir::GeneratorKind::Async(gen)) => match gen {
- hir::AsyncGeneratorKind::Block => " of async block",
- hir::AsyncGeneratorKind::Closure => " of async closure",
- hir::AsyncGeneratorKind::Fn => {
+ let mir_description = match hir.body(body).coroutine_kind {
+ Some(hir::CoroutineKind::Async(gen)) => match gen {
+ hir::CoroutineSource::Block => " of async block",
+ hir::CoroutineSource::Closure => " of async closure",
+ hir::CoroutineSource::Fn => {
let parent_item =
hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
- .expect("generator lowered from async fn should be in fn")
+ .expect("coroutine lowered from async fn should be in fn")
.output;
span = output.span();
if let hir::FnRetTy::Return(ret) = output {
@@ -698,7 +698,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
" of async function"
}
},
- Some(hir::GeneratorKind::Gen) => " of generator",
+ Some(hir::CoroutineKind::Gen(gen)) => match gen {
+ hir::CoroutineSource::Block => " of gen block",
+ hir::CoroutineSource::Closure => " of gen closure",
+ hir::CoroutineSource::Fn => {
+ let parent_item =
+ hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
+ let output = &parent_item
+ .fn_decl()
+ .expect("coroutine lowered from gen fn should be in fn")
+ .output;
+ span = output.span();
+ " of gen function"
+ }
+ },
+ Some(hir::CoroutineKind::Coroutine) => " of coroutine",
None => " of closure",
};
(span, mir_description, hir_ty)
@@ -793,7 +807,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
&self,
fr: RegionVid,
) -> Option<RegionName> {
- // Note: generators from `async fn` yield `()`, so we don't have to
+ // Note: coroutines from `async fn` yield `()`, so we don't have to
// worry about them here.
let yield_ty = self.regioncx.universal_regions().yield_ty?;
debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty);
@@ -942,9 +956,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
_ => return false,
}
- tcx.any_free_region_meets(pred, |r| {
- *r == ty::ReEarlyBound(region)
- })
+ tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region))
})
} else {
false
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 8832d345d..3a104c524 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -6,8 +6,8 @@ use crate::Upvar;
use rustc_index::IndexSlice;
use rustc_middle::mir::{Body, Local};
use rustc_middle::ty::{RegionVid, TyCtxt};
-use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
+use rustc_span::Span;
impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn get_var_name_and_span_for_region(