Skip to content

Commit 80cfebe

Browse files
committed
Tweak borrowck label pointing at !Copy value moved into closure
When encountering a non-`Copy` value that is moved into a closure which is coming directly from a fn parameter, point at the parameter's type when mentioning it is not `Copy`. Before: ``` error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure --> f111.rs:14:25 | 13 | fn do_stuff(foo: Option<Foo>) { | --- captured outer variable 14 | require_fn_trait(|| async { | -- ^^^^^ `foo` is moved here | | | captured by this `Fn` closure 15 | if foo.map_or(false, |f| f.foo()) { | --- | | | variable moved due to use in coroutine | move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait ``` After: ``` error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure --> f111.rs:14:25 | 13 | fn do_stuff(foo: Option<Foo>) { | --- ----------- move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait | | | captured outer variable 14 | require_fn_trait(|| async { | -- ^^^^^ `foo` is moved here | | | captured by this `Fn` closure 15 | if foo.map_or(false, |f| f.foo()) { | --- variable moved due to use in coroutine ```
1 parent 8231065 commit 80cfebe

File tree

2 files changed

+82
-53
lines changed

2 files changed

+82
-53
lines changed

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
115115
fn append_to_grouped_errors(
116116
&self,
117117
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
118-
error: MoveError<'tcx>,
118+
MoveError { place: original_path, ___location, kind }: MoveError<'tcx>,
119119
) {
120-
let MoveError { place: original_path, ___location, kind } = error;
121-
122120
// Note: that the only time we assign a place isn't a temporary
123121
// to a user variable is when initializing it.
124122
// If that ever stops being the case, then the ever initialized
@@ -251,54 +249,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
251249
}
252250

253251
fn report(&mut self, error: GroupedMoveError<'tcx>) {
254-
let (mut err, err_span) = {
255-
let (span, use_spans, original_path, kind) = match error {
256-
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
257-
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
258-
(span, None, original_path, kind)
259-
}
260-
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
261-
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
262-
}
263-
};
264-
debug!(
265-
"report: original_path={:?} span={:?}, kind={:?} \
266-
original_path.is_upvar_field_projection={:?}",
267-
original_path,
268-
span,
269-
kind,
270-
self.is_upvar_field_projection(original_path.as_ref())
271-
);
272-
if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
273-
// If the type may implement Copy, skip the error.
274-
// It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
275-
self.dcx().span_delayed_bug(
252+
let (span, use_spans, original_path, kind) = match error {
253+
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
254+
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
255+
(span, None, original_path, kind)
256+
}
257+
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
258+
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
259+
}
260+
};
261+
debug!(
262+
"report: original_path={:?} span={:?}, kind={:?} \
263+
original_path.is_upvar_field_projection={:?}",
264+
original_path,
265+
span,
266+
kind,
267+
self.is_upvar_field_projection(original_path.as_ref())
268+
);
269+
if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
270+
// If the type may implement Copy, skip the error.
271+
// It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
272+
self.dcx()
273+
.span_delayed_bug(span, "Type may implement copy, but there is no other error.");
274+
return;
275+
}
276+
let mut err = match kind {
277+
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
278+
.report_cannot_move_from_borrowed_content(
279+
original_path,
280+
target_place,
276281
span,
277-
"Type may implement copy, but there is no other error.",
278-
);
279-
return;
282+
use_spans,
283+
),
284+
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
285+
self.cannot_move_out_of_interior_of_drop(span, ty)
286+
}
287+
&IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
288+
self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
280289
}
281-
(
282-
match kind {
283-
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
284-
.report_cannot_move_from_borrowed_content(
285-
original_path,
286-
target_place,
287-
span,
288-
use_spans,
289-
),
290-
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
291-
self.cannot_move_out_of_interior_of_drop(span, ty)
292-
}
293-
&IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
294-
self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
295-
}
296-
},
297-
span,
298-
)
299290
};
300291

301-
self.add_move_hints(error, &mut err, err_span);
292+
self.add_move_hints(error, &mut err, span);
302293
self.buffer_error(err);
303294
}
304295

@@ -482,7 +473,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
482473
self.cannot_move_out_of_interior_noncopy(span, ty, None)
483474
}
484475
ty::Closure(def_id, closure_args)
485-
if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
476+
if def_id.as_local() == Some(self.mir_def_id())
477+
&& let Some(upvar_field) = upvar_field =>
486478
{
487479
let closure_kind_ty = closure_args.as_closure().kind_ty();
488480
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
@@ -495,7 +487,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
495487
let capture_description =
496488
format!("captured variable in an `{closure_kind}` closure");
497489

498-
let upvar = &self.upvars[upvar_field.unwrap().index()];
490+
let upvar = &self.upvars[upvar_field.index()];
499491
let upvar_hir_id = upvar.get_root_variable();
500492
let upvar_name = upvar.to_string(tcx);
501493
let upvar_span = tcx.hir_span(upvar_hir_id);
@@ -604,8 +596,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
604596
self.add_move_error_details(err, &binds_to);
605597
}
606598
// No binding. Nothing to suggest.
607-
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
608-
let use_span = use_spans.var_or_use();
599+
GroupedMoveError::OtherIllegalMove {
600+
ref original_path, use_spans, ref kind, ..
601+
} => {
602+
let mut use_span = use_spans.var_or_use();
609603
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
610604
let place_desc = match self.describe_place(original_path.as_ref()) {
611605
Some(desc) => format!("`{desc}`"),
@@ -622,6 +616,39 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
622616
);
623617
}
624618

619+
if let IllegalMoveOriginKind::BorrowedContent { target_place } = &kind
620+
&& let ty = target_place.ty(self.body, self.infcx.tcx).ty
621+
&& let ty::Closure(def_id, _) = ty.kind()
622+
&& def_id.as_local() == Some(self.mir_def_id())
623+
&& let Some(upvar_field) = self
624+
.prefixes(original_path.as_ref(), PrefixSet::All)
625+
.find_map(|p| self.is_upvar_field_projection(p))
626+
&& let upvar = &self.upvars[upvar_field.index()]
627+
&& let upvar_hir_id = upvar.get_root_variable()
628+
&& let hir::Node::Param(param) = self.infcx.tcx.parent_hir_node(upvar_hir_id)
629+
{
630+
// Instead of pointing at the path where we access the value within a closure,
631+
// we point at the type on the parameter from the definition of the outer
632+
// function:
633+
//
634+
// error[E0507]: cannot move out of `foo`, a captured
635+
// variable in an `Fn` closure
636+
// --> file.rs:14:25
637+
// |
638+
// 13 | fn do_stuff(foo: Option<Foo>) {
639+
// | --- ----------- move occurs because `foo` has type
640+
// | | `Option<Foo>`, which does not implement
641+
// | | the `Copy` trait
642+
// | captured outer variable
643+
// 14 | require_fn_trait(|| async {
644+
// | -- ^^^^^ `foo` is moved here
645+
// | |
646+
// | captured by this `Fn` closure
647+
// 15 | if foo.map_or(false, |f| f.foo()) {
648+
// | --- variable moved due to use in coroutine
649+
use_span = param.ty_span;
650+
}
651+
625652
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
626653
is_partial_move: false,
627654
ty: place_ty,

tests/ui/issues/issue-4335.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu
22
--> $DIR/issue-4335.rs:6:20
33
|
44
LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
5-
| - captured outer variable
5+
| - ----- move occurs because `*v` has type `T`, which does not implement the `Copy` trait
6+
| |
7+
| captured outer variable
68
LL | id(Box::new(|| *v))
7-
| -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
9+
| -- ^^
810
| |
911
| captured by this `FnMut` closure
1012
|

0 commit comments

Comments
 (0)