Auto merge of #122603 - estebank:clone-o-rama, r=lcnr

Detect borrow checker errors where `.clone()` would be an appropriate user action

When a value is moved twice, suggest cloning the earlier move:

```
error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
  --> $DIR/union-move.rs:49:18
   |
LL |         move_out(x.f1_nocopy);
   |                  ^^^^^^^^^^^
   |                  |
   |                  cannot move out of here
   |                  move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
   |
help: consider cloning the value if the performance cost is acceptable
   |
LL |         move_out(x.f1_nocopy.clone());
   |                             ++++++++
```

When a value is borrowed by an `fn` call, consider if cloning the result of the call would be reasonable, and suggest cloning that, instead of the argument:

```
error[E0505]: cannot move out of `a` because it is borrowed
  --> $DIR/variance-issue-20533.rs:53:14
   |
LL |         let a = AffineU32(1);
   |             - binding `a` declared here
LL |         let x = bat(&a);
   |                     -- borrow of `a` occurs here
LL |         drop(a);
   |              ^ move out of `a` occurs here
LL |         drop(x);
   |              - borrow later used here
   |
help: consider cloning the value if the performance cost is acceptable
   |
LL |         let x = bat(&a).clone();
   |                        ++++++++
```

otherwise, suggest cloning the argument:

```
error[E0505]: cannot move out of `a` because it is borrowed
  --> $DIR/variance-issue-20533.rs:59:14
   |
LL |         let a = ClonableAffineU32(1);
   |             - binding `a` declared here
LL |         let x = foo(&a);
   |                     -- borrow of `a` occurs here
LL |         drop(a);
   |              ^ move out of `a` occurs here
LL |         drop(x);
   |              - borrow later used here
   |
help: consider cloning the value if the performance cost is acceptable
   |
LL -         let x = foo(&a);
LL +         let x = foo(a.clone());
   |
```

This suggestion doesn't attempt to square out the types between what's cloned and what the `fn` expects, to allow the user to make a determination on whether to change the `fn` call or `fn` definition themselves.

Special case move errors caused by `FnOnce`:

```
error[E0382]: use of moved value: `blk`
  --> $DIR/once-cant-call-twice-on-heap.rs:8:5
   |
LL | fn foo<F:FnOnce()>(blk: F) {
   |                    --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
LL |     blk();
   |     ----- `blk` moved due to this call
LL |     blk();
   |     ^^^ value used here after move
   |
note: `FnOnce` closures can only be called once
  --> $DIR/once-cant-call-twice-on-heap.rs:6:10
   |
LL | fn foo<F:FnOnce()>(blk: F) {
   |          ^^^^^^^^ `F` is made to be an `FnOnce` closure here
LL |     blk();
   |     ----- this value implements `FnOnce`, which causes it to be moved when called
```

Account for redundant `.clone()` calls in resulting suggestions:

```
error[E0507]: cannot move out of dereference of `S`
  --> $DIR/needs-clone-through-deref.rs:15:18
   |
LL |         for _ in self.clone().into_iter() {}
   |                  ^^^^^^^^^^^^ ----------- value moved due to this method call
   |                  |
   |                  move occurs because value has type `Vec<usize>`, which does not implement the `Copy` trait
   |
note: `into_iter` takes ownership of the receiver `self`, which moves value
  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: you can `clone` the value and consume it, but this might not be your desired behavior
   |
LL |         for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {}
   |                  ++++++++++++++++++++++++++++++    ~
```

We use the presence of `&mut` values in a move error as a proxy for the user caring about side effects, so we don't emit a clone suggestion in that case:

```
error[E0505]: cannot move out of `s` because it is borrowed
  --> $DIR/borrowck-overloaded-index-move-index.rs:53:7
   |
LL |     let mut s = "hello".to_string();
   |         ----- binding `s` declared here
LL |     let rs = &mut s;
   |              ------ borrow of `s` occurs here
...
LL |     f[s] = 10;
   |       ^ move out of `s` occurs here
...
LL |     use_mut(rs);
   |             -- borrow later used here
```

We properly account for `foo += foo;` errors where we *don't* suggest `foo.clone() += foo;`, instead suggesting `foo += foo.clone();`.

---

Each commit can be reviewed in isolation. There are some "cleanup" commits, but kept them separate in order to show *why* specific changes were being made, and their effect on tests' output.

Fix #49693, CC #64167.
This commit is contained in:
bors 2024-04-13 09:07:26 +00:00
commit 6eaa7fb576
124 changed files with 1743 additions and 144 deletions

View File

@ -87,6 +87,12 @@ borrowck_move_unsized =
borrowck_moved_a_fn_once_in_call =
this value implements `FnOnce`, which causes it to be moved when called
borrowck_moved_a_fn_once_in_call_call =
`FnOnce` closures can only be called once
borrowck_moved_a_fn_once_in_call_def =
`{$ty}` is made to be an `FnOnce` closure here
borrowck_moved_due_to_await =
{$place_name} {$is_partial ->
[true] partially moved

View File

@ -203,13 +203,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if !seen_spans.contains(&move_span) {
if !closure {
self.suggest_ref_or_clone(
mpi,
move_span,
&mut err,
&mut in_pattern,
move_spans,
);
self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans);
}
let msg_opt = CapturedMessageOpt {
@ -283,7 +277,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(name) => format!("`{name}`"),
None => "value".to_owned(),
};
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg)
|| if let UseSpans::FnSelfUse { kind, .. } = use_spans
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
&& let ty::Param(_) = self_ty.kind()
&& ty == self_ty
&& Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait()
{
// this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
true
} else {
false
}
{
// Suppress the next suggestion since we don't want to put more bounds onto
// something that already has `Fn`-like bounds (or is a closure), so we can't
// restrict anyways.
@ -339,18 +345,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn suggest_ref_or_clone(
&self,
mpi: MovePathIndex,
move_span: Span,
err: &mut Diag<'tcx>,
in_pattern: &mut bool,
move_spans: UseSpans<'_>,
) {
let move_span = match move_spans {
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
_ => move_spans.args_or_use(),
};
struct ExpressionFinder<'hir> {
expr_span: Span,
expr: Option<&'hir hir::Expr<'hir>>,
pat: Option<&'hir hir::Pat<'hir>>,
parent_pat: Option<&'hir hir::Pat<'hir>>,
hir: rustc_middle::hir::map::Map<'hir>,
}
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
type NestedFilter = OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.hir
}
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span == self.expr_span {
self.expr = Some(e);
@ -385,8 +401,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let expr = hir.body(body_id).value;
let place = &self.move_data.move_paths[mpi].place;
let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);
let mut finder =
ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
let mut finder = ExpressionFinder {
expr_span: move_span,
expr: None,
pat: None,
parent_pat: None,
hir,
};
finder.visit_expr(expr);
if let Some(span) = span
&& let Some(expr) = finder.expr
@ -467,16 +488,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else if let UseSpans::ClosureUse {
closure_kind:
ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
args_span: _,
capture_kind_span: _,
path_span,
..
} = move_spans
{
self.suggest_cloning(err, ty, expr, path_span);
self.suggest_cloning(err, ty, expr, None);
} else if self.suggest_hoisting_call_outside_loop(err, expr) {
// The place where the the type moves would be misleading to suggest clone.
// #121466
self.suggest_cloning(err, ty, expr, move_span);
self.suggest_cloning(err, ty, expr, None);
}
}
if let Some(pat) = finder.pat {
@ -1031,8 +1050,272 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
can_suggest_clone
}
fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
/// We have `S { foo: val, ..base }`, and we suggest instead writing
/// `S { foo: val, bar: base.bar.clone(), .. }` when valid.
fn suggest_cloning_on_functional_record_update(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
expr: &'cx hir::Expr<'cx>,
) {
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return };
let hir::QPath::Resolved(_, path) = struct_qpath else { return };
let hir::def::Res::Def(_, def_id) = path.res else { return };
let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return };
let ty::Adt(def, args) = expr_ty.kind() else { return };
let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = base.kind else { return };
let (hir::def::Res::Local(_)
| hir::def::Res::Def(
DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } | DefKind::AssocConst,
_,
)) = path.res
else {
return;
};
let Ok(base_str) = self.infcx.tcx.sess.source_map().span_to_snippet(base.span) else {
return;
};
// 1. look for the fields of type `ty`.
// 2. check if they are clone and add them to suggestion
// 3. check if there are any values left to `..` and remove it if not
// 4. emit suggestion to clone the field directly as `bar: base.bar.clone()`
let mut final_field_count = fields.len();
let Some(variant) = def.variants().iter().find(|variant| variant.def_id == def_id) else {
// When we have an enum, look for the variant that corresponds to the variant the user
// wrote.
return;
};
let mut sugg = vec![];
for field in &variant.fields {
// In practice unless there are more than one field with the same type, we'll be
// suggesting a single field at a type, because we don't aggregate multiple borrow
// checker errors involving the functional record update sytnax into a single one.
let field_ty = field.ty(self.infcx.tcx, args);
let ident = field.ident(self.infcx.tcx);
if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) {
// Suggest adding field and cloning it.
sugg.push(format!("{ident}: {base_str}.{ident}.clone()"));
final_field_count += 1;
}
}
let (span, sugg) = match fields {
[.., last] => (
if final_field_count == variant.fields.len() {
// We'll remove the `..base` as there aren't any fields left.
last.span.shrink_to_hi().with_hi(base.span.hi())
} else {
last.span.shrink_to_hi()
},
format!(", {}", sugg.join(", ")),
),
// Account for no fields in suggestion span.
[] => (
expr.span.with_lo(struct_qpath.span().hi()),
if final_field_count == variant.fields.len() {
// We'll remove the `..base` as there aren't any fields left.
format!(" {{ {} }}", sugg.join(", "))
} else {
format!(" {{ {}, ..{base_str} }}", sugg.join(", "))
},
),
};
let prefix = if !self.implements_clone(ty) {
let msg = format!("`{ty}` doesn't implement `Copy` or `Clone`");
if let ty::Adt(def, _) = ty.kind() {
err.span_note(self.infcx.tcx.def_span(def.did()), msg);
} else {
err.note(msg);
}
format!("if `{ty}` implemented `Clone`, you could ")
} else {
String::new()
};
let msg = format!(
"{prefix}clone the value from the field instead of using the functional record update \
syntax",
);
err.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable);
}
pub(crate) fn suggest_cloning(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
mut expr: &'cx hir::Expr<'cx>,
mut other_expr: Option<&'cx hir::Expr<'cx>>,
) {
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
// We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
// `Location` that covers both the `S { ... }` literal, all of its fields and the
// `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr`
// will already be correct. Instead, we see if we can suggest writing.
self.suggest_cloning_on_functional_record_update(err, ty, expr);
return;
}
if let Some(some_other_expr) = other_expr
&& let Some(parent_binop) =
self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
if let (hir_id, hir::Node::Expr(e)) = n
&& let hir::ExprKind::AssignOp(_binop, target, _arg) = e.kind
&& target.hir_id == expr.hir_id
{
Some(hir_id)
} else {
None
}
})
&& let Some(other_parent_binop) =
self.infcx.tcx.hir().parent_iter(some_other_expr.hir_id).find_map(|n| {
if let (hir_id, hir::Node::Expr(expr)) = n
&& let hir::ExprKind::AssignOp(..) = expr.kind
{
Some(hir_id)
} else {
None
}
})
&& parent_binop == other_parent_binop
{
// Explicitly look for `expr += other_expr;` and avoid suggesting
// `expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`.
other_expr = Some(expr);
expr = some_other_expr;
}
'outer: {
if let ty::Ref(..) = ty.kind() {
// We check for either `let binding = foo(expr, other_expr);` or
// `foo(expr, other_expr);` and if so we don't suggest an incorrect
// `foo(expr, other_expr).clone()`
if let Some(other_expr) = other_expr
&& let Some(parent_let) =
self.infcx.tcx.hir().parent_iter(expr.hir_id).find_map(|n| {
if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
Some(hir_id)
} else {
None
}
})
&& let Some(other_parent_let) =
self.infcx.tcx.hir().parent_iter(other_expr.hir_id).find_map(|n| {
if let (hir_id, hir::Node::LetStmt(_) | hir::Node::Stmt(_)) = n {
Some(hir_id)
} else {
None
}
})
&& parent_let == other_parent_let
{
// Explicitly check that we don't have `foo(&*expr, other_expr)`, as cloning the
// result of `foo(...)` won't help.
break 'outer;
}
// We're suggesting `.clone()` on an borrowed value. See if the expression we have
// is an argument to a function or method call, and try to suggest cloning the
// *result* of the call, instead of the argument. This is closest to what people
// would actually be looking for in most cases, with maybe the exception of things
// like `fn(T) -> T`, but even then it is reasonable.
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
let mut prev = expr;
while let hir::Node::Expr(parent) = self.infcx.tcx.parent_hir_node(prev.hir_id) {
if let hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) = parent.kind
&& let Some(call_ty) = typeck_results.node_type_opt(parent.hir_id)
&& let call_ty = call_ty.peel_refs()
&& (!call_ty
.walk()
.any(|t| matches!(t.unpack(), ty::GenericArgKind::Lifetime(_)))
|| if let ty::Alias(ty::Projection, _) = call_ty.kind() {
// FIXME: this isn't quite right with lifetimes on assoc types,
// but ignore for now. We will only suggest cloning if
// `<Ty as Trait>::Assoc: Clone`, which should keep false positives
// down to a managable ammount.
true
} else {
false
})
&& self.implements_clone(call_ty)
&& self.suggest_cloning_inner(err, call_ty, parent)
{
return;
}
prev = parent;
}
}
}
let ty = ty.peel_refs();
if self.implements_clone(ty) {
self.suggest_cloning_inner(err, ty, expr);
} else if let ty::Adt(def, args) = ty.kind()
&& def.did().as_local().is_some()
&& def.variants().iter().all(|variant| {
variant
.fields
.iter()
.all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
})
{
err.span_note(
self.infcx.tcx.def_span(def.did()),
format!("if `{ty}` implemented `Clone`, you could clone the value"),
);
}
}
fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
self.infcx
.type_implements_trait(clone_trait_def, [ty], self.param_env)
.must_apply_modulo_regions()
}
/// Given an expression, check if it is a method call `foo.clone()`, where `foo` and
/// `foo.clone()` both have the same type, returning the span for `.clone()` if so.
pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind
&& let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id)
&& let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
&& rcvr_ty == expr_ty
&& segment.ident.name == sym::clone
&& args.is_empty()
{
Some(span)
} else {
None
}
}
fn in_move_closure(&self, expr: &hir::Expr<'_>) -> bool {
for (_, node) in self.infcx.tcx.hir().parent_iter(expr.hir_id) {
if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = node
&& let hir::CaptureBy::Value { .. } = closure.capture_clause
{
// `move || x.clone()` will not work. FIXME: suggest `let y = x.clone(); move || y`
return true;
}
}
false
}
fn suggest_cloning_inner(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
) -> bool {
let tcx = self.infcx.tcx;
if let Some(_) = self.clone_on_reference(expr) {
// Avoid redundant clone suggestion already suggested in `explain_captures`.
// See `tests/ui/moves/needs-clone-through-deref.rs`
return false;
}
if self.in_move_closure(expr) {
return false;
}
// Try to find predicates on *generic params* that would allow copying `ty`
let suggestion =
if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
@ -1040,27 +1323,39 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else {
".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)
.must_apply_modulo_regions()
let mut sugg = Vec::with_capacity(2);
let mut inner_expr = expr;
// Remove uses of `&` and `*` when suggesting `.clone()`.
while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =
&inner_expr.kind
{
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()))
{
"clone the value to increment its reference count"
} else {
"consider cloning the value if the performance cost is acceptable"
};
err.span_suggestion_verbose(
span.shrink_to_hi(),
msg,
suggestion,
Applicability::MachineApplicable,
);
if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind {
// We assume that `&mut` refs are desired for their side-effects, so cloning the
// value wouldn't do what the user wanted.
return false;
}
inner_expr = inner;
}
if inner_expr.span.lo() != expr.span.lo() {
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
}
let span = if inner_expr.span.hi() != expr.span.hi() {
// Account for `(*x)` to suggest `x.clone()`.
expr.span.with_lo(inner_expr.span.hi())
} else {
expr.span.shrink_to_hi()
};
sugg.push((span, suggestion));
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()))
{
"clone the value to increment its reference count"
} else {
"consider cloning the value if the performance cost is acceptable"
};
err.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable);
true
}
fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
@ -1165,6 +1460,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(expr) = self.find_expr(borrow_span)
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
{
self.suggest_cloning(&mut err, ty, expr, self.find_expr(span));
}
self.buffer_error(err);
}
@ -1586,22 +1887,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
for ty in types_to_constrain {
self.suggest_adding_bounds(err, ty, clone, body.span);
if let ty::Adt(..) = ty.kind() {
// The type doesn't implement Clone.
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
let obligation = Obligation::new(
self.infcx.tcx,
ObligationCause::dummy(),
self.param_env,
trait_ref,
);
self.infcx.err_ctxt().suggest_derive(
&obligation,
err,
trait_ref.to_predicate(self.infcx.tcx),
);
}
self.suggest_adding_bounds_or_derive(err, ty, clone, body.span);
}
}
pub(crate) fn suggest_adding_bounds_or_derive(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
trait_def_id: DefId,
span: Span,
) {
self.suggest_adding_bounds(err, ty, trait_def_id, span);
if let ty::Adt(..) = ty.kind() {
// The type doesn't implement the trait.
let trait_ref =
ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, trait_def_id, [ty]));
let obligation = Obligation::new(
self.infcx.tcx,
ObligationCause::dummy(),
self.param_env,
trait_ref,
);
self.infcx.err_ctxt().suggest_derive(
&obligation,
err,
trait_ref.to_predicate(self.infcx.tcx),
);
}
}
@ -1702,6 +2014,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> {
let tcx = self.infcx.tcx;
let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
let mut expr_finder = FindExprBySpan::new(span);
expr_finder.visit_expr(tcx.hir().body(body_id).value);
expr_finder.result
}
fn suggest_slice_method_if_applicable(
&self,
err: &mut Diag<'_>,

View File

@ -5,6 +5,7 @@ use crate::session_diagnostics::{
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
};
use rustc_errors::{Applicability, Diag};
use rustc_errors::{DiagCtxt, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::CoroutineKind;
@ -29,6 +30,8 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
use crate::fluent_generated as fluent;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
@ -587,7 +590,7 @@ impl UseSpans<'_> {
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn args_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
dcx: &DiagCtxt,
err: &mut Diag<'_>,
f: impl FnOnce(Span) -> CaptureArgLabel,
) {
@ -601,7 +604,7 @@ impl UseSpans<'_> {
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_path_only_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
dcx: &DiagCtxt,
err: &mut Diag<'_>,
action: crate::InitializationRequiringAction,
) {
@ -639,7 +642,7 @@ impl UseSpans<'_> {
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
dcx: &DiagCtxt,
err: &mut Diag<'_>,
kind: Option<rustc_middle::mir::BorrowKind>,
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
@ -1034,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.map(|n| format!("`{n}`"))
.unwrap_or_else(|| "value".to_owned());
match kind {
CallKind::FnCall { fn_trait_id, .. }
CallKind::FnCall { fn_trait_id, self_ty }
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
{
err.subdiagnostic(
@ -1046,7 +1049,79 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
is_loop_message,
},
);
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
// Check if the move occurs on a value because of a call on a closure that comes
// from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:
// ```
// error[E0382]: use of moved value: `blk`
// --> $DIR/once-cant-call-twice-on-heap.rs:8:5
// |
// LL | fn foo<F:FnOnce()>(blk: F) {
// | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
// LL | blk();
// | ----- `blk` moved due to this call
// LL | blk();
// | ^^^ value used here after move
// |
// note: `FnOnce` closures can only be called once
// --> $DIR/once-cant-call-twice-on-heap.rs:6:10
// |
// LL | fn foo<F:FnOnce()>(blk: F) {
// | ^^^^^^^^ `F` is made to be an `FnOnce` closure here
// LL | blk();
// | ----- this value implements `FnOnce`, which causes it to be moved when called
// ```
if let ty::Param(param_ty) = self_ty.kind()
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
&& let param = generics.type_param(param_ty, self.infcx.tcx)
&& let Some(hir_generics) = self
.infcx
.tcx
.typeck_root_def_id(self.mir_def_id().to_def_id())
.as_local()
.and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
&& let spans = hir_generics
.predicates
.iter()
.filter_map(|pred| match pred {
hir::WherePredicate::BoundPredicate(pred) => Some(pred),
_ => None,
})
.filter(|pred| {
if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
id == param.def_id
} else {
false
}
})
.flat_map(|pred| pred.bounds)
.filter_map(|bound| {
if let Some(trait_ref) = bound.trait_ref()
&& let Some(trait_def_id) = trait_ref.trait_def_id()
&& trait_def_id == fn_trait_id
{
Some(bound.span())
} else {
None
}
})
.collect::<Vec<Span>>()
&& !spans.is_empty()
{
let mut span: MultiSpan = spans.clone().into();
for sp in spans {
span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
}
span.push_span_label(
fn_call_span,
fluent::borrowck_moved_a_fn_once_in_call,
);
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
} else {
err.subdiagnostic(
self.dcx(),
CaptureReasonNote::FnOnceMoveInCall { var_span },
);
}
}
CallKind::Operator { self_arg, trait_id, .. } => {
let self_arg = self_arg.unwrap();
@ -1212,13 +1287,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.iter_projections()
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
{
let (start, end) = if let Some(expr) = self.find_expr(move_span)
&& let Some(_) = self.clone_on_reference(expr)
&& let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
{
(move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))
} else {
(move_span.shrink_to_lo(), move_span.shrink_to_hi())
};
vec![
// We use the fully-qualified path because `.clone()` can
// sometimes choose `<&T as Clone>` instead of `<T as Clone>`
// when going through auto-deref, so this ensures that doesn't
// happen, causing suggestions for `.clone().clone()`.
(move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
(move_span.shrink_to_hi(), ")".to_string()),
(start, format!("<{ty} as Clone>::clone(&")),
(end, ")".to_string()),
]
} else {
vec![(move_span.shrink_to_hi(), ".clone()".to_string())]

View File

@ -435,7 +435,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
GroupedMoveError::MovesFromPlace {
mut binds_to, move_from, span: other_span, ..
} => {
self.add_borrow_suggestions(err, span);
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
@ -444,6 +446,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
None => "value".to_string(),
};
if let Some(expr) = self.find_expr(span) {
self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span));
}
err.subdiagnostic(
self.dcx(),
crate::session_diagnostics::TypeNoCopy::Label {
@ -468,19 +474,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
// No binding. Nothing to suggest.
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
let span = use_spans.var_or_use();
let use_span = use_spans.var_or_use();
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(original_path.as_ref()) {
Some(desc) => format!("`{desc}`"),
None => "value".to_string(),
};
if let Some(expr) = self.find_expr(use_span) {
self.suggest_cloning(err, place_ty, expr, self.find_expr(span));
}
err.subdiagnostic(
self.dcx(),
crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: place_ty,
place: &place_desc,
span,
span: use_span,
},
);
@ -582,6 +593,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if binds_to.len() == 1 {
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
if let Some(expr) = self.find_expr(binding_span) {
self.suggest_cloning(err, bind_to.ty, expr, None);
}
err.subdiagnostic(
self.dcx(),
crate::session_diagnostics::TypeNoCopy::Label {

View File

@ -3,10 +3,10 @@
// fn body, causing this (invalid) code to be accepted.
pub trait Foo<'a> {
type Bar;
type Bar: Clone;
}
impl<'a, T:'a> Foo<'a> for T {
impl<'a, T: 'a> Foo<'a> for T {
type Bar = &'a T;
}

View File

@ -10,6 +10,11 @@ LL | drop(x);
| ^ move out of `x` occurs here
LL | return f(y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | 's: loop { y = denormalise(&x).clone(); break }
| ++++++++
error: aborting due to 1 previous error

View File

@ -7,6 +7,12 @@ LL | drop(t);
| - value moved here
LL | drop(t);
| ^ value used here after move
|
note: if `S<()>` implemented `Clone`, you could clone the value
--> $DIR/issue-25700.rs:1:1
|
LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>);
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -1,5 +1,6 @@
use std::ops::AddAssign;
#[derive(Clone)]
struct Int(i32);
impl AddAssign for Int {
@ -16,6 +17,7 @@ fn main() {
x;
//~^ ERROR cannot move out of `x` because it is borrowed
//~| move out of `x` occurs here
//~| HELP consider cloning
let y = Int(2);
//~^ HELP consider changing this to be mutable

View File

@ -1,5 +1,5 @@
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/augmented-assignments.rs:16:5
--> $DIR/augmented-assignments.rs:17:5
|
LL | let mut x = Int(1);
| ----- binding `x` declared here
@ -8,9 +8,14 @@ LL | x
...
LL | x;
| ^ move out of `x` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | x.clone();
| ++++++++
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/augmented-assignments.rs:23:5
--> $DIR/augmented-assignments.rs:25:5
|
LL | y
| ^ cannot borrow as mutable

View File

@ -10,6 +10,12 @@ LL | let y = x;
LL |
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let r = &x.0;
LL + let r = x.0.clone();
|
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:18:13
@ -42,6 +48,12 @@ LL | let y = x;
| ^ move out of `x` occurs here
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let r = &x.0;
LL + let r = x.0.clone();
|
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:33:13

View File

@ -10,6 +10,12 @@ LL | &*a,
| --- borrow of `*a` occurs here
LL | a);
| ^ move out of `a` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - &*a,
LL + a.clone(),
|
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@ -22,6 +28,12 @@ LL | &*a,
| --- borrow of `*a` occurs here
LL | a);
| ^ move out of `a` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - &*a,
LL + a.clone(),
|
error: aborting due to 2 previous errors

View File

@ -38,6 +38,11 @@ LL | let [y, z @ ..] = x;
LL | };
LL | &x;
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let [y, z @ ..] = x.clone();
| ++++++++
error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-closures-slice-patterns.rs:33:13
@ -79,6 +84,12 @@ LL | let [y, z @ ..] = *x;
LL | };
LL | &x;
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let [y, z @ ..] = *x;
LL + let [y, z @ ..] = x.clone();
|
error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-closures-slice-patterns.rs:59:13

View File

@ -49,6 +49,12 @@ LL | drop(x.b);
| ^^^ move out of `x.b` occurs here
LL | drop(**p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p = &x.b;
LL + let p = x.b.clone();
|
error[E0505]: cannot move out of `x.b` because it is borrowed
--> $DIR/borrowck-field-sensitivity.rs:41:14
@ -61,6 +67,12 @@ LL | let _y = A { a: 3, .. x };
| ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
LL | drop(**p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p = &x.b;
LL + let p = x.b.clone();
|
error[E0499]: cannot borrow `x.a` as mutable more than once at a time
--> $DIR/borrowck-field-sensitivity.rs:48:13

View File

@ -9,4 +9,5 @@ const MOVE: fn(&String) -> String = {
};
fn main() {
println!("{}", MOVE(&String::new()));
}

View File

@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*x` which is behind a shared reference
|
LL | return *x
| ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - return *x
LL + return x.clone()
|
error: aborting due to 1 previous error

View File

@ -1,6 +1,6 @@
// check that borrowck looks inside consts/statics
static FN : &'static (dyn Fn() -> (Box<dyn Fn()->Box<i32>>) + Sync) = &|| {
static FN : &'static (dyn Fn() -> Box<dyn Fn()->Box<i32>> + Sync) = &|| {
let x = Box::new(0);
Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure
};

View File

@ -7,6 +7,11 @@ LL | Box::new(|| x)
| -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
| |
| captured by this `Fn` closure
|
help: consider cloning the value if the performance cost is acceptable
|
LL | Box::new(|| x.clone())
| ++++++++
error: aborting due to 1 previous error

View File

@ -5,7 +5,7 @@ fn main() {
match x {
Some(ref y) => {
let _b = y; //~ ERROR cannot move out
let _b = y.clone(); //~ ERROR cannot move out
}
_ => {}
}

View File

@ -9,6 +9,11 @@ help: consider removing the dereference here
LL - let _b = *y;
LL + let _b = y;
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let _b = *y;
LL + let _b = y.clone();
|
error: aborting due to 1 previous error

View File

@ -17,6 +17,11 @@ LL | {src};
| --- value moved here
LL | src.0 = 66;
| ^^^^^^^^^^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | {src.clone()};
| ++++++++
error: aborting due to 2 previous errors

View File

@ -13,6 +13,12 @@ LL | println!("v={}", *v);
LL | });
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let w = &v;
LL + let w = v.clone();
|
error[E0505]: cannot move out of `v` because it is borrowed
--> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@ -29,6 +35,12 @@ LL | println!("v={}", *v);
LL | });
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let w = &v;
LL + let w = v.clone();
|
error: aborting due to 2 previous errors

View File

@ -9,6 +9,12 @@ LL | take(v);
| ^ move out of `v` occurs here
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let w = &v;
LL + let w = v.clone();
|
error: aborting due to 1 previous error

View File

@ -10,6 +10,12 @@ LL | let z = *a;
| ^^ move out of `*a` occurs here
LL | b.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let b = &a;
LL + let b = a.clone();
|
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ help: consider removing the dereference here
LL - let y = *x;
LL + let y = x;
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = *x;
LL + let y = x.clone();
|
error: aborting due to 1 previous error

View File

@ -10,6 +10,12 @@ LL | let t1 = t0;
LL | *t1 = 22;
LL | p.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p: &isize = &*t0; // Freezes `*t0`
LL + let p: &isize = t0.clone(); // Freezes `*t0`
|
error: aborting due to 1 previous error

View File

@ -2,6 +2,6 @@
use std::rc::Rc;
pub fn main() {
let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2]).clone()).into_iter();
//~^ ERROR [E0507]
}

View File

@ -12,6 +12,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
|
LL | let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
| ++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | let _x = Rc::new(vec![1, 2]).clone().into_iter();
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ help: consider removing the dereference here
LL - let _x = *Rc::new("hi".to_string());
LL + let _x = Rc::new("hi".to_string());
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let _x = *Rc::new("hi".to_string());
LL + let _x = Rc::new("hi".to_string()).clone();
|
error: aborting due to 1 previous error

View File

@ -8,7 +8,8 @@ static BAR: Foo = Foo { foo: 5 };
fn test(f: Foo) {
let _f = Foo{foo: 4, ..f};
let f = Foo { foo: 4, ..f };
println!("{}", f.foo);
}
fn main() {

View File

@ -1,8 +1,14 @@
error[E0507]: cannot move out of static item `BAR`
--> $DIR/borrowck-move-out-of-static-item.rs:15:10
--> $DIR/borrowck-move-out-of-static-item.rs:16:10
|
LL | test(BAR);
| ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/borrowck-move-out-of-static-item.rs:3:1
|
LL | struct Foo {
| ^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -9,6 +9,12 @@ LL | let S { x: ax } = a;
| ^^ move out of `a.x` occurs here
LL | f(pb);
| -- borrow later used here
|
note: if `S` implemented `Clone`, you could clone the value
--> $DIR/borrowck-move-subcomponent.rs:6:1
|
LL | struct S {
| ^^^^^^^^
error: aborting due to 1 previous error

View File

@ -14,6 +14,12 @@ LL | drop(x1);
...
LL | borrow(&*p1);
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p1 = &x1;
LL + let p1 = x1.clone();
|
error[E0505]: cannot move out of `x2` because it is borrowed
--> $DIR/borrowck-multiple-captures.rs:12:19
@ -30,6 +36,12 @@ LL | drop(x2);
...
LL | borrow(&*p2);
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p2 = &x2;
LL + let p2 = x2.clone();
|
error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:27:19
@ -93,6 +105,12 @@ LL | drop(x);
...
LL | borrow(&*p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let p = &x;
LL + let p = x.clone();
|
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:52:14

View File

@ -29,6 +29,12 @@ LL | s(" world".to_string());
| - value moved here
LL | s(" world".to_string());
| ^ value used here after move
|
note: if `SFnOnce` implemented `Clone`, you could clone the value
--> $DIR/borrowck-overloaded-call.rs:41:1
|
LL | struct SFnOnce {
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -8,6 +8,10 @@ help: consider borrowing here
|
LL | let bad = &v[0];
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let bad = v[0].clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -2,20 +2,63 @@
// move, when the struct implements Drop.
struct B;
struct S { a: isize, b: B }
impl Drop for S { fn drop(&mut self) { } }
struct S<K> { a: isize, b: B, c: K }
impl<K> Drop for S<K> { fn drop(&mut self) { } }
struct T { a: isize, mv: Box<isize> }
struct T { a: isize, b: Box<isize> }
impl Drop for T { fn drop(&mut self) { } }
fn f(s0:S) {
let _s2 = S{a: 2, ..s0};
//~^ ERROR [E0509]
}
struct V<K> { a: isize, b: Box<isize>, c: K }
impl<K> Drop for V<K> { fn drop(&mut self) { } }
fn g(s0:T) {
let _s2 = T{a: 2, ..s0};
//~^ ERROR [E0509]
#[derive(Clone)]
struct Clonable;
mod not_all_clone {
use super::*;
fn a(s0: S<()>) {
let _s2 = S { a: 2, ..s0 };
//~^ ERROR [E0509]
}
fn b(s0: S<B>) {
let _s2 = S { a: 2, ..s0 };
//~^ ERROR [E0509]
//~| ERROR [E0509]
}
fn c<K: Clone>(s0: S<K>) {
let _s2 = S { a: 2, ..s0 };
//~^ ERROR [E0509]
//~| ERROR [E0509]
}
}
mod all_clone {
use super::*;
fn a(s0: T) {
let _s2 = T { a: 2, ..s0 };
//~^ ERROR [E0509]
}
fn b(s0: T) {
let _s2 = T { ..s0 };
//~^ ERROR [E0509]
}
fn c(s0: T) {
let _s2 = T { a: 2, b: s0.b };
//~^ ERROR [E0509]
}
fn d<K: Clone>(s0: V<K>) {
let _s2 = V { a: 2, ..s0 };
//~^ ERROR [E0509]
//~| ERROR [E0509]
}
fn e(s0: V<Clonable>) {
let _s2 = V { a: 2, ..s0 };
//~^ ERROR [E0509]
//~| ERROR [E0509]
}
}
fn main() { }

View File

@ -1,21 +1,191 @@
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:12:15
error[E0509]: cannot move out of type `S<()>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:20:19
|
LL | let _s2 = S{a: 2, ..s0};
| ^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
|
note: `B` doesn't implement `Copy` or `Clone`
--> $DIR/borrowck-struct-update-with-dtor.rs:4:1
|
LL | struct B;
| ^^^^^^^^
help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:24:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
|
note: `B` doesn't implement `Copy` or `Clone`
--> $DIR/borrowck-struct-update-with-dtor.rs:4:1
|
LL | struct B;
| ^^^^^^^^
help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() };
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0509]: cannot move out of type `S<B>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:24:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.c` has type `B`, which does not implement the `Copy` trait
|
note: `B` doesn't implement `Copy` or `Clone`
--> $DIR/borrowck-struct-update-with-dtor.rs:4:1
|
LL | struct B;
| ^^^^^^^^
help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = S { a: 2, b: s0.b.clone(), c: s0.c.clone() };
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:29:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
|
note: `B` doesn't implement `Copy` or `Clone`
--> $DIR/borrowck-struct-update-with-dtor.rs:4:1
|
LL | struct B;
| ^^^^^^^^
help: if `B` implemented `Clone`, you could clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:29:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = S { a: 2, c: s0.c.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:17:15
--> $DIR/borrowck-struct-update-with-dtor.rs:37:19
|
LL | let _s2 = T{a: 2, ..s0};
| ^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.mv` has type `Box<isize>`, which does not implement the `Copy` trait
LL | let _s2 = T { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = T { a: 2, b: s0.b.clone() };
| ~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:42:19
|
LL | let _s2 = T { ..s0 };
| ^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = T { b: s0.b.clone(), ..s0 };
| ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0509]: cannot move out of type `T`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:47:32
|
LL | let _s2 = T { a: 2, b: s0.b };
| ^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let _s2 = T { a: 2, b: s0.b.clone() };
| ++++++++
error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:52:19
|
LL | let _s2 = V { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = V { a: 2, b: s0.b.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `V<K>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:52:19
|
LL | let _s2 = V { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = V { a: 2, c: s0.c.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:58:19
|
LL | let _s2 = V { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = V { a: 2, b: s0.b.clone(), ..s0 };
| +++++++++++++++++
error[E0509]: cannot move out of type `V<Clonable>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:58:19
|
LL | let _s2 = V { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.c` has type `Clonable`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _s2 = V { a: 2, c: s0.c.clone(), ..s0 };
| +++++++++++++++++
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0509`.

View File

@ -9,6 +9,12 @@ LL | free(x);
| ^ move out of `x` occurs here
LL | *y
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = &*x;
LL + let y = x.clone();
|
error: aborting due to 1 previous error

View File

@ -29,15 +29,13 @@ LL | f(1, 2);
LL | f(1, 2);
| ^ value used here after move
|
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/borrowck-unboxed-closures.rs:11:5
note: `FnOnce` closures can only be called once
--> $DIR/borrowck-unboxed-closures.rs:10:8
|
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `F` is made to be an `FnOnce` closure here
LL | f(1, 2);
| ^
help: consider further restricting this bound
|
LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
| ++++++
| ------- this value implements `FnOnce`, which causes it to be moved when called
error: aborting due to 3 previous errors

View File

@ -47,6 +47,7 @@ fn c() {
//~| NOTE cannot move out of here
//~| NOTE move occurs because
//~| HELP consider borrowing here
//~| HELP consider cloning
}
fn d() {
@ -66,6 +67,7 @@ fn d() {
//~| NOTE cannot move out of here
//~| NOTE move occurs because
//~| HELP consider borrowing here
//~| HELP consider cloning
}
fn e() {
@ -86,6 +88,7 @@ fn e() {
//~| NOTE cannot move out of here
//~| NOTE move occurs because
//~| HELP consider borrowing here
//~| HELP consider cloning
}
fn main() {}

View File

@ -53,9 +53,13 @@ help: consider borrowing here
|
LL | let a = &vec[0];
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let a = vec[0].clone();
| ++++++++
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:55:11
--> $DIR/borrowck-vec-pattern-nesting.rs:56:11
|
LL | match vec {
| ^^^ cannot move out of here
@ -73,7 +77,7 @@ LL + [
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:65:13
--> $DIR/borrowck-vec-pattern-nesting.rs:66:13
|
LL | let a = vec[0];
| ^^^^^^
@ -85,9 +89,13 @@ help: consider borrowing here
|
LL | let a = &vec[0];
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let a = vec[0].clone();
| ++++++++
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:74:11
--> $DIR/borrowck-vec-pattern-nesting.rs:76:11
|
LL | match vec {
| ^^^ cannot move out of here
@ -106,7 +114,7 @@ LL + [_a, _b, _c] => {}
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:85:13
--> $DIR/borrowck-vec-pattern-nesting.rs:87:13
|
LL | let a = vec[0];
| ^^^^^^
@ -118,6 +126,10 @@ help: consider borrowing here
|
LL | let a = &vec[0];
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let a = vec[0].clone();
| ++++++++
error: aborting due to 8 previous errors

View File

@ -52,6 +52,11 @@ LL |
LL | println!("{b:?}");
| ----- borrow later used here
|
note: if `A` implemented `Clone`, you could clone the value
--> $DIR/clone-on-ref.rs:19:1
|
LL | struct A;
| ^^^^^^^^
help: consider annotating `A` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]

View File

@ -7,5 +7,5 @@ impl Foo {
}
fn main() {
let foo = &Foo;
<Foo as Clone>::clone(&(*foo)).foo(); //~ ERROR cannot move out
<Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
}

View File

@ -15,6 +15,11 @@ help: you can `clone` the value and consume it, but this might not be your desir
|
LL | <Foo as Clone>::clone(&(*foo)).foo();
| +++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL - (*foo).foo();
LL + foo.clone().foo();
|
error: aborting due to 1 previous error

View File

@ -4,11 +4,25 @@ error[E0382]: use of moved value: `state`
LL | fn fill_memory_blocks_mt(state: &mut State) {
| ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
LL | loop {
| ---- inside of this loop
LL | once(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
LL |
LL | fill_segment(state);
| ----- use occurs due to use in closure
|
note: consider changing this parameter type in function `fill_segment` to borrow instead if owning the value isn't necessary
--> $DIR/issue-101119.rs:14:20
|
LL | fn fill_segment(_: &mut State) {}
| ------------ ^^^^^^^^^^ this parameter takes ownership of the value
| |
| in this function
note: if `State` implemented `Clone`, you could clone the value
--> $DIR/issue-101119.rs:1:1
|
LL | struct State;
| ^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -9,6 +9,12 @@ LL | spawn_blocking(move || {
LL |
LL | self.b;
| ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
|
note: if `StructB` implemented `Clone`, you could clone the value
--> $DIR/issue-103624.rs:23:1
|
LL | struct StructB {}
| ^^^^^^^^^^^^^^
error[E0521]: borrowed data escapes outside of method
--> $DIR/issue-103624.rs:14:9

View File

@ -11,6 +11,11 @@ note: `Example::<E, FakeParam>::change` takes ownership of the receiver `self`,
|
LL | unsafe fn change<NewFakeParam>(self) -> Example<E, NewFakeParam> {
| ^^^^
note: if `Example<E, NoLifetime>` implemented `Clone`, you could clone the value
--> $DIR/issue-119915-bad-clone-suggestion.rs:3:1
|
LL | struct Example<E, FakeParam>(PhantomData<(fn(E), fn(FakeParam))>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -4,6 +4,11 @@ error[E0507]: cannot move out of static item `FOO`
LL | let _a = FOO;
| ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/issue-17718-static-move.rs:1:1
|
LL | struct Foo;
| ^^^^^^^^^^
help: consider borrowing here
|
LL | let _a = &FOO;

View File

@ -19,6 +19,11 @@ error[E0507]: cannot move out of a mutable reference
LL | let a = unsafe { *mut_ref() };
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
| ^^^^^^^^
help: consider removing the dereference here
|
LL - let a = unsafe { *mut_ref() };
@ -31,6 +36,11 @@ error[E0507]: cannot move out of a shared reference
LL | let b = unsafe { *imm_ref() };
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
| ^^^^^^^^
help: consider removing the dereference here
|
LL - let b = unsafe { *imm_ref() };
@ -43,6 +53,11 @@ error[E0507]: cannot move out of a raw pointer
LL | let c = unsafe { *mut_ptr() };
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
| ^^^^^^^^
help: consider removing the dereference here
|
LL - let c = unsafe { *mut_ptr() };
@ -55,6 +70,11 @@ error[E0507]: cannot move out of a raw pointer
LL | let d = unsafe { *const_ptr() };
| ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
| ^^^^^^^^
help: consider removing the dereference here
|
LL - let d = unsafe { *const_ptr() };

View File

@ -22,6 +22,11 @@ error[E0507]: cannot move out of static item `settings_dir`
|
LL | let settings_data = from_string(settings_dir);
| ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let settings_data = from_string(settings_dir.clone());
| ++++++++
error: aborting due to 3 previous errors

View File

@ -14,6 +14,10 @@ help: consider borrowing here
|
LL | let _foo: String = &val;
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let _foo: String = val.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -6,6 +6,12 @@ LL | &([S][0],);
| |
| cannot move out of here
| move occurs because value has type `S`, which does not implement the `Copy` trait
|
note: if `S` implemented `Clone`, you could clone the value
--> $DIR/move-error-in-promoted-2.rs:3:1
|
LL | struct S;
| ^^^^^^^^
error: aborting due to 1 previous error

View File

@ -6,6 +6,11 @@ LL | let _ = S1(C[0]).clone();
| |
| cannot move out of here
| move occurs because value has type `S2`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let _ = S1(C[0].clone()).clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ LL | let a = $c;
LL | sss!();
| ------ in this macro invocation
|
note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-error-snippets.rs:9:1
|
LL | struct A;
| ^^^^^^^^
= note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing here
|

View File

@ -3,24 +3,48 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference
|
LL | *u.a
| ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.a
LL + u.a.clone()
|
error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
--> $DIR/move-from-union-field-issue-66500.rs:16:5
|
LL | *u.b
| ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.b
LL + u.b.clone()
|
error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:20:5
|
LL | *u.c
| ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.c
LL + u.c.clone()
|
error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:24:5
|
LL | *u.d
| ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.d
LL + u.d.clone()
|
error: aborting due to 4 previous errors

View File

@ -3,12 +3,24 @@ error[E0507]: cannot move out of a shared reference
|
LL | static Y: usize = get(*&X);
| ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-in-static-initializer-issue-38520.rs:5:1
|
LL | struct Foo(usize);
| ^^^^^^^^^^
error[E0507]: cannot move out of a shared reference
--> $DIR/move-in-static-initializer-issue-38520.rs:13:22
|
LL | const Z: usize = get(*&X);
| ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-in-static-initializer-issue-38520.rs:5:1
|
LL | struct Foo(usize);
| ^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -9,7 +9,7 @@ fn call<F>(f: F) where F : Fn() {
fn main() {
let y = vec![format!("World")];
call(|| {
<Vec<String> as Clone>::clone(&y).into_iter();
<Vec<String> as Clone>::clone(&y.clone()).into_iter();
//~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
});
}

View File

@ -16,6 +16,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
|
LL | <Vec<String> as Clone>::clone(&y).into_iter();
| +++++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | y.clone().into_iter();
| ++++++++
error: aborting due to 1 previous error

View File

@ -11,6 +11,12 @@ LL | drop(alloc);
LL |
LL | use_value(*theref)
| ------- borrow later used here
|
note: if `Alloc` implemented `Clone`, you could clone the value
--> $DIR/leak-alloc.rs:8:1
|
LL | struct Alloc {}
| ^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -9,6 +9,12 @@ LL | drop(s);
| ^ move out of `s` occurs here
LL | }
| - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
LL + let _map = BTreeMap::from_iter([((), PrintOnDrop(s.clone()))]);
|
error: aborting due to 1 previous error

View File

@ -160,6 +160,10 @@ help: consider borrowing here
|
LL | &x
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | x.clone()
| ++++++++
error: aborting due to 17 previous errors

View File

@ -8,6 +8,10 @@ LL | struct StructA(String);
|
= note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -19,6 +23,10 @@ LL | struct StructA(String);
|
= note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -30,6 +38,10 @@ LL | struct StructA(String);
|
= note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -41,6 +53,10 @@ LL | struct StructA(String);
|
= note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -52,6 +68,10 @@ LL | struct StructA(String);
|
= note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -63,6 +83,10 @@ LL | struct StructA(String);
|
= note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -74,6 +98,10 @@ LL | struct StructA(String);
|
= note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -85,6 +113,10 @@ LL | struct StructA(String);
|
= note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16
@ -96,78 +128,142 @@ LL | struct StructA(String);
|
= note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
LL | struct StructA(String.clone());
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:28:9
|
LL | self.0
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | self.0.clone()
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:38:20
|
LL | let x = &{ self.0 };
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = &{ self.0.clone() };
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:45:12
|
LL | ({ self.0 }) == ({ other.0 })
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | ({ self.0.clone() }) == ({ other.0 })
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:45:28
|
LL | ({ self.0 }) == ({ other.0 })
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | ({ self.0 }) == ({ other.0.clone() })
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:53:36
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 })
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:53:49
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() })
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:68:20
|
LL | let x = &{ self.0 };
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = &{ self.0.clone() };
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:75:12
|
LL | ({ self.0 }) == ({ other.0 })
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | ({ self.0.clone() }) == ({ other.0 })
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:75:28
|
LL | ({ self.0 }) == ({ other.0 })
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | ({ self.0 }) == ({ other.0.clone() })
| ++++++++
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:83:36
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | PartialOrd::partial_cmp(&{ self.0.clone() }, &{ other.0 })
| ++++++++
error[E0507]: cannot move out of `other` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:83:49
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0.clone() })
| ++++++++
error[E0507]: cannot move out of `arg` which is behind a shared reference
--> $DIR/deriving-with-repr-packed-move-errors.rs:92:5
|
LL | arg.0
| ^^^^^ move occurs because `arg.0` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | arg.0.clone()
| ++++++++
error: aborting due to 21 previous errors

View File

@ -36,6 +36,11 @@ LL | #[repr(packed)]
LL | struct X(Y);
| ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait
|
note: if `Y` implemented `Clone`, you could clone the value
--> $DIR/deriving-with-repr-packed.rs:16:1
|
LL | struct Y(usize);
| ^^^^^^^^
= note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -9,6 +9,11 @@ LL | drop(a);
| ^ move out of `a` occurs here
LL | for s in &b {
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let b: Vec<&str> = a.clone().lines().collect();
| ++++++++
error: aborting due to 1 previous error

View File

@ -13,6 +13,12 @@ LL | println!("child function: {}", fancy_num.num);
...
LL | println!("main function: {}", fancy_ref.num);
| ------------- borrow later used here
|
note: if `FancyNum` implemented `Clone`, you could clone the value
--> $DIR/E0504.rs:1:1
|
LL | struct FancyNum {
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -10,6 +10,12 @@ LL | eat(x);
| ^ move out of `x` occurs here
LL | _ref_to_val.use_ref();
| ----------- borrow later used here
|
note: if `Value` implemented `Clone`, you could clone the value
--> $DIR/E0505.rs:1:1
|
LL | struct Value {}
| ^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -11,6 +11,11 @@ note: `TheDarkKnight::nothing_is_true` takes ownership of the receiver `self`, w
|
LL | fn nothing_is_true(self) {}
| ^^^^
note: if `TheDarkKnight` implemented `Clone`, you could clone the value
--> $DIR/E0507.rs:3:1
|
LL | struct TheDarkKnight;
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -7,6 +7,11 @@ LL | let _value = array[0];
| cannot move out of here
| move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/E0508-fail.rs:1:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
help: consider borrowing here
|
LL | let _value = &array[0];

View File

@ -7,6 +7,11 @@ LL | let _value = array[0];
| cannot move out of here
| move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/E0508.rs:1:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
help: consider borrowing here
|
LL | let _value = &array[0];

View File

@ -7,6 +7,11 @@ LL | let fancy_field = drop_struct.fancy;
| cannot move out of here
| move occurs because `drop_struct.fancy` has type `FancyNum`, which does not implement the `Copy` trait
|
note: if `FancyNum` implemented `Clone`, you could clone the value
--> $DIR/E0509.rs:1:1
|
LL | struct FancyNum {
| ^^^^^^^^^^^^^^^
help: consider borrowing here
|
LL | let fancy_field = &drop_struct.fancy;

View File

@ -10,6 +10,12 @@ LL | drop(x);
LL |
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = f(&x, ());
LL + let y = f(x.clone(), ());
|
error: aborting due to 1 previous error

View File

@ -27,6 +27,12 @@ LL | drop(x);
| ^ move out of `x` occurs here
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = f(&x, ());
LL + let y = f(x.clone(), ());
|
error: aborting due to 2 previous errors

View File

@ -10,6 +10,12 @@ LL | drop(x);
LL |
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = f(&x, ());
LL + let y = f(x.clone(), ());
|
error: aborting due to 1 previous error

View File

@ -6,6 +6,11 @@ LL | let _b = A { y: Arc::new(3), ..a };
| |
| cannot move out of here
| move occurs because `a.x` has type `Arc<isize>`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the functional record update syntax
|
LL | let _b = A { y: Arc::new(3), x: a.x.clone() };
| ~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error

View File

@ -7,6 +7,12 @@ LL | drop(foo);
| --- value moved here
LL | match foo {
| ^^^^^^^^^ value used here after move
|
note: if `X` implemented `Clone`, you could clone the value
--> $DIR/issue-17385.rs:1:1
|
LL | struct X(isize);
| ^^^^^^^^
error[E0382]: use of moved value: `e`
--> $DIR/issue-17385.rs:25:11
@ -17,6 +23,12 @@ LL | drop(e);
| - value moved here
LL | match e {
| ^ value used here after move
|
note: if `Enum` implemented `Clone`, you could clone the value
--> $DIR/issue-17385.rs:3:1
|
LL | enum Enum {
| ^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -1,4 +1,4 @@
struct NoCopy;
struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value
fn main() {
let x = NoCopy;
//~^ NOTE move occurs because `x` has type `NoCopy`

View File

@ -11,6 +11,12 @@ LL | let f = move || { let y = x; };
...
LL | let z = x;
| ^ value used here after move
|
note: if `NoCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-24357.rs:1:1
|
LL | struct NoCopy;
| ^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -3,6 +3,11 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared referenc
|
LL | self.tokens
| ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec<isize>`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | self.tokens.clone()
| ++++++++
error: aborting due to 1 previous error

View File

@ -8,6 +8,10 @@ help: consider borrowing here
|
LL | let e = &f.v[0];
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let e = f.v[0].clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference
|
LL | String::from_utf8(*key).unwrap()
| ^^^^ move occurs because `*key` has type `Vec<u8>`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - String::from_utf8(*key).unwrap()
LL + String::from_utf8(key.clone()).unwrap()
|
error: aborting due to 1 previous error

View File

@ -3,6 +3,12 @@ error[E0507]: cannot move out of `*inbounds` which is behind a shared reference
|
LL | array[*inbounds as usize]
| ^^^^^^^^^ move occurs because `*inbounds` has type `Enum`, which does not implement the `Copy` trait
|
note: if `Enum` implemented `Clone`, you could clone the value
--> $DIR/issue-102389.rs:1:1
|
LL | enum Enum { A, B, C }
| ^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -3,6 +3,10 @@
// 'value moved in previous iteration of loop' message
struct NonCopy;
//~^ NOTE if `NonCopy` implemented `Clone`
//~| NOTE if `NonCopy` implemented `Clone`
//~| NOTE if `NonCopy` implemented `Clone`
//~| NOTE if `NonCopy` implemented `Clone`
fn good() {
loop {

View File

@ -1,5 +1,5 @@
error[E0382]: use of moved value: `value`
--> $DIR/issue-72649-uninit-in-loop.rs:20:22
--> $DIR/issue-72649-uninit-in-loop.rs:24:22
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@ -9,9 +9,15 @@ LL | let _used = value;
LL |
LL | let _used2 = value;
| ^^^^^ value used here after move
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
error[E0382]: use of moved value: `value`
--> $DIR/issue-72649-uninit-in-loop.rs:32:26
--> $DIR/issue-72649-uninit-in-loop.rs:36:26
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@ -23,9 +29,15 @@ LL | let _used = value;
...
LL | let _used2 = value;
| ^^^^^ value used here after move
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
error[E0382]: use of moved value: `value`
--> $DIR/issue-72649-uninit-in-loop.rs:42:21
--> $DIR/issue-72649-uninit-in-loop.rs:46:21
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@ -34,9 +46,15 @@ LL | loop {
| ---- inside of this loop
LL | let _used = value;
| ^^^^^ value moved here, in previous iteration of loop
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
error[E0382]: use of moved value: `value`
--> $DIR/issue-72649-uninit-in-loop.rs:53:22
--> $DIR/issue-72649-uninit-in-loop.rs:57:22
|
LL | let mut value = NonCopy{};
| --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@ -45,9 +63,15 @@ LL | loop {
| ---- inside of this loop
LL | let _used2 = value;
| ^^^^^ value moved here, in previous iteration of loop
|
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^
error[E0381]: used binding `value` isn't initialized
--> $DIR/issue-72649-uninit-in-loop.rs:61:21
--> $DIR/issue-72649-uninit-in-loop.rs:65:21
|
LL | let value: NonCopy;
| ----- binding declared here but left uninitialized
@ -60,7 +84,7 @@ LL | let value: NonCopy = value;
| +++++++
error[E0381]: used binding `value` isn't initialized
--> $DIR/issue-72649-uninit-in-loop.rs:69:21
--> $DIR/issue-72649-uninit-in-loop.rs:73:21
|
LL | let mut value: NonCopy;
| --------- binding declared here but left uninitialized

View File

@ -4,11 +4,18 @@ error[E0382]: use of moved value: `a`
LL | let mut a = NotCopy;
| ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait
LL | loop {
| ---- inside of this loop
LL | || {
| ^^ value moved into closure here, in previous iteration of loop
LL | &mut a;
LL | a;
| - use occurs due to use in closure
|
note: if `NotCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-75904-move-closure-loop.rs:5:1
|
LL | struct NotCopy;
| ^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -101,6 +101,12 @@ LL | mut_foo;
| ^^^^^^^ move out of `mut_foo` occurs here
LL | ret;
| --- borrow later used here
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-fn-self-receiver.rs:5:1
|
LL | struct Foo;
| ^^^^^^^^^^
error[E0382]: use of moved value: `rc_foo`
--> $DIR/move-fn-self-receiver.rs:55:5
@ -132,6 +138,11 @@ LL | foo_add + Foo;
LL | foo_add;
| ^^^^^^^ value used here after move
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-fn-self-receiver.rs:5:1
|
LL | struct Foo;
| ^^^^^^^^^^
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL

View File

@ -6,6 +6,12 @@ LL | a[i]
| |
| cannot move out of here
| move occurs because `a[_]` has type `D`, which does not implement the `Copy` trait
|
note: if `D` implemented `Clone`, you could clone the value
--> $DIR/move-out-of-array-1.rs:5:1
|
LL | struct D { _x: u8 }
| ^^^^^^^^
error: aborting due to 1 previous error

View File

@ -2,7 +2,7 @@ use std::thread;
fn main() {
let x = "Hello world!".to_string();
thread::spawn(move|| {
thread::spawn(move || {
println!("{}", x);
});
println!("{}", x); //~ ERROR borrow of moved value

View File

@ -3,8 +3,8 @@ error[E0382]: borrow of moved value: `x`
|
LL | let x = "Hello world!".to_string();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | thread::spawn(move || {
| ------- value moved into closure here
LL | println!("{}", x);
| - variable moved due to use in closure
LL | });

View File

@ -7,6 +7,11 @@ LL | let _f = to_fn(|| test(i));
| -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
| |
| captured by this `Fn` closure
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let _f = to_fn(|| test(i.clone()));
| ++++++++
error: aborting due to 1 previous error

View File

@ -12,7 +12,7 @@ impl Deref for S {
impl S {
fn foo(&self) {
// `self.clone()` returns `&S`, not `Vec`
for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} //~ ERROR cannot move out of dereference of `S`
for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {} //~ ERROR cannot move out of dereference of `S`
}
}
fn main() {}

View File

@ -10,8 +10,8 @@ note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {}
| ++++++++++++++++++++++++++++++ +
LL | for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {}
| ++++++++++++++++++++++++++++++ ~
error: aborting due to 1 previous error

View File

@ -18,7 +18,7 @@ pub fn hashmap_copy<T, U>(
map: &HashMap<T, U, Hash128_1>,
) where T: Hash + Clone, U: Clone
{
let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); //~ ERROR
let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect(); //~ ERROR
}
pub fn make_map() -> HashMap<String, i64, Hash128_1>

View File

@ -10,8 +10,8 @@ note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`,
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ ~
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]

View File

@ -7,5 +7,5 @@ impl Foo {
}
fn main() {
let foo = &Foo;
<Foo as Clone>::clone(&foo).foo(); //~ ERROR cannot move out
<Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
}

View File

@ -15,6 +15,10 @@ help: you can `clone` the value and consume it, but this might not be your desir
|
LL | <Foo as Clone>::clone(&foo).foo();
| +++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | foo.clone().foo();
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ help: consider removing the dereference here
LL - let x = { *r };
LL + let x = { r };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let x = { *r };
LL + let x = { r.clone() };
|
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:6:22
@ -21,6 +26,11 @@ help: consider removing the dereference here
LL - let y = unsafe { *r };
LL + let y = unsafe { r };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = unsafe { *r };
LL + let y = unsafe { r.clone() };
|
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:7:26
@ -33,6 +43,11 @@ help: consider removing the dereference here
LL - let z = loop { break *r; };
LL + let z = loop { break r; };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let z = loop { break *r; };
LL + let z = loop { break r.clone(); };
|
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:11:15
@ -47,6 +62,10 @@ help: consider borrowing here
|
LL | let x = { &arr[0] };
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = { arr[0].clone() };
| ++++++++
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:12:22
@ -61,6 +80,10 @@ help: consider borrowing here
|
LL | let y = unsafe { &arr[0] };
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let y = unsafe { arr[0].clone() };
| ++++++++
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:13:26
@ -75,6 +98,10 @@ help: consider borrowing here
|
LL | let z = loop { break &arr[0]; };
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let z = loop { break arr[0].clone(); };
| ++++++++
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:17:38
@ -87,6 +114,11 @@ help: consider removing the dereference here
LL - let x = { let mut u = 0; u += 1; *r };
LL + let x = { let mut u = 0; u += 1; r };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let x = { let mut u = 0; u += 1; *r };
LL + let x = { let mut u = 0; u += 1; r.clone() };
|
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:18:45
@ -99,6 +131,11 @@ help: consider removing the dereference here
LL - let y = unsafe { let mut u = 0; u += 1; *r };
LL + let y = unsafe { let mut u = 0; u += 1; r };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = unsafe { let mut u = 0; u += 1; *r };
LL + let y = unsafe { let mut u = 0; u += 1; r.clone() };
|
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:19:49
@ -111,6 +148,11 @@ help: consider removing the dereference here
LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
LL + let z = loop { let mut u = 0; u += 1; break r; u += 2; };
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
LL + let z = loop { let mut u = 0; u += 1; break r.clone(); u += 2; };
|
error: aborting due to 9 previous errors

View File

@ -57,6 +57,12 @@ LL | || x;
| move out of `x` occurs here
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let r = &x;
LL + let r = x.clone();
|
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:35:5
@ -103,6 +109,11 @@ LL | || *x = String::new();
| ^^ -- borrow occurs due to use in closure
| |
| value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let r = x.clone();
| ++++++++
error[E0382]: use of moved value: `x`
--> $DIR/closure-access-spans.rs:50:5
@ -115,6 +126,11 @@ LL | || x;
| ^^ - use occurs due to use in closure
| |
| value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let r = x.clone();
| ++++++++
error: aborting due to 9 previous errors

View File

@ -0,0 +1,23 @@
// check that moves due to a closure capture give a special note
//@ run-rustfix
#![allow(unused_variables, unused_must_use, dead_code)]
fn move_after_move(x: String) {
|| x.clone();
let y = x; //~ ERROR
}
fn borrow_after_move(x: String) {
|| x.clone();
let y = &x; //~ ERROR
}
fn borrow_mut_after_move(mut x: String) {
|| x.clone();
let y = &mut x; //~ ERROR
}
fn fn_ref<F: Fn()>(f: F) -> F { f }
fn fn_mut<F: FnMut()>(f: F) -> F { f }
fn main() {}

View File

@ -1,4 +1,6 @@
// check that moves due to a closure capture give a special note
//@ run-rustfix
#![allow(unused_variables, unused_must_use, dead_code)]
fn move_after_move(x: String) {
|| x;

View File

@ -1,5 +1,5 @@
error[E0382]: use of moved value: `x`
--> $DIR/closure-move-spans.rs:5:13
--> $DIR/closure-move-spans.rs:7:13
|
LL | fn move_after_move(x: String) {
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@ -9,9 +9,14 @@ LL | || x;
| value moved into closure here
LL | let y = x;
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | || x.clone();
| ++++++++
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-move-spans.rs:10:13
--> $DIR/closure-move-spans.rs:12:13
|
LL | fn borrow_after_move(x: String) {
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@ -21,9 +26,14 @@ LL | || x;
| value moved into closure here
LL | let y = &x;
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | || x.clone();
| ++++++++
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-move-spans.rs:15:13
--> $DIR/closure-move-spans.rs:17:13
|
LL | fn borrow_mut_after_move(mut x: String) {
| ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait
@ -33,6 +43,11 @@ LL | || x;
| value moved into closure here
LL | let y = &mut x;
| ^^^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | || x.clone();
| ++++++++
error: aborting due to 3 previous errors

View File

@ -4,10 +4,16 @@ error[E0382]: use of moved value: `x`
LL | fn repreated_move(x: String) {
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | for i in 0..10 {
| -------------- inside of this loop
LL | || x;
| ^^ - use occurs due to use in closure
| |
| value moved into closure here, in previous iteration of loop
|
help: consider cloning the value if the performance cost is acceptable
|
LL | || x.clone();
| ++++++++
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/closures-in-loops.rs:13:16

Some files were not shown because too many files have changed in this diff Show More