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:
commit
6eaa7fb576
@ -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
|
||||
|
@ -203,13 +203,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
|
||||
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 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
Some(name) => format!("`{name}`"),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) {
|
||||
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_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 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
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 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
|
||||
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 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
|
||||
} 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 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||
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 @@ fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>
|
||||
} 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 @@ pub(crate) fn report_move_out_while_borrowed(
|
||||
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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
}
|
||||
}
|
||||
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 @@ fn suggest_using_local_if_applicable(
|
||||
);
|
||||
}
|
||||
|
||||
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<'_>,
|
||||
|
@ -5,6 +5,7 @@
|
||||
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::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 @@ pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
||||
#[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 @@ pub(super) fn args_subdiag(
|
||||
#[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 @@ pub(super) fn var_path_only_subdiag(
|
||||
#[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 @@ fn explain_captures(
|
||||
.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 @@ fn explain_captures(
|
||||
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 @@ fn explain_captures(
|
||||
.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())]
|
||||
|
@ -435,7 +435,9 @@ fn report_cannot_move_from_borrowed_content(
|
||||
|
||||
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 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
|
||||
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 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
|
||||
}
|
||||
// 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 @@ fn add_move_error_details(&self, err: &mut Diag<'_>, binds_to: &[Local]) {
|
||||
|
||||
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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -9,4 +9,5 @@ fn broken(x: &String) -> String {
|
||||
};
|
||||
|
||||
fn main() {
|
||||
println!("{}", MOVE(&String::new()));
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -8,7 +8,8 @@ struct Foo {
|
||||
|
||||
|
||||
fn test(f: Foo) {
|
||||
let _f = Foo{foo: 4, ..f};
|
||||
let f = Foo { foo: 4, ..f };
|
||||
println!("{}", f.foo);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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() };
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
});
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
fn main() {
|
||||
let x = "Hello world!".to_string();
|
||||
thread::spawn(move|| {
|
||||
thread::spawn(move || {
|
||||
println!("{}", x);
|
||||
});
|
||||
println!("{}", x); //~ ERROR borrow of moved value
|
||||
|
@ -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 | });
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
23
tests/ui/nll/closure-move-spans.fixed
Normal file
23
tests/ui/nll/closure-move-spans.fixed
Normal 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() {}
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user