diff --git a/Cargo.lock b/Cargo.lock
index 552b446a1e753..4a54dc87862e5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3341,6 +3341,7 @@ dependencies = [
name = "run_make_support"
version = "0.0.0"
dependencies = [
+ "gimli",
"object 0.34.0",
"regex",
"wasmparser",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index bddb50568d41b..727c6bc82fef9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3112,6 +3112,7 @@ pub struct Delegation {
/// Path resolution id.
pub id: NodeId,
pub qself: Option
>,
+ pub rename: Option,
pub path: Path,
pub body: Option>,
}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index c4e49d7dbea44..7dbfb7c736454 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1149,10 +1149,13 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
- ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
+ if let Some(rename) = rename {
+ vis.visit_ident(rename);
+ }
if let Some(body) = body {
vis.visit_block(body);
}
@@ -1195,10 +1198,13 @@ pub fn noop_flat_map_assoc_item(
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
- AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
visitor.visit_id(id);
visitor.visit_qself(qself);
visitor.visit_path(path);
+ if let Some(rename) = rename {
+ visitor.visit_ident(rename);
+ }
if let Some(body) = body {
visitor.visit_block(body);
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 968d10ad4872c..d9740928f8d67 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -382,11 +382,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
- ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(path, *id));
+ visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
}
@@ -782,11 +783,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
- AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
+ AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(path, *id));
+ visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
}
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index f4d5e71badebb..a1e5c275c189c 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -49,7 +49,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
-use rustc_middle::ty::ResolverAstLowering;
+use rustc_middle::ty::{Asyncness, ResolverAstLowering};
use rustc_span::{symbol::Ident, Span};
use rustc_target::spec::abi;
use std::iter;
@@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
return false;
};
if let Some(local_sig_id) = sig_id.as_local() {
- self.resolver.has_self.contains(&local_sig_id)
+ self.resolver.delegation_fn_sigs[&local_sig_id].has_self
} else {
match self.tcx.def_kind(sig_id) {
DefKind::Fn => false,
@@ -82,13 +82,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
delegation: &Delegation,
item_id: NodeId,
) -> DelegationResults<'hir> {
- let span = delegation.path.segments.last().unwrap().ident.span;
+ let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
match sig_id {
Ok(sig_id) => {
- let decl = self.lower_delegation_decl(sig_id, span);
- let sig = self.lower_delegation_sig(span, decl);
- let body_id = self.lower_delegation_body(sig.decl, delegation);
+ let (param_count, c_variadic) = self.param_count(sig_id);
+ let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
+ let sig = self.lower_delegation_sig(sig_id, decl, span);
+ let body_id = self.lower_delegation_body(delegation, param_count, span);
let generics = self.lower_delegation_generics(span);
DelegationResults { body_id, sig, generics }
@@ -123,34 +124,47 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}
+ // Function parameter count, including C variadic `...` if present.
+ fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
+ if let Some(local_sig_id) = sig_id.as_local() {
+ // Map may be filled incorrectly due to recursive delegation.
+ // Error will be emmited later during HIR ty lowering.
+ match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
+ Some(sig) => (sig.param_count, sig.c_variadic),
+ None => (0, false),
+ }
+ } else {
+ let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
+ (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
+ }
+ }
+
fn lower_delegation_decl(
&mut self,
sig_id: DefId,
- param_span: Span,
+ param_count: usize,
+ c_variadic: bool,
+ span: Span,
) -> &'hir hir::FnDecl<'hir> {
- let args_count = if let Some(local_sig_id) = sig_id.as_local() {
- // Map may be filled incorrectly due to recursive delegation.
- // Error will be emitted later during HIR ty lowering.
- self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
- } else {
- self.tcx.fn_arg_names(sig_id).len()
- };
- let inputs = self.arena.alloc_from_iter((0..args_count).map(|arg| hir::Ty {
+ // The last parameter in C variadic functions is skipped in the signature,
+ // like during regular lowering.
+ let decl_param_count = param_count - c_variadic as usize;
+ let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
- span: self.lower_span(param_span),
+ span,
}));
let output = self.arena.alloc(hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
- span: self.lower_span(param_span),
+ span,
});
self.arena.alloc(hir::FnDecl {
inputs,
output: hir::FnRetTy::Return(output),
- c_variadic: false,
+ c_variadic,
lifetime_elision_allowed: true,
implicit_self: hir::ImplicitSelfKind::None,
})
@@ -158,35 +172,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_delegation_sig(
&mut self,
- span: Span,
+ sig_id: DefId,
decl: &'hir hir::FnDecl<'hir>,
+ span: Span,
) -> hir::FnSig<'hir> {
- hir::FnSig {
- decl,
- header: hir::FnHeader {
- unsafety: hir::Unsafety::Normal,
- constness: hir::Constness::NotConst,
- asyncness: hir::IsAsync::NotAsync,
- abi: abi::Abi::Rust,
- },
- span: self.lower_span(span),
- }
+ let header = if let Some(local_sig_id) = sig_id.as_local() {
+ match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
+ Some(sig) => self.lower_fn_header(sig.header),
+ None => self.generate_header_error(),
+ }
+ } else {
+ let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
+ let asyncness = match self.tcx.asyncness(sig_id) {
+ Asyncness::Yes => hir::IsAsync::Async(span),
+ Asyncness::No => hir::IsAsync::NotAsync,
+ };
+ hir::FnHeader {
+ unsafety: sig.unsafety,
+ constness: self.tcx.constness(sig_id),
+ asyncness,
+ abi: sig.abi,
+ }
+ };
+ hir::FnSig { decl, header, span }
}
- fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
+ fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
let pat_node_id = self.next_node_id();
let pat_id = self.lower_node_id(pat_node_id);
let pat = self.arena.alloc(hir::Pat {
hir_id: pat_id,
kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None),
- span: ty.span,
+ span,
default_binding_modes: false,
});
- (hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
+ (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
}
- fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
+ fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> {
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
ident: Ident::empty(),
hir_id: self.next_id(),
@@ -195,20 +219,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
infer_args: false,
}));
- let path =
- self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
+ let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
- span: ty.span,
+ span,
}
}
fn lower_delegation_body(
&mut self,
- decl: &'hir hir::FnDecl<'hir>,
delegation: &Delegation,
+ param_count: usize,
+ span: Span,
) -> BodyId {
let path = self.lower_qpath(
delegation.id,
@@ -224,8 +248,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut parameters: Vec> = Vec::new();
let mut args: Vec> = Vec::new();
- for (idx, param_ty) in decl.inputs.iter().enumerate() {
- let (param, pat_node_id) = this.generate_param(param_ty);
+ for idx in 0..param_count {
+ let (param, pat_node_id) = this.generate_param(span);
parameters.push(param);
let arg = if let Some(block) = block
@@ -245,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
} else {
let pat_hir_id = this.lower_node_id(pat_node_id);
- this.generate_arg(param_ty, pat_hir_id)
+ this.generate_arg(pat_hir_id, span)
};
args.push(arg);
}
@@ -304,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
implicit_self: hir::ImplicitSelfKind::None,
});
- let sig = self.lower_delegation_sig(span, decl);
+ let header = self.generate_header_error();
+ let sig = hir::FnSig { decl, header, span };
+
let body_id = self.lower_body(|this| {
let expr =
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
@@ -312,6 +338,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
DelegationResults { generics, body_id, sig }
}
+
+ fn generate_header_error(&self) -> hir::FnHeader {
+ hir::FnHeader {
+ unsafety: hir::Unsafety::Normal,
+ constness: hir::Constness::NotConst,
+ asyncness: hir::IsAsync::NotAsync,
+ abi: abi::Abi::Rust,
+ }
+ }
}
struct SelfResolver<'a> {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index e4c633aa324a8..1a1c50018ac52 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1344,7 +1344,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
- fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+ pub(super) fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
hir::IsAsync::Async(span)
} else {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 4878da530b0f5..93ea8fb6979a6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -347,7 +347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
mpi: MovePathIndex,
err: &mut Diag<'tcx>,
in_pattern: &mut bool,
- move_spans: UseSpans<'_>,
+ move_spans: UseSpans<'tcx>,
) {
let move_span = match move_spans {
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -491,11 +491,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
..
} = move_spans
{
- self.suggest_cloning(err, ty, expr, None);
+ self.suggest_cloning(err, ty, expr, None, Some(move_spans));
} 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, None);
+ self.suggest_cloning(err, ty, expr, None, Some(move_spans));
}
}
if let Some(pat) = finder.pat {
@@ -1085,6 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty: Ty<'tcx>,
mut expr: &'cx hir::Expr<'cx>,
mut other_expr: Option<&'cx hir::Expr<'cx>>,
+ use_spans: Option>,
) {
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
// We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
@@ -1197,14 +1198,50 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
})
{
+ let ty_span = self.infcx.tcx.def_span(def.did());
+ let mut span: MultiSpan = ty_span.into();
+ span.push_span_label(ty_span, "consider implementing `Clone` for this type");
+ span.push_span_label(expr.span, "you could clone this value");
err.span_note(
- self.infcx.tcx.def_span(def.did()),
+ span,
+ format!("if `{ty}` implemented `Clone`, you could clone the value"),
+ );
+ } else if let ty::Param(param) = ty.kind()
+ && let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
+ && let generics = self.infcx.tcx.generics_of(self.mir_def_id())
+ && let generic_param = generics.type_param(*param, self.infcx.tcx)
+ && let param_span = self.infcx.tcx.def_span(generic_param.def_id)
+ && if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans
+ && let CallKind::FnCall { fn_trait_id, self_ty } = kind
+ && let ty::Param(_) = self_ty.kind()
+ && ty == self_ty
+ && [
+ self.infcx.tcx.lang_items().fn_once_trait(),
+ self.infcx.tcx.lang_items().fn_mut_trait(),
+ self.infcx.tcx.lang_items().fn_trait(),
+ ]
+ .contains(&Some(fn_trait_id))
+ {
+ // Do not suggest `F: FnOnce() + Clone`.
+ false
+ } else {
+ true
+ }
+ {
+ let mut span: MultiSpan = param_span.into();
+ span.push_span_label(
+ param_span,
+ "consider constraining this type parameter with `Clone`",
+ );
+ span.push_span_label(expr.span, "you could clone this value");
+ err.span_help(
+ span,
format!("if `{ty}` implemented `Clone`, you could clone the value"),
);
}
}
- fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
+ pub(crate) 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)
@@ -1403,7 +1440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans));
}
self.buffer_error(err);
}
@@ -1964,7 +2001,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> {
let tcx = self.infcx.tcx;
let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
- let mut expr_finder = FindExprBySpan::new(span);
+ let mut expr_finder = FindExprBySpan::new(span, tcx);
expr_finder.visit_expr(tcx.hir().body(body_id).value);
expr_finder.result
}
@@ -1998,14 +2035,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
let mut expr_finder =
- FindExprBySpan::new(self.body.local_decls[*index1].source_info.span);
+ FindExprBySpan::new(self.body.local_decls[*index1].source_info.span, tcx);
expr_finder.visit_expr(hir.body(body_id).value);
let Some(index1) = expr_finder.result else {
note_default_suggestion();
return;
};
- expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span);
+ expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span, tcx);
expr_finder.visit_expr(hir.body(body_id).value);
let Some(index2) = expr_finder.result else {
note_default_suggestion();
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 418eabe3ae242..5ebdb69050b24 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -76,7 +76,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
&& let Some(body_id) = node.body_id()
{
let body = tcx.hir().body(body_id);
- let mut expr_finder = FindExprBySpan::new(span);
+ let mut expr_finder = FindExprBySpan::new(span, tcx);
expr_finder.visit_expr(body.value);
if let Some(mut expr) = expr_finder.result {
while let hir::ExprKind::AddrOf(_, _, inner)
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index bc02c5be93d61..288b846daf56e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -2,10 +2,13 @@
#![allow(rustc::untranslatable_diagnostic)]
use rustc_errors::{Applicability, Diag};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{CaptureBy, ExprKind, HirId, Node};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
+use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
use crate::diagnostics::CapturedMessageOpt;
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
@@ -303,6 +306,121 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.cannot_move_out_of(span, &description)
}
+ fn suggest_clone_of_captured_var_in_move_closure(
+ &self,
+ err: &mut Diag<'_>,
+ upvar_hir_id: HirId,
+ upvar_name: &str,
+ use_spans: Option>,
+ ) {
+ let tcx = self.infcx.tcx;
+ let typeck_results = tcx.typeck(self.mir_def_id());
+ let Some(use_spans) = use_spans else { return };
+ // We only care about the case where a closure captured a binding.
+ let UseSpans::ClosureUse { args_span, .. } = use_spans else { return };
+ let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
+ // Fetch the type of the expression corresponding to the closure-captured binding.
+ let Some(captured_ty) = typeck_results.node_type_opt(upvar_hir_id) else { return };
+ if !self.implements_clone(captured_ty) {
+ // We only suggest cloning the captured binding if the type can actually be cloned.
+ return;
+ };
+ // Find the closure that captured the binding.
+ let mut expr_finder = FindExprBySpan::new(args_span, tcx);
+ expr_finder.include_closures = true;
+ expr_finder.visit_expr(tcx.hir().body(body_id).value);
+ let Some(closure_expr) = expr_finder.result else { return };
+ let ExprKind::Closure(closure) = closure_expr.kind else { return };
+ // We'll only suggest cloning the binding if it's a `move` closure.
+ let CaptureBy::Value { .. } = closure.capture_clause else { return };
+ // Find the expression within the closure where the binding is consumed.
+ let mut suggested = false;
+ let use_span = use_spans.var_or_use();
+ let mut expr_finder = FindExprBySpan::new(use_span, tcx);
+ expr_finder.include_closures = true;
+ expr_finder.visit_expr(tcx.hir().body(body_id).value);
+ let Some(use_expr) = expr_finder.result else { return };
+ let parent = tcx.parent_hir_node(use_expr.hir_id);
+ if let Node::Expr(expr) = parent
+ && let ExprKind::Assign(lhs, ..) = expr.kind
+ && lhs.hir_id == use_expr.hir_id
+ {
+ // Cloning the value being assigned makes no sense:
+ //
+ // error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ // --> $DIR/option-content-move2.rs:11:9
+ // |
+ // LL | let mut var = None;
+ // | ------- captured outer variable
+ // LL | func(|| {
+ // | -- captured by this `FnMut` closure
+ // LL | // Shouldn't suggest `move ||.as_ref()` here
+ // LL | move || {
+ // | ^^^^^^^ `var` is moved here
+ // LL |
+ // LL | var = Some(NotCopyable);
+ // | ---
+ // | |
+ // | variable moved due to use in closure
+ // | move occurs because `var` has type `Option`, which does not implement the `Copy` trait
+ // |
+ return;
+ }
+
+ // Search for an appropriate place for the structured `.clone()` suggestion to be applied.
+ // If we encounter a statement before the borrow error, we insert a statement there.
+ for (_, node) in tcx.hir().parent_iter(closure_expr.hir_id) {
+ if let Node::Stmt(stmt) = node {
+ let padding = tcx
+ .sess
+ .source_map()
+ .indentation_before(stmt.span)
+ .unwrap_or_else(|| " ".to_string());
+ err.multipart_suggestion_verbose(
+ "clone the value before moving it into the closure",
+ vec![
+ (
+ stmt.span.shrink_to_lo(),
+ format!("let value = {upvar_name}.clone();\n{padding}"),
+ ),
+ (use_span, "value".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ suggested = true;
+ break;
+ } else if let Node::Expr(expr) = node
+ && let ExprKind::Closure(_) = expr.kind
+ {
+ // We want to suggest cloning only on the first closure, not
+ // subsequent ones (like `ui/suggestions/option-content-move2.rs`).
+ break;
+ }
+ }
+ if !suggested {
+ // If we couldn't find a statement for us to insert a new `.clone()` statement before,
+ // we have a bare expression, so we suggest the creation of a new block inline to go
+ // from `move || val` to `{ let value = val.clone(); move || value }`.
+ let padding = tcx
+ .sess
+ .source_map()
+ .indentation_before(closure_expr.span)
+ .unwrap_or_else(|| " ".to_string());
+ err.multipart_suggestion_verbose(
+ "clone the value before moving it into the closure",
+ vec![
+ (
+ closure_expr.span.shrink_to_lo(),
+ format!("{{\n{padding}let value = {upvar_name}.clone();\n{padding}"),
+ ),
+ (use_spans.var_or_use(), "value".to_string()),
+ (closure_expr.span.shrink_to_hi(), format!("\n{padding}}}")),
+ ],
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
fn report_cannot_move_from_borrowed_content(
&mut self,
move_place: Place<'tcx>,
@@ -310,10 +428,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
span: Span,
use_spans: Option>,
) -> Diag<'tcx> {
+ let tcx = self.infcx.tcx;
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.
- let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
+ let ty = deref_target_place.ty(self.body, tcx).ty;
let upvar_field = self
.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
@@ -363,8 +482,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar = &self.upvars[upvar_field.unwrap().index()];
let upvar_hir_id = upvar.get_root_variable();
- let upvar_name = upvar.to_string(self.infcx.tcx);
- let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
+ let upvar_name = upvar.to_string(tcx);
+ let upvar_span = tcx.hir().span(upvar_hir_id);
let place_name = self.describe_any_place(move_place.as_ref());
@@ -380,12 +499,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
closure_kind_ty, closure_kind, place_description,
);
- self.cannot_move_out_of(span, &place_description)
+ let closure_span = tcx.def_span(def_id);
+ let mut err = self
+ .cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
.with_span_label(
- self.infcx.tcx.def_span(def_id),
+ closure_span,
format!("captured by this `{closure_kind}` closure"),
- )
+ );
+ self.suggest_clone_of_captured_var_in_move_closure(
+ &mut err,
+ upvar_hir_id,
+ &upvar_name,
+ use_spans,
+ );
+ err
}
_ => {
let source = self.borrowed_content_source(deref_base);
@@ -415,7 +543,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
),
(_, _, _) => self.cannot_move_out_of(
span,
- &source.describe_for_unnamed_place(self.infcx.tcx),
+ &source.describe_for_unnamed_place(tcx),
),
}
}
@@ -447,7 +575,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(expr) = self.find_expr(span) {
- self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span));
+ self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None);
}
err.subdiagnostic(
@@ -482,7 +610,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(expr) = self.find_expr(use_span) {
- self.suggest_cloning(err, place_ty, expr, self.find_expr(span));
+ self.suggest_cloning(
+ err,
+ place_ty,
+ expr,
+ self.find_expr(span),
+ Some(use_spans),
+ );
}
err.subdiagnostic(
@@ -595,7 +729,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
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);
+ self.suggest_cloning(err, bind_to.ty, expr, None, None);
}
err.subdiagnostic(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 4a0df6cf7b86f..63da27246a2af 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1964,11 +1964,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
try_emit("recursive delegation");
}
- let sig = self.tcx().fn_sig(sig_id).instantiate_identity();
- if sig.output().has_opaque_types() {
- try_emit("delegation to a function with opaque type");
- }
-
let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id());
let parent_generics = self.tcx().generics_of(parent);
@@ -1991,29 +1986,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
try_emit("delegation to a trait method from a free function");
}
- if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
- try_emit("delegation to async functions");
- }
-
- if self.tcx().constness(sig_id) == hir::Constness::Const {
- try_emit("delegation to const functions");
- }
-
- if sig.c_variadic() {
- try_emit("delegation to variadic functions");
- // variadic functions are also `unsafe` and `extern "C"`.
- // Do not emit same error multiple times.
- return error_occured;
- }
-
- if let hir::Unsafety::Unsafe = sig.unsafety() {
- try_emit("delegation to unsafe functions");
- }
-
- if abi::Abi::Rust != sig.abi() {
- try_emit("delegation to non Rust ABI functions");
- }
-
error_occured
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cc026e349d74e..cda332aee5647 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -45,7 +45,7 @@ use rustc_data_structures::unord::UnordMap;
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
@@ -224,8 +224,15 @@ pub struct ResolverAstLowering {
pub lint_buffer: Steal,
/// Information about functions signatures for delegation items expansion
- pub has_self: LocalDefIdSet,
- pub fn_parameter_counts: LocalDefIdMap,
+ pub delegation_fn_sigs: LocalDefIdMap,
+}
+
+#[derive(Debug)]
+pub struct DelegationFnSig {
+ pub header: ast::FnHeader,
+ pub param_count: usize,
+ pub has_self: bool,
+ pub c_variadic: bool,
}
#[derive(Clone, Copy, Debug)]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 84ecd0a0de54f..ed51710564a42 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -686,6 +686,8 @@ impl<'a> Parser<'a> {
(None, self.parse_path(PathStyle::Expr)?)
};
+ let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None };
+
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
Some(self.parse_block()?)
} else {
@@ -695,11 +697,9 @@ impl<'a> Parser<'a> {
let span = span.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::fn_delegation, span);
- let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
- Ok((
- ident,
- ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
- ))
+ let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
+ let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
+ Ok((ident, ItemKind::Delegation(Box::new(deleg))))
}
fn parse_item_list(
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c877ae5e21f48..292af43b602e0 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -21,6 +21,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_bound_vars::Set1;
+use rustc_middle::ty::DelegationFnSig;
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, ResolveDocLinks};
use rustc_session::lint;
@@ -4749,12 +4750,13 @@ struct ItemInfoCollector<'a, 'b, 'tcx> {
impl ItemInfoCollector<'_, '_, '_> {
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) {
- let def_id = self.r.local_def_id(id);
- self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len());
-
- if sig.decl.has_self() {
- self.r.has_self.insert(def_id);
- }
+ let sig = DelegationFnSig {
+ header: sig.header,
+ param_count: sig.decl.inputs.len(),
+ has_self: sig.decl.has_self(),
+ c_variadic: sig.decl.c_variadic(),
+ };
+ self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
}
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index d79c638fa0789..64451030adf0f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2039,7 +2039,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
ast::AssocItemKind::Delegation(..)
- if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) =>
+ if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)]
+ .has_self =>
{
AssocSuggestion::MethodWithSelf { called }
}
@@ -2062,7 +2063,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if filter_fn(res) {
let def_id = res.def_id();
let has_self = match def_id.as_local() {
- Some(def_id) => self.r.has_self.contains(&def_id),
+ Some(def_id) => {
+ self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self)
+ }
None => self
.r
.tcx
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b5b6d899cc58e..e07c3247d07ae 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -43,7 +43,7 @@ use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::NonMacroAttrKind;
use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{PrimTy, TraitCandidate};
use rustc_index::IndexVec;
@@ -52,8 +52,8 @@ use rustc_middle::metadata::ModChild;
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
-use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt, TyCtxtFeed};
-use rustc_middle::ty::{Feed, ResolverGlobalCtxt, ResolverOutputs};
+use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTools};
+use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed};
use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
use rustc_session::lint::LintBuffer;
@@ -992,7 +992,6 @@ pub struct Resolver<'a, 'tcx> {
extern_prelude: FxHashMap>,
/// N.B., this is used only for better diagnostics, not name resolution itself.
- has_self: LocalDefIdSet,
field_def_ids: LocalDefIdMap<&'tcx [DefId]>,
/// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax.
@@ -1149,8 +1148,7 @@ pub struct Resolver<'a, 'tcx> {
legacy_const_generic_args: FxHashMap>>,
/// Amount of lifetime parameters for each item in the crate.
item_generics_num_lifetimes: FxHashMap,
- /// Amount of parameters for each function in the crate.
- fn_parameter_counts: LocalDefIdMap,
+ delegation_fn_sigs: LocalDefIdMap,
main_def: Option,
trait_impls: FxIndexMap>,
@@ -1399,7 +1397,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
prelude: None,
extern_prelude,
- has_self: Default::default(),
field_def_ids: Default::default(),
field_visibility_spans: FxHashMap::default(),
@@ -1508,7 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_resolutions: Default::default(),
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
- fn_parameter_counts: Default::default(),
+ delegation_fn_sigs: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1621,8 +1618,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
trait_map: self.trait_map,
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
- has_self: self.has_self,
- fn_parameter_counts: self.fn_parameter_counts,
+ delegation_fn_sigs: self.delegation_fn_sigs,
};
ResolverOutputs { global_ctxt, ast_lowering }
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8abf42e2c1392..99591b5e1440b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -192,6 +192,7 @@ symbols! {
Duration,
Encodable,
Encoder,
+ Enumerate,
Eq,
Equal,
Err,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 837b784f2725a..e50edfdc656ce 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -50,22 +50,38 @@ pub struct FindExprBySpan<'hir> {
pub span: Span,
pub result: Option<&'hir hir::Expr<'hir>>,
pub ty_result: Option<&'hir hir::Ty<'hir>>,
+ pub include_closures: bool,
+ pub tcx: TyCtxt<'hir>,
}
impl<'hir> FindExprBySpan<'hir> {
- pub fn new(span: Span) -> Self {
- Self { span, result: None, ty_result: None }
+ pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
+ Self { span, result: None, ty_result: None, tcx, include_closures: false }
}
}
impl<'v> Visitor<'v> for FindExprBySpan<'v> {
+ type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
if self.span == ex.span {
self.result = Some(ex);
} else {
+ if let hir::ExprKind::Closure(..) = ex.kind
+ && self.include_closures
+ && let closure_header_sp = self.span.with_hi(ex.span.hi())
+ && closure_header_sp == ex.span
+ {
+ self.result = Some(ex);
+ }
hir::intravisit::walk_expr(self, ex);
}
}
+
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if self.span == ty.span {
self.ty_result = Some(ty);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 9d3caaa01abd7..cc879c42ce95b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -901,7 +901,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Remove all the desugaring and macro contexts.
span.remove_mark();
}
- let mut expr_finder = FindExprBySpan::new(span);
+ let mut expr_finder = FindExprBySpan::new(span, self.tcx);
let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
return;
};
@@ -1367,7 +1367,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return false;
};
let body = self.tcx.hir().body(body_id);
- let mut expr_finder = FindExprBySpan::new(span);
+ let mut expr_finder = FindExprBySpan::new(span, self.tcx);
expr_finder.visit_expr(body.value);
let Some(expr) = expr_finder.result else {
return false;
@@ -1469,7 +1469,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Remove all the hir desugaring contexts while maintaining the macro contexts.
span.remove_mark();
}
- let mut expr_finder = super::FindExprBySpan::new(span);
+ let mut expr_finder = super::FindExprBySpan::new(span, self.tcx);
let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
return false;
};
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 0e309689680ad..1971136e54c72 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -2457,7 +2457,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let Some(body_id) =
self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
{
- let mut expr_finder = FindExprBySpan::new(span);
+ let mut expr_finder = FindExprBySpan::new(span, self.tcx);
expr_finder.visit_expr(self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index ef46040f0a703..7adbabf69e490 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -15,6 +15,7 @@ use crate::ops::Try;
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Enumerate")]
pub struct Enumerate {
iter: I,
count: usize,
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index b49585599cb32..ff41f6e77be7a 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -201,14 +201,21 @@ pub fn to_u16s>(s: S) -> crate::io::Result> {
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
-// The first callback, `f1`, is yielded a (pointer, len) pair which can be
+// The first callback, `f1`, is passed a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
-// The closure is expected to return what the syscall returns which will be
-// interpreted by this function to determine if the syscall needs to be invoked
-// again (with more buffer space).
+// The closure is expected to:
+// - On success, return the actual length of the written data *without* the null terminator.
+// This can be 0. In this case the last_error must be left unchanged.
+// - On insufficient buffer space,
+// - either return the required length *with* the null terminator,
+// - or set the last-error to ERROR_INSUFFICIENT_BUFFER and return `len`.
+// - On other failure, return 0 and set last_error.
+//
+// This is how most but not all syscalls indicate the required buffer space.
+// Other syscalls may need translation to match this protocol.
//
// Once the syscall has completed (errors bail out early) the second closure is
-// yielded the data which has been read from the syscall. The return value
+// passed the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result
where
diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs
index 374c9845ea4bb..64d8b72aed282 100644
--- a/library/std/src/sys/pal/windows/os.rs
+++ b/library/std/src/sys/pal/windows/os.rs
@@ -326,6 +326,8 @@ fn home_dir_crt() -> Option {
super::fill_utf16_buf(
|buf, mut sz| {
+ // GetUserProfileDirectoryW does not quite use the usual protocol for
+ // negotiating the buffer size, so we have to translate.
match c::GetUserProfileDirectoryW(
ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN),
buf,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 1dd639a89188b..a16e9c02e2e17 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3824,6 +3824,7 @@ impl<'test> TestCx<'test> {
.arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
.arg("--extern")
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
+ .arg("--edition=2021")
.arg(&self.testpaths.file.join("rmake.rs"))
.env("TARGET", &self.config.target)
.env("PYTHON", &self.config.python)
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 3ea35c7940c21..c385ef0f96753 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2021"
object = "0.34.0"
wasmparser = "0.118.2"
regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
+gimli = "0.28.1"
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index e723e824ed6c8..aeb7417fa69c7 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -14,6 +14,7 @@ use std::env;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
+pub use gimli;
pub use object;
pub use regex;
pub use wasmparser;
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index f0ed0ae806fd8..139bbe55e9e16 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -238,7 +238,6 @@ run-make/relocation-model/Makefile
run-make/relro-levels/Makefile
run-make/remap-path-prefix-dwarf/Makefile
run-make/remap-path-prefix/Makefile
-run-make/repr128-dwarf/Makefile
run-make/reproducible-build-2/Makefile
run-make/reproducible-build/Makefile
run-make/resolve-rename/Makefile
diff --git a/tests/run-make/repr128-dwarf/Makefile b/tests/run-make/repr128-dwarf/Makefile
deleted file mode 100644
index 3f933042724a3..0000000000000
--- a/tests/run-make/repr128-dwarf/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# ignore-windows
-# This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit
-# enums.
-
-include ../tools.mk
-
-all:
- $(RUSTC) -Cdebuginfo=2 lib.rs -o $(TMPDIR)/repr128.rlib
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128A $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128B $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128C $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128D $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128A $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128B $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128C $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 )"
- "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128D $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7f )"
diff --git a/tests/run-make/repr128-dwarf/lib.rs b/tests/run-make/repr128-dwarf/main.rs
similarity index 89%
rename from tests/run-make/repr128-dwarf/lib.rs
rename to tests/run-make/repr128-dwarf/main.rs
index 63675441d4bab..57923a8386db9 100644
--- a/tests/run-make/repr128-dwarf/lib.rs
+++ b/tests/run-make/repr128-dwarf/main.rs
@@ -1,4 +1,3 @@
-#![crate_type = "lib"]
#![feature(repr128)]
// Use .to_le() to ensure that the bytes are in the same order on both little- and big-endian
@@ -21,3 +20,7 @@ pub enum I128Enum {
}
pub fn f(_: U128Enum, _: I128Enum) {}
+
+fn main() {
+ f(U128Enum::U128A, I128Enum::I128A);
+}
diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs
new file mode 100644
index 0000000000000..90c4b4edcb86c
--- /dev/null
+++ b/tests/run-make/repr128-dwarf/rmake.rs
@@ -0,0 +1,67 @@
+//@ ignore-windows
+// This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit enums.
+
+extern crate run_make_support;
+
+use gimli::{AttributeValue, Dwarf, EndianRcSlice, Reader, RunTimeEndian};
+use object::{Object, ObjectSection};
+use run_make_support::{gimli, object, rustc, tmp_dir};
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+fn main() {
+ let output = tmp_dir().join("repr128");
+ dbg!(&output);
+ rustc().input("main.rs").arg("-o").arg(&output).arg("-Cdebuginfo=2").run();
+ let output = std::fs::read(output).unwrap();
+ let obj = object::File::parse(output.as_slice()).unwrap();
+ let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big };
+ let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> {
+ let data = obj.section_by_name(section.name()).map(|s| s.uncompressed_data().unwrap());
+ Ok(EndianRcSlice::new(Rc::from(data.unwrap_or_default().as_ref()), endian))
+ })
+ .unwrap();
+ let mut iter = dwarf.units();
+ let mut still_to_find = HashMap::from([
+ ("U128A", 0_u128),
+ ("U128B", 1_u128),
+ ("U128C", u64::MAX as u128 + 1),
+ ("U128D", u128::MAX),
+ ("I128A", 0_i128 as u128),
+ ("I128B", (-1_i128) as u128),
+ ("I128C", i128::MIN as u128),
+ ("I128D", i128::MAX as u128),
+ ]);
+ while let Some(header) = iter.next().unwrap() {
+ let unit = dwarf.unit(header).unwrap();
+ let mut cursor = unit.entries();
+ while let Some((_, entry)) = cursor.next_dfs().unwrap() {
+ if entry.tag() == gimli::constants::DW_TAG_enumerator {
+ let name = dwarf
+ .attr_string(
+ &unit,
+ entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(),
+ )
+ .unwrap();
+ let name = name.to_string().unwrap();
+ if let Some(expected) = still_to_find.remove(name.as_ref()) {
+ match entry.attr(gimli::constants::DW_AT_const_value).unwrap().unwrap().value()
+ {
+ AttributeValue::Block(value) => {
+ assert_eq!(
+ value.to_slice().unwrap(),
+ expected.to_le_bytes().as_slice(),
+ "{name}"
+ );
+ }
+ value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"),
+ }
+ }
+ }
+ }
+ }
+ if !still_to_find.is_empty() {
+ panic!("Didn't find debug entries for {still_to_find:?}");
+ }
+}
diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr
index fb0e63c207a54..8d40e6905e07f 100644
--- a/tests/ui/associated-types/issue-25700.stderr
+++ b/tests/ui/associated-types/issue-25700.stderr
@@ -12,7 +12,10 @@ note: if `S<()>` implemented `Clone`, you could clone the value
--> $DIR/issue-25700.rs:1:1
|
LL | struct S(#[allow(dead_code)] Option<&'static T>);
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(t);
+ | - you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs
new file mode 100644
index 0000000000000..7f95fa7ebbece
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs
@@ -0,0 +1,8 @@
+//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"]
+fn main() {
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs
new file mode 100644
index 0000000000000..d96e8b8ef8436
--- /dev/null
+++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs
@@ -0,0 +1,8 @@
+//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"]
+fn main() {
+ sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
index db3407a7d55fc..694fa460e9bb4 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
+++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
@@ -1,14 +1,29 @@
+//@ ignore-cross-compile because aux-bin does not yet support it
+//@ only-unix because SIGPIPE is a unix thing
+//@ aux-bin: assert-inherit-sig_dfl.rs
+//@ aux-bin: assert-inherit-sig_ign.rs
//@ run-pass
-//@ aux-build:sigpipe-utils.rs
-#![feature(unix_sigpipe)]
+#![feature(rustc_private, unix_sigpipe)]
-#[unix_sigpipe = "inherit"]
+extern crate libc;
+
+// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec:ing child
+// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See
+// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384
+#[unix_sigpipe = "sig_dfl"]
fn main() {
- extern crate sigpipe_utils;
+ // First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"].
+ assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl");
+
+ // With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN.
+ unsafe {
+ libc::signal(libc::SIGPIPE, libc::SIG_IGN);
+ }
+ assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_ign");
+}
- // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored,
- // instead the default handler shall be installed. (We assume that the
- // process that runs these tests have the default handler.)
- sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+fn assert_inherit_sigpipe_disposition(aux_bin: &str) {
+ let mut cmd = std::process::Command::new(aux_bin);
+ assert!(cmd.status().unwrap().success());
}
diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
index dcf1c02bceefa..4c1de72798c45 100644
--- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
+++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
@@ -23,6 +23,13 @@ LL | fn copy(x: T) -> (T, T) { (x, x) }
| | value moved here
| move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/typeck-auto-trait-no-supertraits-2.rs:8:9
+ |
+LL | fn copy(x: T) -> (T, T) { (x, x) }
+ | ^ - you could clone this value
+ | |
+ | consider constraining this type parameter with `Clone`
help: consider further restricting this bound
|
LL | fn copy(x: T) -> (T, T) { (x, x) }
diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr
index 6fbbb55437eb2..1b59216b3c76c 100644
--- a/tests/ui/binop/binop-consume-args.stderr
+++ b/tests/ui/binop/binop-consume-args.stderr
@@ -8,6 +8,13 @@ LL | lhs + rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:5:8
+ |
+LL | fn add, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs + rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -26,6 +33,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:5:30
+ |
+LL | fn add, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs + rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn add, B: Copy>(lhs: A, rhs: B) {
@@ -41,6 +55,13 @@ LL | lhs - rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:11:8
+ |
+LL | fn sub, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs - rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -59,6 +80,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:11:30
+ |
+LL | fn sub, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs - rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn sub, B: Copy>(lhs: A, rhs: B) {
@@ -74,6 +102,13 @@ LL | lhs * rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:17:8
+ |
+LL | fn mul, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs * rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -92,6 +127,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:17:30
+ |
+LL | fn mul, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs * rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn mul, B: Copy>(lhs: A, rhs: B) {
@@ -107,6 +149,13 @@ LL | lhs / rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:23:8
+ |
+LL | fn div, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs / rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -125,6 +174,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:23:30
+ |
+LL | fn div, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs / rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn div, B: Copy>(lhs: A, rhs: B) {
@@ -140,6 +196,13 @@ LL | lhs % rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:29:8
+ |
+LL | fn rem, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs % rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -158,6 +221,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:29:30
+ |
+LL | fn rem, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs % rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn rem, B: Copy>(lhs: A, rhs: B) {
@@ -173,6 +243,13 @@ LL | lhs & rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:35:11
+ |
+LL | fn bitand, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs & rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
help: consider further restricting this bound
@@ -191,6 +268,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:35:36
+ |
+LL | fn bitand, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs & rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn bitand, B: Copy>(lhs: A, rhs: B) {
@@ -206,6 +290,13 @@ LL | lhs | rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:41:10
+ |
+LL | fn bitor, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs | rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
help: consider further restricting this bound
@@ -224,6 +315,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:41:34
+ |
+LL | fn bitor, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs | rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn bitor, B: Copy>(lhs: A, rhs: B) {
@@ -239,6 +337,13 @@ LL | lhs ^ rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:47:11
+ |
+LL | fn bitxor, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs ^ rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
help: consider further restricting this bound
@@ -257,6 +362,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:47:36
+ |
+LL | fn bitxor, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs ^ rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn bitxor, B: Copy>(lhs: A, rhs: B) {
@@ -272,6 +384,13 @@ LL | lhs << rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:53:8
+ |
+LL | fn shl, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs << rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
help: consider further restricting this bound
@@ -290,6 +409,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:53:30
+ |
+LL | fn shl, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs << rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn shl, B: Copy>(lhs: A, rhs: B) {
@@ -305,6 +431,13 @@ LL | lhs >> rhs;
LL | drop(lhs);
| ^^^ value used here after move
|
+help: if `A` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:59:8
+ |
+LL | fn shr, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs >> rhs;
+ | --- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
help: consider further restricting this bound
@@ -323,6 +456,13 @@ LL | drop(lhs);
LL | drop(rhs);
| ^^^ value used here after move
|
+help: if `B` implemented `Clone`, you could clone the value
+ --> $DIR/binop-consume-args.rs:59:30
+ |
+LL | fn shr, B>(lhs: A, rhs: B) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | lhs >> rhs;
+ | --- you could clone this value
help: consider restricting type parameter `B`
|
LL | fn shr, B: Copy>(lhs: A, rhs: B) {
diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr
index 1dd8c9a87d472..83c27590e9014 100644
--- a/tests/ui/binop/binop-move-semantics.stderr
+++ b/tests/ui/binop/binop-move-semantics.stderr
@@ -11,6 +11,13 @@ LL | | x;
| |_____value used here after move
| `x` moved due to usage in operator
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/binop-move-semantics.rs:5:16
+ |
+LL | fn double_move>(x: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | x
+ | - you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting this bound
@@ -51,6 +58,14 @@ LL | x
...
LL | use_mut(n); use_imm(m);
| - borrow later used here
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/binop-move-semantics.rs:17:18
+ |
+LL | fn move_borrowed>(x: T, mut y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let m = &x;
+ | -- you could clone this value
error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/binop-move-semantics.rs:23:5
@@ -65,6 +80,15 @@ LL | y;
| ^ move out of `y` occurs here
LL | use_mut(n); use_imm(m);
| - borrow later used here
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/binop-move-semantics.rs:17:18
+ |
+LL | fn move_borrowed>(x: T, mut y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let m = &x;
+LL | let n = &mut y;
+ | ------ you could clone this value
error[E0507]: cannot move out of `*m` which is behind a mutable reference
--> $DIR/binop-move-semantics.rs:30:5
@@ -80,12 +104,29 @@ LL | | *n;
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/binop-move-semantics.rs:26:24
+ |
+LL | fn illegal_dereference>(mut x: T, y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | *m
+ | -- you could clone this value
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> $DIR/binop-move-semantics.rs:32:5
|
LL | *n;
| ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/binop-move-semantics.rs:26:24
+ |
+LL | fn illegal_dereference>(mut x: T, y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | *n;
+ | -- you could clone this value
error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable
--> $DIR/binop-move-semantics.rs:54:5
diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr
index 01647011207f4..9915acfe06537 100644
--- a/tests/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr
@@ -11,6 +11,12 @@ LL | let _h = to_fn_once(move || -> isize { *bar });
| | variable moved due to use in closure
| | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait
| `bar` is moved here
+ |
+help: clone the value before moving it into the closure
+ |
+LL ~ let value = bar.clone();
+LL ~ let _h = to_fn_once(move || -> isize { value });
+ |
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
index 86bddacbdc727..b4b60d40d9143 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/borrowck-move-out-of-static-item.rs:3:1
|
LL | struct Foo {
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | test(BAR);
+ | --- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
index 4d9477f85811d..cc6c3bdeb1022 100644
--- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
@@ -14,7 +14,10 @@ note: if `S` implemented `Clone`, you could clone the value
--> $DIR/borrowck-move-subcomponent.rs:6:1
|
LL | struct S {
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let pb = &a;
+ | -- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr
index 1602058c183fc..c3b7b0b6080c6 100644
--- a/tests/ui/borrowck/borrowck-overloaded-call.stderr
+++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr
@@ -34,7 +34,10 @@ note: if `SFnOnce` implemented `Clone`, you could clone the value
--> $DIR/borrowck-overloaded-call.rs:41:1
|
LL | struct SFnOnce {
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | s(" world".to_string());
+ | - you could clone this value
error: aborting due to 3 previous errors
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index f0eaf4bac7dfa..19f040556f8ae 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -32,6 +32,13 @@ LL |
LL | println!("{b}");
| --- borrow later used here
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/clone-on-ref.rs:11:8
+ |
+LL | fn bar(x: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let a = &x;
+ | -- you could clone this value
help: consider further restricting this bound
|
LL | fn bar(x: T) {
@@ -56,7 +63,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/clone-on-ref.rs:19:1
|
LL | struct A;
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+LL | fn qux(x: A) {
+LL | let a = &x;
+ | -- you could clone this value
help: consider annotating `A` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr
index b4775496f4f48..a894fa63ace28 100644
--- a/tests/ui/borrowck/issue-101119.stderr
+++ b/tests/ui/borrowck/issue-101119.stderr
@@ -22,7 +22,10 @@ note: if `State` implemented `Clone`, you could clone the value
--> $DIR/issue-101119.rs:1:1
|
LL | struct State;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | fill_segment(state);
+ | ----- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
index 94421c35c65d2..603055beadcef 100644
--- a/tests/ui/borrowck/issue-103624.stderr
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -13,8 +13,11 @@ LL | self.b;
note: if `StructB` implemented `Clone`, you could clone the value
--> $DIR/issue-103624.rs:23:1
|
+LL | self.b;
+ | ------ you could clone this value
+...
LL | struct StructB {}
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
error[E0521]: borrowed data escapes outside of method
--> $DIR/issue-103624.rs:14:9
diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
index 701f00d079d38..dde17d1f6523c 100644
--- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
+++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
@@ -15,7 +15,10 @@ note: if `Example` implemented `Clone`, you could clone the value
--> $DIR/issue-119915-bad-clone-suggestion.rs:3:1
|
LL | struct Example(PhantomData<(fn(E), fn(FakeParam))>);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | unsafe { self.change() }
+ | ---- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr
index e2c3a9d5a2663..057ac6d7e3df9 100644
--- a/tests/ui/borrowck/issue-17718-static-move.stderr
+++ b/tests/ui/borrowck/issue-17718-static-move.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/issue-17718-static-move.rs:1:1
|
LL | struct Foo;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _a = FOO;
+ | --- you could clone this value
help: consider borrowing here
|
LL | let _a = &FOO;
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
index 1da6f0bef0234..20a4bd4e42378 100644
--- a/tests/ui/borrowck/issue-20801.stderr
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -23,7 +23,10 @@ note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = unsafe { *mut_ref() };
+ | ---------- you could clone this value
help: consider removing the dereference here
|
LL - let a = unsafe { *mut_ref() };
@@ -40,7 +43,10 @@ note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let b = unsafe { *imm_ref() };
+ | ---------- you could clone this value
help: consider removing the dereference here
|
LL - let b = unsafe { *imm_ref() };
@@ -57,7 +63,10 @@ note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let c = unsafe { *mut_ptr() };
+ | ---------- you could clone this value
help: consider removing the dereference here
|
LL - let c = unsafe { *mut_ptr() };
@@ -74,7 +83,10 @@ note: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-20801.rs:3:1
|
LL | struct T(u8);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let d = unsafe { *const_ptr() };
+ | ------------ you could clone this value
help: consider removing the dereference here
|
LL - let d = unsafe { *const_ptr() };
diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr
index 43f4e820857a0..1e9b1d5209cb6 100644
--- a/tests/ui/borrowck/move-error-in-promoted-2.stderr
+++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr
@@ -11,7 +11,10 @@ note: if `S` implemented `Clone`, you could clone the value
--> $DIR/move-error-in-promoted-2.rs:3:1
|
LL | struct S;
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | &([S][0],);
+ | ------ you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr
index 40b64398aef6a..97d140515184a 100644
--- a/tests/ui/borrowck/move-error-snippets.stderr
+++ b/tests/ui/borrowck/move-error-snippets.stderr
@@ -13,7 +13,12 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-error-snippets.rs:9:1
|
LL | struct A;
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+ |
+ ::: $DIR/move-error-snippets-ext.rs:5:17
+ |
+LL | let a = $c;
+ | -- you could clone this value
= 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
|
diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
index a4e70b506462d..009e85a8031ee 100644
--- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
+++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-in-static-initializer-issue-38520.rs:5:1
|
LL | struct Foo(usize);
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | static Y: usize = get(*&X);
+ | --- you could clone this value
error[E0507]: cannot move out of a shared reference
--> $DIR/move-in-static-initializer-issue-38520.rs:13:22
@@ -20,7 +23,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-in-static-initializer-issue-38520.rs:5:1
|
LL | struct Foo(usize);
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | const Z: usize = get(*&X);
+ | --- you could clone this value
error: aborting due to 2 previous errors
diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr
index 53ff5f0107df3..bdaa9449f913e 100644
--- a/tests/ui/box/leak-alloc.stderr
+++ b/tests/ui/box/leak-alloc.stderr
@@ -16,7 +16,10 @@ note: if `Alloc` implemented `Clone`, you could clone the value
--> $DIR/leak-alloc.rs:8:1
|
LL | struct Alloc {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let boxed = Box::new_in(10, alloc.by_ref());
+ | ----- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/coroutine/borrowing.stderr b/tests/ui/coroutine/borrowing.stderr
index acd4cdafdfdf7..22e331c6923d6 100644
--- a/tests/ui/coroutine/borrowing.stderr
+++ b/tests/ui/coroutine/borrowing.stderr
@@ -4,6 +4,7 @@ error[E0597]: `a` does not live long enough
LL | let _b = {
| -- borrow later stored here
LL | let a = 3;
+ | - binding `a` declared here
LL | Pin::new(&mut || yield &a).resume(())
| -- ^ borrowed value does not live long enough
| |
@@ -18,6 +19,7 @@ error[E0597]: `a` does not live long enough
LL | let _b = {
| -- borrow later stored here
LL | let a = 3;
+ | - binding `a` declared here
LL | || {
| -- value captured here by coroutine
LL | yield &a
diff --git a/tests/ui/coroutine/dropck.stderr b/tests/ui/coroutine/dropck.stderr
index 241d6dfe0a169..1148b9eed718b 100644
--- a/tests/ui/coroutine/dropck.stderr
+++ b/tests/ui/coroutine/dropck.stderr
@@ -18,6 +18,9 @@ LL | }
error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:15:18
|
+LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
+ | ---- binding `ref_` declared here
+...
LL | gen = || {
| -- value captured here by coroutine
LL | // but the coroutine can use it to drop a `Ref<'a, i32>`.
diff --git a/tests/ui/delegation/auxiliary/fn-header-aux.rs b/tests/ui/delegation/auxiliary/fn-header-aux.rs
new file mode 100644
index 0000000000000..d26209a4f789f
--- /dev/null
+++ b/tests/ui/delegation/auxiliary/fn-header-aux.rs
@@ -0,0 +1,9 @@
+//@ edition:2018
+
+#![feature(c_variadic)]
+
+pub unsafe fn unsafe_fn_extern() {}
+pub extern "C" fn extern_fn_extern() {}
+pub unsafe extern "C" fn variadic_fn_extern(n: usize, mut args: ...) {}
+pub const fn const_fn_extern() {}
+pub async fn async_fn_extern() {}
diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs
new file mode 100644
index 0000000000000..db20e1058e061
--- /dev/null
+++ b/tests/ui/delegation/fn-header.rs
@@ -0,0 +1,57 @@
+//@ check-pass
+//@ edition:2018
+//@ aux-crate:fn_header_aux=fn-header-aux.rs
+
+#![feature(c_variadic)]
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+#![deny(unused_unsafe)]
+
+mod to_reuse {
+ pub unsafe fn unsafe_fn() {}
+ pub extern "C" fn extern_fn() {}
+ pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
+ pub const fn const_fn() {}
+ pub async fn async_fn() {}
+}
+
+reuse to_reuse::unsafe_fn;
+reuse to_reuse::extern_fn;
+reuse to_reuse::variadic_fn;
+reuse to_reuse::const_fn;
+reuse to_reuse::async_fn;
+
+reuse fn_header_aux::unsafe_fn_extern;
+reuse fn_header_aux::extern_fn_extern;
+reuse fn_header_aux::variadic_fn_extern;
+reuse fn_header_aux::const_fn_extern;
+reuse fn_header_aux::async_fn_extern;
+
+const fn const_check() {
+ const_fn();
+ const_fn_extern();
+}
+
+async fn async_check() {
+ async_fn().await;
+ async_fn_extern().await;
+}
+
+fn main() {
+ unsafe {
+ unsafe_fn();
+ unsafe_fn_extern();
+ }
+ extern_fn();
+ extern_fn_extern();
+ let _: extern "C" fn() = extern_fn;
+ let _: extern "C" fn() = extern_fn_extern;
+ unsafe {
+ variadic_fn(0);
+ variadic_fn(0, 1);
+ variadic_fn_extern(0);
+ variadic_fn_extern(0, 1);
+ }
+ let _: unsafe extern "C" fn(usize, ...) = variadic_fn;
+ let _: unsafe extern "C" fn(usize, ...) = variadic_fn_extern;
+}
diff --git a/tests/ui/delegation/impl-trait.rs b/tests/ui/delegation/impl-trait.rs
new file mode 100644
index 0000000000000..13df0155485c9
--- /dev/null
+++ b/tests/ui/delegation/impl-trait.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+ pub fn foo() -> impl Clone { 0 }
+}
+
+reuse to_reuse::foo;
+
+trait Trait {
+ fn bar() -> impl Clone { 1 }
+}
+
+struct S;
+impl Trait for S {}
+
+impl S {
+ reuse to_reuse::foo;
+ reuse ::bar;
+}
+
+fn main() {
+ foo().clone();
+ ::bar().clone();
+}
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
index 9dccb12b57adb..5f78de97638b5 100644
--- a/tests/ui/delegation/not-supported.rs
+++ b/tests/ui/delegation/not-supported.rs
@@ -14,9 +14,9 @@ mod generics {
fn foo3<'a: 'a>(_: &'a u32) {}
reuse GenericTrait::bar;
- //~^ delegation with early bound generics is not supported yet
+ //~^ ERROR delegation with early bound generics is not supported yet
reuse GenericTrait::bar1;
- //~^ delegation with early bound generics is not supported yet
+ //~^ ERROR delegation with early bound generics is not supported yet
}
struct F;
@@ -73,26 +73,18 @@ mod opaque {
}
reuse to_reuse::opaque_arg;
//~^ ERROR delegation with early bound generics is not supported yet
- reuse to_reuse::opaque_ret;
- //~^ ERROR delegation to a function with opaque type is not supported yet
-}
-mod fn_header {
- mod to_reuse {
- pub unsafe fn unsafe_fn() {}
- pub extern "C" fn extern_fn() {}
- pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
- pub const fn const_fn() {}
+ trait ToReuse {
+ fn opaque_ret() -> impl Trait { unimplemented!() }
}
- reuse to_reuse::unsafe_fn;
- //~^ ERROR delegation to unsafe functions is not supported yet
- reuse to_reuse::extern_fn;
- //~^ ERROR delegation to non Rust ABI functions is not supported yet
- reuse to_reuse::variadic_fn;
- //~^ ERROR delegation to variadic functions is not supported yet
- reuse to_reuse::const_fn;
- //~^ ERROR delegation to const functions is not supported yet
+ // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls.
+ impl ToReuse for u8 {
+ reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type
+ }
+ impl ToReuse for u16 {
+ reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type
+ }
}
mod recursive {
diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr
index f6c49366899c1..e2cb04f977b1e 100644
--- a/tests/ui/delegation/not-supported.stderr
+++ b/tests/ui/delegation/not-supported.stderr
@@ -115,53 +115,46 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
LL | reuse to_reuse::opaque_arg;
| ^^^^^^^^^^
-error: delegation to a function with opaque type is not supported yet
- --> $DIR/not-supported.rs:76:21
+error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}`
+ --> $DIR/not-supported.rs:83:25
|
-LL | pub fn opaque_ret() -> impl Trait { unimplemented!() }
- | --------------------------------- callee defined here
-...
-LL | reuse to_reuse::opaque_ret;
- | ^^^^^^^^^^
-
-error: delegation to unsafe functions is not supported yet
- --> $DIR/not-supported.rs:88:21
+LL | reuse to_reuse::opaque_ret;
+ | ^^^^^^^^^^
|
-LL | pub unsafe fn unsafe_fn() {}
- | ------------------------- callee defined here
-...
-LL | reuse to_reuse::unsafe_fn;
- | ^^^^^^^^^
-
-error: delegation to non Rust ABI functions is not supported yet
- --> $DIR/not-supported.rs:90:21
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+ --> $DIR/not-supported.rs:83:25
|
-LL | pub extern "C" fn extern_fn() {}
- | ----------------------------- callee defined here
-...
-LL | reuse to_reuse::extern_fn;
- | ^^^^^^^^^
-
-error: delegation to variadic functions is not supported yet
- --> $DIR/not-supported.rs:92:21
+LL | reuse to_reuse::opaque_ret;
+ | ^^^^^^^^^^
+ = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::` is well-formed
+ --> $DIR/not-supported.rs:82:5
|
-LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
- | ------------------------------------------------------------- callee defined here
-...
-LL | reuse to_reuse::variadic_fn;
- | ^^^^^^^^^^^
+LL | impl ToReuse for u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-error: delegation to const functions is not supported yet
- --> $DIR/not-supported.rs:94:21
+error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}`
+ --> $DIR/not-supported.rs:86:24
|
-LL | pub const fn const_fn() {}
- | ----------------------- callee defined here
-...
-LL | reuse to_reuse::const_fn;
- | ^^^^^^^^
+LL | reuse ToReuse::opaque_ret;
+ | ^^^^^^^^^^
+ |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+ --> $DIR/not-supported.rs:86:24
+ |
+LL | reuse ToReuse::opaque_ret;
+ | ^^^^^^^^^^
+ = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::` is well-formed
+ --> $DIR/not-supported.rs:85:5
+ |
+LL | impl ToReuse for u16 {
+ | ^^^^^^^^^^^^^^^^^^^^
+ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: recursive delegation is not supported yet
- --> $DIR/not-supported.rs:107:22
+ --> $DIR/not-supported.rs:99:22
|
LL | pub reuse to_reuse2::foo;
| --- callee defined here
@@ -169,7 +162,7 @@ LL | pub reuse to_reuse2::foo;
LL | reuse to_reuse1::foo;
| ^^^
-error: aborting due to 19 previous errors
+error: aborting due to 16 previous errors
-Some errors have detailed explanations: E0049, E0195.
+Some errors have detailed explanations: E0049, E0195, E0391.
For more information about an error, try `rustc --explain E0049`.
diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs
new file mode 100644
index 0000000000000..f4b3da76c56c7
--- /dev/null
+++ b/tests/ui/delegation/rename.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod to_reuse {
+ pub fn a() {}
+}
+
+reuse to_reuse::a as b;
+
+struct S;
+impl S {
+ reuse to_reuse::a as b;
+}
+
+fn main() {
+ b();
+ S::b();
+}
diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr
index 26ac532263fd0..a8523d25cab9b 100644
--- a/tests/ui/derives/deriving-with-repr-packed.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed.stderr
@@ -40,7 +40,10 @@ note: if `Y` implemented `Clone`, you could clone the value
--> $DIR/deriving-with-repr-packed.rs:16:1
|
LL | struct Y(usize);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | struct X(Y);
+ | - you could clone this value
= 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)
diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr
index 900cb706bd97c..343bca9a72e24 100644
--- a/tests/ui/error-codes/E0504.stderr
+++ b/tests/ui/error-codes/E0504.stderr
@@ -18,7 +18,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value
--> $DIR/E0504.rs:1:1
|
LL | struct FancyNum {
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let fancy_ref = &fancy_num;
+ | ---------- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr
index ce01298a70d90..266df9ea32a71 100644
--- a/tests/ui/error-codes/E0505.stderr
+++ b/tests/ui/error-codes/E0505.stderr
@@ -15,7 +15,10 @@ note: if `Value` implemented `Clone`, you could clone the value
--> $DIR/E0505.rs:1:1
|
LL | struct Value {}
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _ref_to_val: &Value = &x;
+ | -- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr
index 60a4daa9d382e..70d99ea2cce5c 100644
--- a/tests/ui/error-codes/E0507.stderr
+++ b/tests/ui/error-codes/E0507.stderr
@@ -15,7 +15,10 @@ note: if `TheDarkKnight` implemented `Clone`, you could clone the value
--> $DIR/E0507.rs:3:1
|
LL | struct TheDarkKnight;
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | x.borrow().nothing_is_true();
+ | ---------- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr
index 96d3bcb67a57f..fcfac399e0df5 100644
--- a/tests/ui/error-codes/E0508-fail.stderr
+++ b/tests/ui/error-codes/E0508-fail.stderr
@@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/E0508-fail.rs:1:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _value = array[0];
+ | -------- you could clone this value
help: consider borrowing here
|
LL | let _value = &array[0];
diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr
index c1b622e243213..b9fa0f4d17a5f 100644
--- a/tests/ui/error-codes/E0508.stderr
+++ b/tests/ui/error-codes/E0508.stderr
@@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/E0508.rs:1:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _value = array[0];
+ | -------- you could clone this value
help: consider borrowing here
|
LL | let _value = &array[0];
diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr
index 75c372d044019..628a253e08593 100644
--- a/tests/ui/error-codes/E0509.stderr
+++ b/tests/ui/error-codes/E0509.stderr
@@ -11,7 +11,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value
--> $DIR/E0509.rs:1:1
|
LL | struct FancyNum {
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let fancy_field = drop_struct.fancy;
+ | ----------------- you could clone this value
help: consider borrowing here
|
LL | let fancy_field = &drop_struct.fancy;
diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs
index 81f2027286791..30e25ca8edccd 100644
--- a/tests/ui/fn/suggest-return-closure.rs
+++ b/tests/ui/fn/suggest-return-closure.rs
@@ -18,6 +18,7 @@ fn fn_mut() -> _ {
//~| NOTE for more information on `Fn` traits and closure types
let x = String::new();
//~^ HELP: consider changing this to be mutable
+ //~| NOTE binding `x` declared here
|c| { //~ NOTE: value captured here
x.push(c);
//~^ ERROR: does not live long enough
diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr
index 8e80a11fe1b08..d276ce8be2ba5 100644
--- a/tests/ui/fn/suggest-return-closure.stderr
+++ b/tests/ui/fn/suggest-return-closure.stderr
@@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ {
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/suggest-return-closure.rs:31:13
+ --> $DIR/suggest-return-closure.rs:32:13
|
LL | fn fun() -> _ {
| ^
@@ -32,7 +32,7 @@ LL | fn fun() -> _ {
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/suggest-return-closure.rs:22:9
+ --> $DIR/suggest-return-closure.rs:23:9
|
LL | let x = String::new();
| - help: consider changing this to be mutable: `mut x`
@@ -41,8 +41,11 @@ LL | x.push(c);
| ^ cannot borrow as mutable
error[E0597]: `x` does not live long enough
- --> $DIR/suggest-return-closure.rs:22:9
+ --> $DIR/suggest-return-closure.rs:23:9
|
+LL | let x = String::new();
+ | - binding `x` declared here
+...
LL | |c| {
| --- value captured here
LL | x.push(c);
diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr
index 988db0fb1fc4b..3c451a859e94c 100644
--- a/tests/ui/issues/issue-17385.stderr
+++ b/tests/ui/issues/issue-17385.stderr
@@ -12,7 +12,10 @@ note: if `X` implemented `Clone`, you could clone the value
--> $DIR/issue-17385.rs:1:1
|
LL | struct X(isize);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(foo);
+ | --- you could clone this value
error[E0382]: use of moved value: `e`
--> $DIR/issue-17385.rs:25:11
@@ -28,7 +31,10 @@ note: if `Enum` implemented `Clone`, you could clone the value
--> $DIR/issue-17385.rs:3:1
|
LL | enum Enum {
- | ^^^^^^^^^
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | drop(e);
+ | - you could clone this value
error: aborting due to 2 previous errors
diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs
index d1a9e37251ee7..63c061594d87e 100644
--- a/tests/ui/issues/issue-24357.rs
+++ b/tests/ui/issues/issue-24357.rs
@@ -1,10 +1,12 @@
struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value
+//~^ NOTE consider implementing `Clone` for this type
fn main() {
let x = NoCopy;
//~^ NOTE move occurs because `x` has type `NoCopy`
let f = move || { let y = x; };
//~^ NOTE value moved into closure here
//~| NOTE variable moved due to use in closure
+ //~| NOTE you could clone this value
let z = x;
//~^ ERROR use of moved value: `x`
//~| NOTE value used here after move
diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr
index 6d50eea7e21a0..2d85077fe4c21 100644
--- a/tests/ui/issues/issue-24357.stderr
+++ b/tests/ui/issues/issue-24357.stderr
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `x`
- --> $DIR/issue-24357.rs:8:12
+ --> $DIR/issue-24357.rs:10:12
|
LL | let x = NoCopy;
| - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
@@ -16,7 +16,10 @@ note: if `NoCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-24357.rs:1:1
|
LL | struct NoCopy;
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let f = move || { let y = x; };
+ | - you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr
index 8b4aff54dc3c0..14b5cfa9f9ac4 100644
--- a/tests/ui/issues/issue-4335.stderr
+++ b/tests/ui/issues/issue-4335.stderr
@@ -7,6 +7,14 @@ LL | id(Box::new(|| *v))
| -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
| |
| captured by this `FnMut` closure
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/issue-4335.rs:5:10
+ |
+LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> {
+ | ^ consider constraining this type parameter with `Clone`
+LL | id(Box::new(|| *v))
+ | -- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr
index 838eaffb5a0dc..162d7ac031a67 100644
--- a/tests/ui/mir/issue-102389.stderr
+++ b/tests/ui/mir/issue-102389.stderr
@@ -8,7 +8,10 @@ note: if `Enum` implemented `Clone`, you could clone the value
--> $DIR/issue-102389.rs:1:1
|
LL | enum Enum { A, B, C }
- | ^^^^^^^^^
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | array[*inbounds as usize]
+ | --------- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/moves/borrow-closures-instead-of-move.rs b/tests/ui/moves/borrow-closures-instead-of-move.rs
index 51771ced7f22f..e4bca54e995fa 100644
--- a/tests/ui/moves/borrow-closures-instead-of-move.rs
+++ b/tests/ui/moves/borrow-closures-instead-of-move.rs
@@ -1,4 +1,4 @@
-fn takes_fn(f: impl Fn()) {
+fn takes_fn(f: impl Fn()) { //~ HELP if `impl Fn()` implemented `Clone`
loop {
takes_fnonce(f);
//~^ ERROR use of moved value
@@ -6,7 +6,7 @@ fn takes_fn(f: impl Fn()) {
}
}
-fn takes_fn_mut(m: impl FnMut()) {
+fn takes_fn_mut(m: impl FnMut()) { //~ HELP if `impl FnMut()` implemented `Clone`
if maybe() {
takes_fnonce(m);
//~^ HELP consider mutably borrowing
diff --git a/tests/ui/moves/borrow-closures-instead-of-move.stderr b/tests/ui/moves/borrow-closures-instead-of-move.stderr
index 9a84ddef7e64e..ab6ff417efb60 100644
--- a/tests/ui/moves/borrow-closures-instead-of-move.stderr
+++ b/tests/ui/moves/borrow-closures-instead-of-move.stderr
@@ -15,6 +15,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {}
| ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value
| |
| in this function
+help: if `impl Fn()` implemented `Clone`, you could clone the value
+ --> $DIR/borrow-closures-instead-of-move.rs:1:16
+ |
+LL | fn takes_fn(f: impl Fn()) {
+ | ^^^^^^^^^ consider constraining this type parameter with `Clone`
+LL | loop {
+LL | takes_fnonce(f);
+ | - you could clone this value
help: consider borrowing `f`
|
LL | takes_fnonce(&f);
@@ -39,6 +47,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {}
| ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value
| |
| in this function
+help: if `impl FnMut()` implemented `Clone`, you could clone the value
+ --> $DIR/borrow-closures-instead-of-move.rs:9:20
+ |
+LL | fn takes_fn_mut(m: impl FnMut()) {
+ | ^^^^^^^^^^^^ consider constraining this type parameter with `Clone`
+LL | if maybe() {
+LL | takes_fnonce(m);
+ | - you could clone this value
help: consider mutably borrowing `m`
|
LL | takes_fnonce(&mut m);
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs
index 86f389cb3af1e..8f2e01bdf1aba 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs
@@ -7,6 +7,10 @@ struct NonCopy;
//~| NOTE if `NonCopy` implemented `Clone`
//~| NOTE if `NonCopy` implemented `Clone`
//~| NOTE if `NonCopy` implemented `Clone`
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
fn good() {
loop {
@@ -21,6 +25,7 @@ fn moved_here_1() {
//~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
let _used = value;
//~^ NOTE value moved here
+ //~| NOTE you could clone this value
let _used2 = value; //~ ERROR use of moved value: `value`
//~^ NOTE value used here after move
}
@@ -32,6 +37,7 @@ fn moved_here_2() {
loop { //~ NOTE inside of this loop
let _used = value;
//~^ NOTE value moved here
+ //~| NOTE you could clone this value
loop {
let _used2 = value; //~ ERROR use of moved value: `value`
//~^ NOTE value used here after move
@@ -45,6 +51,7 @@ fn moved_loop_1() {
loop { //~ NOTE inside of this loop
let _used = value; //~ ERROR use of moved value: `value`
//~^ NOTE value moved here, in previous iteration of loop
+ //~| NOTE you could clone this value
}
}
@@ -56,6 +63,7 @@ fn moved_loop_2() {
loop { //~ NOTE inside of this loop
let _used2 = value; //~ ERROR use of moved value: `value`
//~^ NOTE value moved here, in previous iteration of loop
+ //~| NOTE you could clone this value
}
}
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
index a613f35a35e0a..3a93769ac4549 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -1,12 +1,12 @@
error[E0382]: use of moved value: `value`
- --> $DIR/issue-72649-uninit-in-loop.rs:24:22
+ --> $DIR/issue-72649-uninit-in-loop.rs:29:22
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
LL |
LL | let _used = value;
| ----- value moved here
-LL |
+...
LL | let _used2 = value;
| ^^^^^ value used here after move
|
@@ -14,10 +14,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _used = value;
+ | ----- you could clone this value
error[E0382]: use of moved value: `value`
- --> $DIR/issue-72649-uninit-in-loop.rs:36:26
+ --> $DIR/issue-72649-uninit-in-loop.rs:42:26
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -34,10 +37,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _used = value;
+ | ----- you could clone this value
error[E0382]: use of moved value: `value`
- --> $DIR/issue-72649-uninit-in-loop.rs:46:21
+ --> $DIR/issue-72649-uninit-in-loop.rs:52:21
|
LL | let value = NonCopy{};
| ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -51,10 +57,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _used = value;
+ | ----- you could clone this value
error[E0382]: use of moved value: `value`
- --> $DIR/issue-72649-uninit-in-loop.rs:57:22
+ --> $DIR/issue-72649-uninit-in-loop.rs:64:22
|
LL | let mut value = NonCopy{};
| --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -68,10 +77,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-72649-uninit-in-loop.rs:5:1
|
LL | struct NonCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let _used2 = value;
+ | ----- you could clone this value
error[E0381]: used binding `value` isn't initialized
- --> $DIR/issue-72649-uninit-in-loop.rs:65:21
+ --> $DIR/issue-72649-uninit-in-loop.rs:73:21
|
LL | let value: NonCopy;
| ----- binding declared here but left uninitialized
@@ -84,7 +96,7 @@ LL | let value: NonCopy = /* value */;
| +++++++++++++
error[E0381]: used binding `value` isn't initialized
- --> $DIR/issue-72649-uninit-in-loop.rs:73:21
+ --> $DIR/issue-72649-uninit-in-loop.rs:81:21
|
LL | let mut value: NonCopy;
| --------- binding declared here but left uninitialized
diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr
index b6ad906bbdb09..815e91b0f4df2 100644
--- a/tests/ui/moves/issue-75904-move-closure-loop.stderr
+++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr
@@ -15,7 +15,10 @@ note: if `NotCopy` implemented `Clone`, you could clone the value
--> $DIR/issue-75904-move-closure-loop.rs:5:1
|
LL | struct NotCopy;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | a;
+ | - you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr
index e6bf52276ac2f..f2c6008d27eac 100644
--- a/tests/ui/moves/move-fn-self-receiver.stderr
+++ b/tests/ui/moves/move-fn-self-receiver.stderr
@@ -106,7 +106,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-fn-self-receiver.rs:5:1
|
LL | struct Foo;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let ret = mut_foo.use_mut_self();
+ | ------- you could clone this value
error[E0382]: use of moved value: `rc_foo`
--> $DIR/move-fn-self-receiver.rs:55:5
@@ -142,7 +145,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/move-fn-self-receiver.rs:5:1
|
LL | struct Foo;
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | foo_add + Foo;
+ | ------- you could clone this value
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr
index 9e4a08e0cef54..8a030f0219207 100644
--- a/tests/ui/moves/move-out-of-array-1.stderr
+++ b/tests/ui/moves/move-out-of-array-1.stderr
@@ -11,7 +11,10 @@ note: if `D` implemented `Clone`, you could clone the value
--> $DIR/move-out-of-array-1.rs:5:1
|
LL | struct D { _x: u8 }
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | a[i]
+ | ---- you could clone this value
error: aborting due to 1 previous error
diff --git a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
index 4759b45892cc4..a8473bb81983d 100644
--- a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
+++ b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
@@ -17,6 +17,13 @@ LL | let mut r = R {c: Box::new(f)};
LL | f(&mut r, false)
| ^ value borrowed here after move
|
+help: if `F` implemented `Clone`, you could clone the value
+ --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:30:16
+ |
+LL | fn conspirator(mut f: F) where F: FnMut(&mut R, bool) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let mut r = R {c: Box::new(f)};
+ | - you could clone this value
help: consider mutably borrowing `f`
|
LL | let mut r = R {c: Box::new(&mut f)};
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
index e726c8145c3ba..bfb855c7fb1f4 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
@@ -3,6 +3,7 @@
fn duplicate_t(t: T) -> (T, T) {
//~^ HELP consider restricting type parameter `T`
+ //~| HELP if `T` implemented `Clone`, you could clone the value
(t, t) //~ use of moved value: `t`
}
@@ -72,10 +73,11 @@ where
#[rustfmt::skip]
fn existing_colon(t: T) {
//~^ HELP consider restricting type parameter `T`
+ //~| HELP if `T` implemented `Clone`, you could clone the value
[t, t]; //~ use of moved value: `t`
}
-fn existing_colon_in_where(t: T)
+fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value
where
T:, T: Copy
//~^ HELP consider further restricting type parameter `T`
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
index ee08ce0fa5ba4..fbe5a1d74c372 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
@@ -3,6 +3,7 @@
fn duplicate_t(t: T) -> (T, T) {
//~^ HELP consider restricting type parameter `T`
+ //~| HELP if `T` implemented `Clone`, you could clone the value
(t, t) //~ use of moved value: `t`
}
@@ -72,10 +73,11 @@ where
#[rustfmt::skip]
fn existing_colon(t: T) {
//~^ HELP consider restricting type parameter `T`
+ //~| HELP if `T` implemented `Clone`, you could clone the value
[t, t]; //~ use of moved value: `t`
}
-fn existing_colon_in_where(t: T)
+fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value
where
T:,
//~^ HELP consider further restricting type parameter `T`
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
index 3e37fcb2141fc..c03204c7b9f10 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -1,21 +1,29 @@
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:7:9
|
LL | fn duplicate_t(t: T) -> (T, T) {
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-LL |
+...
LL | (t, t)
| - ^ value used here after move
| |
| value moved here
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:4:16
+ |
+LL | fn duplicate_t(t: T) -> (T, T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | (t, t)
+ | - you could clone this value
help: consider restricting type parameter `T`
|
LL | fn duplicate_t(t: T) -> (T, T) {
| ++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:12:9
|
LL | fn duplicate_opt(t: Option) -> (Option, Option) {
| - move occurs because `t` has type `Option`, which does not implement the `Copy` trait
@@ -31,7 +39,7 @@ LL | fn duplicate_opt(t: Option) -> (Option, Option) {
| ++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:17:9
|
LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) {
| - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait
@@ -47,7 +55,7 @@ LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) {
| ++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:22:9
|
LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) {
| - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait
@@ -63,7 +71,7 @@ LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) {
| ++++++ ++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:27:9
|
LL | fn duplicate_custom(t: S) -> (S, S) {
| - move occurs because `t` has type `S`, which does not implement the `Copy` trait
@@ -79,7 +87,7 @@ LL | fn duplicate_custom(t: S) -> (S, S) {
| ++++++++++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:45:9
|
LL | fn duplicate_custom_1(t: S) -> (S, S) where {
| - move occurs because `t` has type `S`, which does not implement the `Copy` trait
@@ -95,7 +103,7 @@ LL | fn duplicate_custom_1(t: S) -> (S, S) where {
| ++++++++++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:53:9
|
LL | fn duplicate_custom_2(t: S) -> (S, S)
| - move occurs because `t` has type `S`, which does not implement the `Copy` trait
@@ -111,7 +119,7 @@ LL | T: A + Copy + Trait,
| ++++++++++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:62:9
|
LL | fn duplicate_custom_3(t: S) -> (S, S)
| - move occurs because `t` has type `S`, which does not implement the `Copy` trait
@@ -127,7 +135,7 @@ LL | T: A + Copy + Trait,
| ++++++++++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:70:9
|
LL | fn duplicate_custom_4(t: S) -> (S, S)
| - move occurs because `t` has type `S`, which does not implement the `Copy` trait
@@ -143,23 +151,31 @@ LL | fn duplicate_custom_4(t: S) -> (S, S)
| ++++++++++++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:77:9
|
LL | fn existing_colon(t: T) {
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-LL |
+...
LL | [t, t];
| - ^ value used here after move
| |
| value moved here
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:74:19
+ |
+LL | fn existing_colon(t: T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | [t, t];
+ | - you could clone this value
help: consider restricting type parameter `T`
|
LL | fn existing_colon(t: T) {
| ++++
error[E0382]: use of moved value: `t`
- --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:85:9
|
LL | fn existing_colon_in_where(t: T)
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
@@ -169,6 +185,14 @@ LL | [t, t];
| |
| value moved here
|
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/use_of_moved_value_copy_suggestions.rs:80:28
+ |
+LL | fn existing_colon_in_where(t: T)
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | [t, t];
+ | - you could clone this value
help: consider further restricting type parameter `T`
|
LL | T:, T: Copy
diff --git a/tests/ui/nll/closure-borrow-spans.stderr b/tests/ui/nll/closure-borrow-spans.stderr
index cac22c2ecda49..c466cad25d2e5 100644
--- a/tests/ui/nll/closure-borrow-spans.stderr
+++ b/tests/ui/nll/closure-borrow-spans.stderr
@@ -25,6 +25,8 @@ LL | f.use_ref();
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:19:16
|
+LL | let x = 1;
+ | - binding `x` declared here
LL | f = || x;
| -- ^ borrowed value does not live long enough
| |
@@ -85,6 +87,8 @@ LL | f.use_ref();
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:52:16
|
+LL | let mut x = 1;
+ | ----- binding `x` declared here
LL | f = || x = 0;
| -- ^ borrowed value does not live long enough
| |
@@ -145,6 +149,8 @@ LL | f.use_ref();
error[E0597]: `x` does not live long enough
--> $DIR/closure-borrow-spans.rs:86:16
|
+LL | let x = &mut z;
+ | - binding `x` declared here
LL | f = || *x = 0;
| -- ^^ borrowed value does not live long enough
| |
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
index aa73e91cc77e5..8e47ab780f210 100644
--- a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -37,6 +37,9 @@ LL | fn test() {
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-nested.rs:21:40
|
+LL | let y = 22;
+ | - binding `y` declared here
+LL |
LL | let mut closure = || {
| -- value captured here
LL | let mut closure1 = || p = &y;
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
index 949dcc78703a7..c428150aa2f4c 100644
--- a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -23,6 +23,8 @@ LL | fn test() {
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-ref.rs:23:35
|
+LL | let y = 22;
+ | - binding `y` declared here
LL | let mut closure = || p = &y;
| -- ^ borrowed value does not live long enough
| |
diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
index 81b5f09b04157..15f48d88c379b 100644
--- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
@@ -1,6 +1,8 @@
error[E0597]: `local_arr` does not live long enough
--> $DIR/propagate-multiple-requirements.rs:15:14
|
+LL | let local_arr = other_local_arr;
+ | --------- binding `local_arr` declared here
LL | let mut out: &mut &'static [i32] = &mut (&[1] as _);
| ------------------- type annotation requires that `local_arr` is borrowed for `'static`
LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| {
diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
index 2aff375f0a77c..496a298a36ce9 100644
--- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -32,7 +32,10 @@ note: if `S>` implemented `Clone`, you could clone the value
--> $DIR/issue-21232-partial-init-and-use.rs:15:1
|
LL | struct S {
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let mut s: S = S::new(); drop(s);
+ | - you could clone this value
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-21232-partial-init-and-use.rs:116:5
@@ -83,7 +86,10 @@ note: if `S>` implemented `Clone`, you could clone the value
--> $DIR/issue-21232-partial-init-and-use.rs:15:1
|
LL | struct S {
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let mut s: S = S::new(); drop(s);
+ | - you could clone this value
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-21232-partial-init-and-use.rs:142:5
diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed
new file mode 100644
index 0000000000000..7692be7ccc801
--- /dev/null
+++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed
@@ -0,0 +1,23 @@
+// Issue 27282: Example 1: This sidesteps the AST checks disallowing
+// mutable borrows in match guards by hiding the mutable borrow in a
+// guard behind a move (of the ref mut pattern id) within a closure.
+//@ run-rustfix
+#![feature(if_let_guard)]
+
+fn main() {
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
+}
diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs
index 833ca8afd618e..f3d0a184e03c5 100644
--- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs
+++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs
@@ -1,14 +1,14 @@
// Issue 27282: Example 1: This sidesteps the AST checks disallowing
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the ref mut pattern id) within a closure.
-
+//@ run-rustfix
#![feature(if_let_guard)]
fn main() {
match Some(&4) {
None => {},
ref mut foo
- if { (|| { let bar = foo; bar.take() })(); false } => {},
+ if { (|| { let mut bar = foo; bar.take() })(); false } => {},
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}
@@ -16,7 +16,7 @@ fn main() {
match Some(&4) {
None => {},
ref mut foo
- if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {},
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}
diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
index 4a512560c8751..7781e77894b89 100644
--- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
+++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
@@ -1,22 +1,30 @@
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
-LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
- | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {},
+ | ++++++++
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
|
-LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
- | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+LL | if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {},
+ | ++++++++
error: aborting due to 2 previous errors
diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.stderr b/tests/ui/nll/issue-27282-mutation-in-guard.stderr
index 0b5d723172c76..f73e4aaa489aa 100644
--- a/tests/ui/nll/issue-27282-mutation-in-guard.stderr
+++ b/tests/ui/nll/issue-27282-mutation-in-guard.stderr
@@ -7,6 +7,10 @@ LL | (|| { let bar = foo; bar.take() })();
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | (|| { let bar = foo.clone(); bar.take() })();
+ | ++++++++
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-mutation-in-guard.rs:20:18
@@ -17,6 +21,10 @@ LL | (|| { let bar = foo; bar.take() })();
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | (|| { let bar = foo.clone(); bar.take() })();
+ | ++++++++
error: aborting due to 2 previous errors
diff --git a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr
index f7a525ee9b046..e3f44467550cd 100644
--- a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr
+++ b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr
@@ -11,6 +11,8 @@ LL | || doit(data);
error[E0597]: `data` does not live long enough
--> $DIR/issue-42574-diagnostic-in-nested-closure.rs:6:13
|
+LL | fn doit(data: &'static mut ()) {
+ | ---- binding `data` declared here
LL | || doit(data);
| -- -----^^^^-
| | | |
diff --git a/tests/ui/nll/match-guards-always-borrow.fixed b/tests/ui/nll/match-guards-always-borrow.fixed
new file mode 100644
index 0000000000000..56e743bf196a6
--- /dev/null
+++ b/tests/ui/nll/match-guards-always-borrow.fixed
@@ -0,0 +1,66 @@
+#![feature(if_let_guard)]
+#![allow(unused_mut)]
+//@ run-rustfix
+
+// Here is arielb1's basic example from rust-lang/rust#27282
+// that AST borrowck is flummoxed by:
+
+fn should_reject_destructive_mutate_in_guard() {
+ match Some(&4) {
+ None => {},
+ ref mut foo if {
+ (|| { let mut bar = foo.clone(); bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ false } => { },
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(()) = {
+ (|| { let mut bar = foo.clone(); bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ None } => { },
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+// Here below is a case that needs to keep working: we only use the
+// binding via immutable-borrow in the guard, and we mutate in the arm
+// body.
+fn allow_mutate_in_arm_body() {
+ match Some(&4) {
+ None => {},
+ ref mut foo if foo.is_some() => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(_) = foo => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+// Here below is a case that needs to keep working: we only use the
+// binding via immutable-borrow in the guard, and we move into the arm
+// body.
+fn allow_move_into_arm_body() {
+ match Some(&4) {
+ None => {},
+ mut foo if foo.is_some() => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ mut foo if let Some(_) = foo => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+}
+
+fn main() {
+ should_reject_destructive_mutate_in_guard();
+ allow_mutate_in_arm_body();
+ allow_move_into_arm_body();
+}
diff --git a/tests/ui/nll/match-guards-always-borrow.rs b/tests/ui/nll/match-guards-always-borrow.rs
index ff63cc092734a..927d55c42a6e3 100644
--- a/tests/ui/nll/match-guards-always-borrow.rs
+++ b/tests/ui/nll/match-guards-always-borrow.rs
@@ -1,4 +1,6 @@
#![feature(if_let_guard)]
+#![allow(unused_mut)]
+//@ run-rustfix
// Here is arielb1's basic example from rust-lang/rust#27282
// that AST borrowck is flummoxed by:
@@ -7,7 +9,7 @@ fn should_reject_destructive_mutate_in_guard() {
match Some(&4) {
None => {},
ref mut foo if {
- (|| { let bar = foo; bar.take() })();
+ (|| { let mut bar = foo; bar.take() })();
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
false } => { },
Some(s) => std::process::exit(*s),
@@ -16,7 +18,7 @@ fn should_reject_destructive_mutate_in_guard() {
match Some(&4) {
None => {},
ref mut foo if let Some(()) = {
- (|| { let bar = foo; bar.take() })();
+ (|| { let mut bar = foo; bar.take() })();
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
None } => { },
Some(s) => std::process::exit(*s),
diff --git a/tests/ui/nll/match-guards-always-borrow.stderr b/tests/ui/nll/match-guards-always-borrow.stderr
index afd853c403ee3..bb0c5bd4c9761 100644
--- a/tests/ui/nll/match-guards-always-borrow.stderr
+++ b/tests/ui/nll/match-guards-always-borrow.stderr
@@ -1,22 +1,30 @@
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/match-guards-always-borrow.rs:10:14
+ --> $DIR/match-guards-always-borrow.rs:12:14
|
-LL | (|| { let bar = foo; bar.take() })();
- | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+LL | (|| { let mut bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | (|| { let mut bar = foo.clone(); bar.take() })();
+ | ++++++++
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/match-guards-always-borrow.rs:19:14
+ --> $DIR/match-guards-always-borrow.rs:21:14
|
-LL | (|| { let bar = foo; bar.take() })();
- | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+LL | (|| { let mut bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | (|| { let mut bar = foo.clone(); bar.take() })();
+ | ++++++++
error: aborting due to 2 previous errors
diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr
index 842ecaf524b47..d138412137959 100644
--- a/tests/ui/nll/move-errors.stderr
+++ b/tests/ui/nll/move-errors.stderr
@@ -8,7 +8,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let b = *a;
+ | -- you could clone this value
help: consider removing the dereference here
|
LL - let b = *a;
@@ -28,7 +31,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let b = a[0];
+ | ---- you could clone this value
help: consider borrowing here
|
LL | let b = &a[0];
@@ -44,7 +50,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let s = **r;
+ | --- you could clone this value
help: consider removing the dereference here
|
LL - let s = **r;
@@ -61,7 +70,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let s = *r;
+ | -- you could clone this value
help: consider removing the dereference here
|
LL - let s = *r;
@@ -81,7 +93,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = [A("".to_string())][0];
+ | ---------------------- you could clone this value
help: consider borrowing here
|
LL | let a = &[A("".to_string())][0];
@@ -126,7 +141,10 @@ note: if `A` implemented `Clone`, you could clone the value
--> $DIR/move-errors.rs:1:1
|
LL | struct A(String);
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | b = *a;
+ | -- you could clone this value
error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
--> $DIR/move-errors.rs:74:11
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
index 5227ca8ec17d8..1d086c658dfcd 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
@@ -1,6 +1,8 @@
error[E0597]: `a` does not live long enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
|
+LL | let a = ();
+ | - binding `a` declared here
LL | let b = |_| &a;
| --- -^
| | ||
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
index 5227ca8ec17d8..1d086c658dfcd 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
@@ -1,6 +1,8 @@
error[E0597]: `a` does not live long enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
|
+LL | let a = ();
+ | - binding `a` declared here
LL | let b = |_| &a;
| --- -^
| | ||
diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr
index c7c08c948abdb..c42ea0172cf75 100644
--- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr
+++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr
@@ -33,7 +33,9 @@ error[E0597]: `a` does not live long enough
|
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
| -- lifetime `'a` defined here
-...
+LL | let a = 22;
+ | - binding `a` declared here
+LL | let b = 44;
LL | let _closure = || {
| -- value captured here
LL | let c = 66;
diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr
index b7861a3bd069f..287337c7d52d3 100644
--- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr
+++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr
@@ -34,7 +34,9 @@ error[E0597]: `b` does not live long enough
|
LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
| -- lifetime `'a` defined here
-...
+LL | let a = 22;
+LL | let b = 44;
+ | - binding `b` declared here
LL | let _closure = || {
| -- value captured here
LL | let c = 66;
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 00964cb8336ed..e925fe78f3393 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -337,7 +337,10 @@ note: if `U` implemented `Clone`, you could clone the value
--> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
|
LL | struct U;
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | - you could clone this value
error[E0507]: cannot move out of `b` in pattern guard
--> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
@@ -350,7 +353,10 @@ note: if `U` implemented `Clone`, you could clone the value
--> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
|
LL | struct U;
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | - you could clone this value
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0507]: cannot move out of `a` in pattern guard
diff --git a/tests/ui/regions/regions-addr-of-upvar-self.stderr b/tests/ui/regions/regions-addr-of-upvar-self.stderr
index c16a6f8585b69..3a028cc9e211c 100644
--- a/tests/ui/regions/regions-addr-of-upvar-self.stderr
+++ b/tests/ui/regions/regions-addr-of-upvar-self.stderr
@@ -20,6 +20,8 @@ LL | let p: &'static mut usize = &mut self.food;
error[E0597]: `self` does not live long enough
--> $DIR/regions-addr-of-upvar-self.rs:8:46
|
+LL | pub fn chase_cat(&mut self) {
+ | --------- binding `self` declared here
LL | let _f = || {
| -- value captured here
LL | let p: &'static mut usize = &mut self.food;
diff --git a/tests/ui/regions/regions-nested-fns-2.stderr b/tests/ui/regions/regions-nested-fns-2.stderr
index 254497639a179..02359fe1213d8 100644
--- a/tests/ui/regions/regions-nested-fns-2.stderr
+++ b/tests/ui/regions/regions-nested-fns-2.stderr
@@ -1,6 +1,9 @@
error[E0597]: `y` does not live long enough
--> $DIR/regions-nested-fns-2.rs:7:25
|
+LL | let y = 3;
+ | - binding `y` declared here
+LL | ignore(
LL | |z| {
| --- value captured here
LL | if false { &y } else { z }
diff --git a/tests/ui/regions/regions-nested-fns.stderr b/tests/ui/regions/regions-nested-fns.stderr
index ee43f9fa5724d..23b3f78dd4eb5 100644
--- a/tests/ui/regions/regions-nested-fns.stderr
+++ b/tests/ui/regions/regions-nested-fns.stderr
@@ -27,6 +27,9 @@ LL | }
error[E0597]: `y` does not live long enough
--> $DIR/regions-nested-fns.rs:10:15
|
+LL | let y = 3;
+ | - binding `y` declared here
+...
LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| {
| --- value captured here
LL | ay = x;
diff --git a/tests/ui/regions/regions-steal-closure.stderr b/tests/ui/regions/regions-steal-closure.stderr
index 9324eb892a67d..50068b32fa3a7 100644
--- a/tests/ui/regions/regions-steal-closure.stderr
+++ b/tests/ui/regions/regions-steal-closure.stderr
@@ -4,6 +4,7 @@ error[E0597]: `i` does not live long enough
LL | let mut cl_box = {
| ---------- borrow later stored here
LL | let mut i = 3;
+ | ----- binding `i` declared here
LL | box_it(Box::new(|| i += 1))
| -- ^ borrowed value does not live long enough
| |
diff --git a/tests/ui/span/send-is-not-static-ensures-scoping.stderr b/tests/ui/span/send-is-not-static-ensures-scoping.stderr
index bae0befcacaa7..c15547e84125b 100644
--- a/tests/ui/span/send-is-not-static-ensures-scoping.stderr
+++ b/tests/ui/span/send-is-not-static-ensures-scoping.stderr
@@ -16,6 +16,9 @@ error[E0597]: `y` does not live long enough
|
LL | let bad = {
| --- borrow later stored here
+LL | let x = 1;
+LL | let y = &x;
+ | - binding `y` declared here
...
LL | scoped(|| {
| -- value captured here
diff --git a/tests/ui/suggestions/option-content-move2.rs b/tests/ui/suggestions/option-content-move2.rs
index 88e8a5b7aeef0..b0104d9bafb79 100644
--- a/tests/ui/suggestions/option-content-move2.rs
+++ b/tests/ui/suggestions/option-content-move2.rs
@@ -1,8 +1,10 @@
struct NotCopyable;
+#[derive(Clone)]
+struct NotCopyableButCloneable;
fn func H, H: FnMut()>(_: F) {}
-fn parse() {
+fn foo() {
let mut var = None;
func(|| {
// Shouldn't suggest `move ||.as_ref()` here
@@ -12,5 +14,15 @@ fn parse() {
}
});
}
+fn bar() {
+ let mut var = None;
+ func(|| {
+ // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
+ move || {
+ //~^ ERROR: cannot move out of `var`
+ var = Some(NotCopyableButCloneable);
+ }
+ });
+}
fn main() {}
diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr
index 0297c031eccaf..be97cba17b900 100644
--- a/tests/ui/suggestions/option-content-move2.stderr
+++ b/tests/ui/suggestions/option-content-move2.stderr
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
- --> $DIR/option-content-move2.rs:9:9
+ --> $DIR/option-content-move2.rs:11:9
|
LL | let mut var = None;
| ------- captured outer variable
@@ -15,6 +15,23 @@ LL | var = Some(NotCopyable);
| variable moved due to use in closure
| move occurs because `var` has type `Option`, which does not implement the `Copy` trait
-error: aborting due to 1 previous error
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move2.rs:21:9
+ |
+LL | let mut var = None;
+ | ------- captured outer variable
+LL | func(|| {
+ | -- captured by this `FnMut` closure
+LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
+LL | move || {
+ | ^^^^^^^ `var` is moved here
+LL |
+LL | var = Some(NotCopyableButCloneable);
+ | ---
+ | |
+ | variable moved due to use in closure
+ | move occurs because `var` has type `Option`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/suggestions/option-content-move3.rs b/tests/ui/suggestions/option-content-move3.rs
new file mode 100644
index 0000000000000..a245309d97fdf
--- /dev/null
+++ b/tests/ui/suggestions/option-content-move3.rs
@@ -0,0 +1,30 @@
+#[derive(Debug)]
+struct NotCopyable;
+#[derive(Debug, Clone)]
+struct NotCopyableButCloneable;
+
+fn func H, H: FnMut()>(_: F) {}
+
+fn foo() {
+ let var = NotCopyable;
+ func(|| {
+ // Shouldn't suggest `move ||.as_ref()` here
+ move || { //~ ERROR cannot move out of `var`
+ let x = var; //~ ERROR cannot move out of `var`
+ println!("{x:?}");
+ }
+ });
+}
+
+fn bar() {
+ let var = NotCopyableButCloneable;
+ func(|| {
+ // Shouldn't suggest `move ||.as_ref()` here
+ move || { //~ ERROR cannot move out of `var`
+ let x = var; //~ ERROR cannot move out of `var`
+ println!("{x:?}");
+ }
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr
new file mode 100644
index 0000000000000..a20dcce1ee310
--- /dev/null
+++ b/tests/ui/suggestions/option-content-move3.stderr
@@ -0,0 +1,95 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move3.rs:13:21
+ |
+LL | let var = NotCopyable;
+ | --- captured outer variable
+...
+LL | move || {
+ | ------- captured by this `FnMut` closure
+LL | let x = var;
+ | ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+ |
+note: if `NotCopyable` implemented `Clone`, you could clone the value
+ --> $DIR/option-content-move3.rs:2:1
+ |
+LL | struct NotCopyable;
+ | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let x = var;
+ | --- you could clone this value
+help: consider borrowing here
+ |
+LL | let x = &var;
+ | +
+
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move3.rs:12:9
+ |
+LL | let var = NotCopyable;
+ | --- captured outer variable
+LL | func(|| {
+ | -- captured by this `FnMut` closure
+LL | // Shouldn't suggest `move ||.as_ref()` here
+LL | move || {
+ | ^^^^^^^ `var` is moved here
+LL | let x = var;
+ | ---
+ | |
+ | variable moved due to use in closure
+ | move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+ |
+note: if `NotCopyable` implemented `Clone`, you could clone the value
+ --> $DIR/option-content-move3.rs:2:1
+ |
+LL | struct NotCopyable;
+ | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let x = var;
+ | --- you could clone this value
+
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move3.rs:24:21
+ |
+LL | let var = NotCopyableButCloneable;
+ | --- captured outer variable
+...
+LL | move || {
+ | ------- captured by this `FnMut` closure
+LL | let x = var;
+ | ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let x = &var;
+ | +
+
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move3.rs:23:9
+ |
+LL | let var = NotCopyableButCloneable;
+ | --- captured outer variable
+LL | func(|| {
+ | -- captured by this `FnMut` closure
+LL | // Shouldn't suggest `move ||.as_ref()` here
+LL | move || {
+ | ^^^^^^^ `var` is moved here
+LL | let x = var;
+ | ---
+ | |
+ | variable moved due to use in closure
+ | move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
+ |
+help: clone the value before moving it into the closure
+ |
+LL ~ {
+LL + let value = var.clone();
+LL ~ move || {
+LL ~ let x = value;
+LL | println!("{x:?}");
+LL ~ }
+LL + }
+ |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr
index 23aa18d7156ac..fc6f610ddd4c2 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr
@@ -1,6 +1,9 @@
error[E0597]: `factorial` does not live long enough
--> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17
|
+LL | let mut factorial: Option u32>> = None;
+ | ------------- binding `factorial` declared here
+LL |
LL | let f = |x: u32| -> u32 {
| --------------- value captured here
LL | let g = factorial.as_ref().unwrap();
@@ -30,7 +33,9 @@ error[E0597]: `factorial` does not live long enough
--> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17
|
LL | let mut factorial: Option u32 + 'static>> = None;
- | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static`
+ | ------------- ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static`
+ | |
+ | binding `factorial` declared here
LL |
LL | let f = |x: u32| -> u32 {
| --------------- value captured here
diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr
index 782fa63280ed6..f8e9609cb1c5e 100644
--- a/tests/ui/union/union-borrow-move-parent-sibling.stderr
+++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr
@@ -54,7 +54,10 @@ note: if `MockVec` implemented `Clone`, you could clone the value
--> $DIR/union-borrow-move-parent-sibling.rs:25:1
|
LL | struct MockVec {
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let a = (u.x.0).0;
+ | --------- you could clone this value
help: consider borrowing here
|
LL | let a = &(u.x.0).0;
diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr
index 5ebb2716e5a06..d520fb00ea9d5 100644
--- a/tests/ui/union/union-move.stderr
+++ b/tests/ui/union/union-move.stderr
@@ -20,7 +20,10 @@ note: if `U1` implemented `Clone`, you could clone the value
--> $DIR/union-move.rs:9:1
|
LL | union U1 {
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- you could clone this value
error[E0382]: use of moved value: `x`
--> $DIR/union-move.rs:42:18
@@ -44,7 +47,10 @@ note: if `U1` implemented `Clone`, you could clone the value
--> $DIR/union-move.rs:9:1
|
LL | union U1 {
- | ^^^^^^^^
+ | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- you could clone this value
error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
--> $DIR/union-move.rs:49:18
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr
index 187dd66b2fe59..bc9b3ea990384 100644
--- a/tests/ui/unop-move-semantics.stderr
+++ b/tests/ui/unop-move-semantics.stderr
@@ -33,6 +33,14 @@ LL | !x;
...
LL | use_mut(n); use_imm(m);
| - borrow later used here
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/unop-move-semantics.rs:11:18
+ |
+LL | fn move_borrowed>(x: T, mut y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let m = &x;
+ | -- you could clone this value
error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/unop-move-semantics.rs:17:6
@@ -47,6 +55,15 @@ LL | !y;
| ^ move out of `y` occurs here
LL | use_mut(n); use_imm(m);
| - borrow later used here
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/unop-move-semantics.rs:11:18
+ |
+LL | fn move_borrowed>(x: T, mut y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+LL | let m = &x;
+LL | let n = &mut y;
+ | ------ you could clone this value
error[E0507]: cannot move out of `*m` which is behind a mutable reference
--> $DIR/unop-move-semantics.rs:24:6
@@ -59,6 +76,14 @@ LL | !*m;
|
note: calling this operator moves the value
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/unop-move-semantics.rs:20:24
+ |
+LL | fn illegal_dereference>(mut x: T, y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | !*m;
+ | -- you could clone this value
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> $DIR/unop-move-semantics.rs:26:6
@@ -68,6 +93,15 @@ LL | !*n;
| ||
| |move occurs because `*n` has type `T`, which does not implement the `Copy` trait
| `*n` moved due to usage in operator
+ |
+help: if `T` implemented `Clone`, you could clone the value
+ --> $DIR/unop-move-semantics.rs:20:24
+ |
+LL | fn illegal_dereference>(mut x: T, y: T) {
+ | ^ consider constraining this type parameter with `Clone`
+...
+LL | !*n;
+ | -- you could clone this value
error: aborting due to 5 previous errors
diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr
index 4515d313ec0a4..03cada07a9e3d 100644
--- a/tests/ui/variance/variance-issue-20533.stderr
+++ b/tests/ui/variance/variance-issue-20533.stderr
@@ -14,7 +14,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
--> $DIR/variance-issue-20533.rs:26:1
|
LL | struct AffineU32(u32);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let x = foo(&a);
+ | -- you could clone this value
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:41:14
@@ -32,7 +35,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
--> $DIR/variance-issue-20533.rs:26:1
|
LL | struct AffineU32(u32);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let x = bar(&a);
+ | -- you could clone this value
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:47:14
@@ -50,7 +56,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
--> $DIR/variance-issue-20533.rs:26:1
|
LL | struct AffineU32(u32);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | let x = baz(&a);
+ | -- you could clone this value
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:53:14