diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f6076896385a6..458c2f3885f94 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -531,6 +531,8 @@ pub enum BindingForm<'tcx> { Var(VarBindingForm<'tcx>), /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. ImplicitSelf, + /// Reference used in a guard expression to ensure immutability. + RefForGuard, } CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } @@ -555,6 +557,7 @@ mod binding_form_impl { match self { Var(binding) => binding.hash_stable(hcx, hasher), ImplicitSelf => (), + RefForGuard => (), } } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index c481d1d325b32..3dca7768d704e 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -202,7 +202,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// the local assigned at `location`. /// This is done by searching in statements succeeding `location` /// and originating from `maybe_closure_span`. - fn find_closure_span( + pub(super) fn find_closure_span( &self, maybe_closure_span: Span, location: Location, @@ -742,6 +742,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { autoderef, &including_downcast, )?; + } else if let Place::Local(local) = proj.base { + if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) + = self.mir.local_decls[local].is_user_variable { + self.append_place_to_string( + &proj.base, + buf, + autoderef, + &including_downcast, + )?; + } else { + buf.push_str(&"*"); + self.append_place_to_string( + &proj.base, + buf, + autoderef, + &including_downcast, + )?; + } } else { buf.push_str(&"*"); self.append_place_to_string( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index e7f00b577b39f..c212c1b826bd9 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -16,7 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; use rustc::infer::InferCtxt; use rustc::lint::builtin::UNUSED_MUT; -use rustc::mir::{self, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; +use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place}; use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; @@ -43,14 +43,13 @@ use dataflow::{do_dataflow, DebugFormatted}; use dataflow::{EverInitializedPlaces, MovingOutStatements}; use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use util::borrowck_errors::{BorrowckErrors, Origin}; -use util::collect_writes::FindAssignments; -use util::suggest_ref_mut; use self::borrow_set::{BorrowData, BorrowSet}; use self::flows::Flows; use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; +use self::mutability_errors::AccessKind; use self::path_utils::*; @@ -58,12 +57,13 @@ crate mod borrow_set; mod error_reporting; mod flows; mod location; +mod move_errors; +mod mutability_errors; mod path_utils; crate mod place_ext; mod places_conflict; mod prefixes; mod used_muts; -mod move_errors; pub(crate) mod nll; @@ -922,7 +922,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } let mutability_error = - self.check_access_permissions(place_span, rw, is_local_mutation_allowed, flow_state); + self.check_access_permissions( + place_span, + rw, + is_local_mutation_allowed, + flow_state, + context.loc, + ); let conflict_error = self.check_access_for_conflict(context, place_span, sd, rw, flow_state); @@ -1668,6 +1674,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } + /// Check the permissions for the given place and read or write kind /// /// Returns true if an error is reported, false otherwise. @@ -1677,17 +1684,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, flow_state: &Flows<'cx, 'gcx, 'tcx>, + location: Location, ) -> bool { debug!( "check_access_permissions({:?}, {:?}, {:?})", place, kind, is_local_mutation_allowed ); - #[derive(Copy, Clone, Debug)] - enum AccessKind { - MutableBorrow, - Mutate, - } let error_access; let the_place_err; @@ -1756,206 +1759,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } // at this point, we have set up the error reporting state. - - let mut err; - let item_msg = match self.describe_place(place) { - Some(name) => format!("immutable item `{}`", name), - None => "immutable item".to_owned(), - }; - - // `act` and `acted_on` are strings that let us abstract over - // the verbs used in some diagnostic messages. - let act; - let acted_on; - - match error_access { - AccessKind::Mutate => { - let item_msg = match the_place_err { - Place::Projection(box Projection { - base: _, - elem: ProjectionElem::Deref, - }) => match self.describe_place(place) { - Some(description) => { - format!("`{}` which is behind a `&` reference", description) - } - None => format!("data in a `&` reference"), - }, - _ => item_msg, - }; - err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); - act = "assign"; - acted_on = "written"; - } - AccessKind::MutableBorrow => { - err = self - .tcx - .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); - act = "borrow as mutable"; - acted_on = "borrowed as mutable"; - } - } - - match the_place_err { - // We want to suggest users use `let mut` for local (user - // variable) mutations... - Place::Local(local) if self.mir.local_decls[*local].can_be_made_mutable() => { - // ... but it doesn't make sense to suggest it on - // variables that are `ref x`, `ref mut x`, `&self`, - // or `&mut self` (such variables are simply not - // mutable).. - let local_decl = &self.mir.local_decls[*local]; - assert_eq!(local_decl.mutability, Mutability::Not); - - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_suggestion( - local_decl.source_info.span, - "consider changing this to be mutable", - format!("mut {}", local_decl.name.unwrap()), - ); - } - - // complete hack to approximate old AST-borrowck - // diagnostic: if the span starts with a mutable borrow of - // a local variable, then just suggest the user remove it. - Place::Local(_) - if { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - snippet.starts_with("&mut ") - } else { - false - } - } => - { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_label(span, "try removing `&mut` here"); - } - - // We want to point out when a `&` can be readily replaced - // with an `&mut`. - // - // FIXME: can this case be generalized to work for an - // arbitrary base for the projection? - Place::Projection(box Projection { - base: Place::Local(local), - elem: ProjectionElem::Deref, - }) if self.mir.local_decls[*local].is_user_variable.is_some() => { - let local_decl = &self.mir.local_decls[*local]; - let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { - ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => { - Some(suggest_ampmut_self(local_decl)) - }, - - ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - })) => Some(suggest_ampmut( - self.tcx, - self.mir, - *local, - local_decl, - *opt_ty_info, - )), - - ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - })) => suggest_ref_mut(self.tcx, local_decl.source_info.span), - - ClearCrossCrate::Clear => bug!("saw cleared local state"), - }; - - if let Some((err_help_span, suggested_code)) = suggestion { - err.span_suggestion( - err_help_span, - "consider changing this to be a mutable reference", - suggested_code, - ); - } - - if let Some(name) = local_decl.name { - err.span_label( - span, - format!( - "`{NAME}` is a `&` reference, \ - so the data it refers to cannot be {ACTED_ON}", - NAME = name, - ACTED_ON = acted_on - ), - ); - } else { - err.span_label( - span, - format!("cannot {ACT} through `&`-reference", ACT = act), - ); - } - } - - _ => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - } - } - - err.emit(); + self.report_mutability_error( + place, + span, + the_place_err, + error_access, + location, + ); return true; - - fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( - local_decl: &mir::LocalDecl<'tcx>, - ) -> (Span, String) { - (local_decl.source_info.span, "&mut self".to_string()) - } - - // When we want to suggest a user change a local variable to be a `&mut`, there - // are three potential "obvious" things to highlight: - // - // let ident [: Type] [= RightHandSideExpression]; - // ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ - // (1.) (2.) (3.) - // - // We can always fallback on highlighting the first. But chances are good that - // the user experience will be better if we highlight one of the others if possible; - // for example, if the RHS is present and the Type is not, then the type is going to - // be inferred *from* the RHS, which means we should highlight that (and suggest - // that they borrow the RHS mutably). - // - // This implementation attempts to emulate AST-borrowck prioritization - // by trying (3.), then (2.) and finally falling back on (1.). - fn suggest_ampmut<'cx, 'gcx, 'tcx>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - local: Local, - local_decl: &mir::LocalDecl<'tcx>, - opt_ty_info: Option, - ) -> (Span, String) { - let locations = mir.find_assignments(local); - if locations.len() > 0 { - let assignment_rhs_span = mir.source_info(locations[0]).span; - let snippet = tcx.sess.codemap().span_to_snippet(assignment_rhs_span); - if let Ok(src) = snippet { - if src.starts_with('&') { - let borrowed_expr = src[1..].to_string(); - return ( - assignment_rhs_span, - format!("&mut {}", borrowed_expr), - ); - } - } - } - - let highlight_span = match opt_ty_info { - // if this is a variable binding with an explicit type, - // try to highlight that for the suggestion. - Some(ty_span) => ty_span, - - // otherwise, just highlight the span associated with - // the (MIR) LocalDecl. - None => local_decl.source_info.span, - }; - - let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); - assert_eq!(ty_mut.mutbl, hir::MutImmutable); - (highlight_span, format!("&mut {}", ty_mut.ty)) - } } /// Adds the place into the used mutable variables set diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs new file mode 100644 index 0000000000000..2a074a84e63e5 --- /dev/null +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -0,0 +1,469 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir; +use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Mir}; +use rustc::mir::{Mutability, Place, Projection, ProjectionElem, Static}; +use rustc::ty::{self, TyCtxt}; +use rustc_data_structures::indexed_vec::Idx; +use syntax_pos::Span; + +use borrow_check::MirBorrowckCtxt; +use util::borrowck_errors::{BorrowckErrors, Origin}; +use util::collect_writes::FindAssignments; +use util::suggest_ref_mut; + +#[derive(Copy, Clone, Debug)] +pub(super) enum AccessKind { + MutableBorrow, + Mutate, +} + +impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { + pub(super) fn report_mutability_error( + &mut self, + access_place: &Place<'tcx>, + span: Span, + the_place_err: &Place<'tcx>, + error_access: AccessKind, + location: Location, + ) { + let mut err; + let item_msg; + let reason; + let access_place_desc = self.describe_place(access_place); + + match the_place_err { + Place::Local(local) => { + item_msg = format!("`{}`", access_place_desc.unwrap()); + if let Place::Local(_) = access_place { + reason = ", as it is not declared as mutable".to_string(); + } else { + let name = self.mir.local_decls[*local] + .name + .expect("immutable unnamed local"); + reason = format!(", as `{}` is not declared as mutable", name); + } + } + + Place::Projection(box Projection { + base, + elem: ProjectionElem::Field(upvar_index, _), + }) => { + debug_assert!(is_closure_or_generator( + base.ty(self.mir, self.tcx).to_ty(self.tcx) + )); + + item_msg = format!("`{}`", access_place_desc.unwrap()); + if self.is_upvar(access_place) { + reason = ", as it is not declared as mutable".to_string(); + } else { + let name = self.mir.upvar_decls[upvar_index.index()].debug_name; + reason = format!(", as `{}` is not declared as mutable", name); + } + } + + Place::Projection(box Projection { + base, + elem: ProjectionElem::Deref, + }) => { + if *base == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() { + item_msg = format!("`{}`", access_place_desc.unwrap()); + debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); + debug_assert!(is_closure_or_generator( + the_place_err.ty(self.mir, self.tcx).to_ty(self.tcx) + )); + + reason = if self.is_upvar(access_place) { + ", as it is a captured variable in a `Fn` closure".to_string() + } else { + format!(", as `Fn` closures cannot mutate their captured variables") + } + } else if { + if let Place::Local(local) = *base { + if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) + = self.mir.local_decls[local].is_user_variable { + true + } else { + false + } + } else { + false + } + } { + item_msg = format!("`{}`", access_place_desc.unwrap()); + reason = format!(", as it is immutable for the pattern guard"); + } else { + let pointer_type = + if base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + "`&` reference" + } else { + "`*const` pointer" + }; + if let Some(desc) = access_place_desc { + item_msg = format!("`{}`", desc); + reason = match error_access { + AccessKind::Mutate => format!(" which is behind a {}", pointer_type), + AccessKind::MutableBorrow => { + format!(", as it is behind a {}", pointer_type) + } + } + } else { + item_msg = format!("data in a {}", pointer_type); + reason = "".to_string(); + } + } + } + + Place::Static(box Static { def_id, ty: _ }) => { + if let Place::Static(_) = access_place { + item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); + reason = "".to_string(); + } else { + item_msg = format!("`{}`", access_place_desc.unwrap()); + let static_name = &self.tcx.item_name(*def_id); + reason = format!(", as `{}` is an immutable static item", static_name); + } + } + + Place::Projection(box Projection { + base: _, + elem: ProjectionElem::Index(_), + }) + | Place::Projection(box Projection { + base: _, + elem: ProjectionElem::ConstantIndex { .. }, + }) + | Place::Projection(box Projection { + base: _, + elem: ProjectionElem::Subslice { .. }, + }) + | Place::Projection(box Projection { + base: _, + elem: ProjectionElem::Downcast(..), + }) => bug!("Unexpected immutable place."), + } + + // `act` and `acted_on` are strings that let us abstract over + // the verbs used in some diagnostic messages. + let act; + let acted_on; + + + let span = match error_access { + AccessKind::Mutate => { + err = self.tcx + .cannot_assign(span, &(item_msg + &reason), Origin::Mir); + act = "assign"; + acted_on = "written"; + span + } + AccessKind::MutableBorrow => { + act = "borrow as mutable"; + acted_on = "borrowed as mutable"; + + let closure_span = self.find_closure_span(span, location); + if let Some((args, var)) = closure_span { + err = self.tcx.cannot_borrow_path_as_mutable_because( + args, + &item_msg, + &reason, + Origin::Mir, + ); + err.span_label( + var, + format!( + "mutable borrow occurs due to use of `{}` in closure", + self.describe_place(access_place).unwrap(), + ), + ); + args + } else { + err = self.tcx.cannot_borrow_path_as_mutable_because( + span, + &item_msg, + &reason, + Origin::Mir, + ); + span + } + } + }; + + match the_place_err { + // We want to suggest users use `let mut` for local (user + // variable) mutations... + Place::Local(local) if self.mir.local_decls[*local].can_be_made_mutable() => { + // ... but it doesn't make sense to suggest it on + // variables that are `ref x`, `ref mut x`, `&self`, + // or `&mut self` (such variables are simply not + // mutable). + let local_decl = &self.mir.local_decls[*local]; + assert_eq!(local_decl.mutability, Mutability::Not); + + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_suggestion( + local_decl.source_info.span, + "consider changing this to be mutable", + format!("mut {}", local_decl.name.unwrap()), + ); + } + + // Also suggest adding mut for upvars + Place::Projection(box Projection { + base, + elem: ProjectionElem::Field(upvar_index, _), + }) => { + debug_assert!(is_closure_or_generator( + base.ty(self.mir, self.tcx).to_ty(self.tcx) + )); + + err.span_label(span, format!("cannot {ACT}", ACT = act)); + + let upvar_hir_id = self.mir.upvar_decls[upvar_index.index()] + .var_hir_id + .assert_crate_local(); + let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id); + if let Some(hir::map::NodeBinding(pat)) = self.tcx.hir.find(upvar_node_id) { + if let hir::PatKind::Binding( + hir::BindingAnnotation::Unannotated, + _, + upvar_ident, + _, + ) = pat.node + { + err.span_suggestion( + upvar_ident.span, + "consider changing this to be mutable", + format!("mut {}", upvar_ident.name), + ); + } + } + } + + // complete hack to approximate old AST-borrowck + // diagnostic: if the span starts with a mutable borrow of + // a local variable, then just suggest the user remove it. + Place::Local(_) + if { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + snippet.starts_with("&mut ") + } else { + false + } + } => + { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, "try removing `&mut` here"); + } + + Place::Projection(box Projection { + base: Place::Local(local), + elem: ProjectionElem::Deref, + }) if { + if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = + self.mir.local_decls[*local].is_user_variable + { + true + } else { + false + } + } => + { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.note( + "variables bound in patterns are immutable until the end of the pattern guard", + ); + } + + // We want to point out when a `&` can be readily replaced + // with an `&mut`. + // + // FIXME: can this case be generalized to work for an + // arbitrary base for the projection? + Place::Projection(box Projection { + base: Place::Local(local), + elem: ProjectionElem::Deref, + }) if self.mir.local_decls[*local].is_user_variable.is_some() => + { + let local_decl = &self.mir.local_decls[*local]; + let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { + ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => { + Some(suggest_ampmut_self(local_decl)) + } + + ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + })) => Some(suggest_ampmut( + self.tcx, + self.mir, + *local, + local_decl, + *opt_ty_info, + )), + + ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + })) => suggest_ref_mut(self.tcx, local_decl.source_info.span), + + // + ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(), + + ClearCrossCrate::Clear => bug!("saw cleared local state"), + }; + + let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { + ("&", "reference") + } else { + ("*const", "pointer") + }; + + if let Some((err_help_span, suggested_code)) = suggestion { + err.span_suggestion( + err_help_span, + &format!("consider changing this to be a mutable {}", pointer_desc), + suggested_code, + ); + } + + if let Some(name) = local_decl.name { + err.span_label( + span, + format!( + "`{NAME}` is a `{SIGIL}` {DESC}, \ + so the data it refers to cannot be {ACTED_ON}", + NAME = name, + SIGIL = pointer_sigil, + DESC = pointer_desc, + ACTED_ON = acted_on + ), + ); + } else { + err.span_label( + span, + format!( + "cannot {ACT} through `{SIGIL}` {DESC}", + ACT = act, + SIGIL = pointer_sigil, + DESC = pointer_desc + ), + ); + } + } + + Place::Projection(box Projection { + base, + elem: ProjectionElem::Deref, + }) if *base == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() => + { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_help( + self.mir.span, + "consider changing this to accept closures that implement `FnMut`" + ); + } + + _ => { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + } + } + + err.emit(); + } + + // Does this place refer to what the user sees as an upvar + fn is_upvar(&self, place: &Place<'tcx>) -> bool { + match *place { + Place::Projection(box Projection { + ref base, + elem: ProjectionElem::Field(_, _), + }) => { + let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + is_closure_or_generator(base_ty) + } + Place::Projection(box Projection { + base: + Place::Projection(box Projection { + ref base, + elem: ProjectionElem::Field(upvar_index, _), + }), + elem: ProjectionElem::Deref, + }) => { + let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + is_closure_or_generator(base_ty) && self.mir.upvar_decls[upvar_index.index()].by_ref + } + _ => false, + } + } +} + +fn suggest_ampmut_self<'cx, 'gcx, 'tcx>(local_decl: &mir::LocalDecl<'tcx>) -> (Span, String) { + (local_decl.source_info.span, "&mut self".to_string()) +} + +// When we want to suggest a user change a local variable to be a `&mut`, there +// are three potential "obvious" things to highlight: +// +// let ident [: Type] [= RightHandSideExpression]; +// ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +// (1.) (2.) (3.) +// +// We can always fallback on highlighting the first. But chances are good that +// the user experience will be better if we highlight one of the others if possible; +// for example, if the RHS is present and the Type is not, then the type is going to +// be inferred *from* the RHS, which means we should highlight that (and suggest +// that they borrow the RHS mutably). +// +// This implementation attempts to emulate AST-borrowck prioritization +// by trying (3.), then (2.) and finally falling back on (1.). +fn suggest_ampmut<'cx, 'gcx, 'tcx>( + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + mir: &Mir<'tcx>, + local: Local, + local_decl: &mir::LocalDecl<'tcx>, + opt_ty_info: Option, +) -> (Span, String) { + let locations = mir.find_assignments(local); + if locations.len() > 0 { + let assignment_rhs_span = mir.source_info(locations[0]).span; + let snippet = tcx.sess.codemap().span_to_snippet(assignment_rhs_span); + if let Ok(src) = snippet { + if src.starts_with('&') { + let borrowed_expr = src[1..].to_string(); + return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); + } + } + } + + let highlight_span = match opt_ty_info { + // if this is a variable binding with an explicit type, + // try to highlight that for the suggestion. + Some(ty_span) => ty_span, + + // otherwise, just highlight the span associated with + // the (MIR) LocalDecl. + None => local_decl.source_info.span, + }; + + let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); + assert_eq!(ty_mut.mutbl, hir::MutImmutable); + if local_decl.ty.is_region_ptr() { + (highlight_span, format!("&mut {}", ty_mut.ty)) + } else { + (highlight_span, format!("*mut {}", ty_mut.ty)) + } +} + +fn is_closure_or_generator(ty: ty::Ty) -> bool { + ty.is_closure() || ty.is_generator() +} diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 7bd9a241a534e..384eb1db04ff7 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -206,7 +206,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.consume_by_copy_or_move(place) } _ => { - unpack!(block = this.as_operand(block, scope, upvar)) + // Turn mutable borrow captures into unique + // borrow captures when capturing an immutable + // variable. This is sound because the mutation + // that caused the capture will cause an error. + match upvar.kind { + ExprKind::Borrow { + borrow_kind: BorrowKind::Mut { + allow_two_phase_borrow: false + }, + region, + arg, + } => unpack!(block = this.limit_capture_mutability( + upvar.span, + upvar.ty, + scope, + block, + arg, + region, + )), + _ => unpack!(block = this.as_operand(block, scope, upvar)), + } } } }) @@ -393,6 +413,101 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + fn limit_capture_mutability( + &mut self, + upvar_span: Span, + upvar_ty: Ty<'tcx>, + temp_lifetime: Option, + mut block: BasicBlock, + arg: ExprRef<'tcx>, + region: &'tcx ty::RegionKind, + ) -> BlockAnd> { + let this = self; + + let source_info = this.source_info(upvar_span); + let temp = this.local_decls.push(LocalDecl::new_temp(upvar_ty, upvar_span)); + + this.cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageLive(temp) + }); + + let arg_place = unpack!(block = this.as_place(block, arg)); + + let mutability = match arg_place { + Place::Local(local) => this.local_decls[local].mutability, + Place::Projection(box Projection { + base: Place::Local(local), + elem: ProjectionElem::Deref, + }) => { + debug_assert!( + if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) + = this.local_decls[local].is_user_variable { + true + } else { + false + }, + "Unexpected capture place", + ); + this.local_decls[local].mutability + } + Place::Projection(box Projection { + ref base, + elem: ProjectionElem::Field(upvar_index, _), + }) + | Place::Projection(box Projection { + base: Place::Projection(box Projection { + ref base, + elem: ProjectionElem::Field(upvar_index, _), + }), + elem: ProjectionElem::Deref, + }) => { + // Not projected from the implicit `self` in a closure. + debug_assert!( + match *base { + Place::Local(local) => local == Local::new(1), + Place::Projection(box Projection { + ref base, + elem: ProjectionElem::Deref, + }) => *base == Place::Local(Local::new(1)), + _ => false, + }, + "Unexpected capture place" + ); + // Not in a closure + debug_assert!( + this.upvar_decls.len() > upvar_index.index(), + "Unexpected capture place" + ); + this.upvar_decls[upvar_index.index()].mutability + } + _ => bug!("Unexpected capture place"), + }; + + let borrow_kind = match mutability { + Mutability::Not => BorrowKind::Unique, + Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + }; + + this.cfg.push_assign( + block, + source_info, + &Place::Local(temp), + Rvalue::Ref(region, borrow_kind, arg_place), + ); + + // In constants, temp_lifetime is None. We should not need to drop + // anything because no values with a destructor can be created in + // a constant at this time, even if the type may need dropping. + if let Some(temp_lifetime) = temp_lifetime { + this.schedule_drop_storage_and_value( + upvar_span, temp_lifetime, &Place::Local(temp), upvar_ty, + ); + } + + block.and(Operand::Move(Place::Local(temp))) + } + // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap()); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 3a6c7dc9754a7..d75b8d506e77b 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1198,7 +1198,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scope, // FIXME: should these secretly injected ref_for_guard's be marked as `internal`? internal: false, - is_user_variable: None, + is_user_variable: Some(ClearCrossCrate::Set(BindingForm::RefForGuard)), }); LocalsForNode::Three { val_for_guard, ref_for_guard, for_arm_body } } else { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index cfdb8b0048a86..24228389fbfbb 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -286,6 +286,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// (A match binding can have two locals; the 2nd is for the arm's guard.) var_indices: NodeMap, local_decls: IndexVec>, + upvar_decls: Vec, unit_temp: Option>, /// cached block with the RESUME terminator; this is created @@ -472,11 +473,52 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let tcx = hir.tcx(); let span = tcx.hir.span(fn_id); + + // Gather the upvars of a closure, if any. + let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { + freevars.iter().map(|fv| { + let var_id = fv.var_id(); + let var_hir_id = tcx.hir.node_to_hir_id(var_id); + let closure_expr_id = tcx.hir.local_def_id(fn_id); + let capture = hir.tables().upvar_capture(ty::UpvarId { + var_id: var_hir_id, + closure_expr_id: LocalDefId::from_def_id(closure_expr_id), + }); + let by_ref = match capture { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true + }; + let mut decl = UpvarDecl { + debug_name: keywords::Invalid.name(), + var_hir_id: ClearCrossCrate::Set(var_hir_id), + by_ref, + mutability: Mutability::Not, + }; + if let Some(hir::map::NodeBinding(pat)) = tcx.hir.find(var_id) { + if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + decl.debug_name = ident.name; + + if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { + if bm == ty::BindByValue(hir::MutMutable) { + decl.mutability = Mutability::Mut; + } else { + decl.mutability = Mutability::Not; + } + } else { + tcx.sess.delay_span_bug(pat.span, "missing binding mode"); + } + } + } + decl + }).collect() + }); + let mut builder = Builder::new(hir.clone(), span, arguments.len(), safety, - return_ty); + return_ty, + upvar_decls); let fn_def_id = tcx.hir.local_def_id(fn_id); let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id); @@ -519,46 +561,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, info!("fn_id {:?} has attrs {:?}", closure_expr_id, tcx.get_attrs(closure_expr_id)); - // Gather the upvars of a closure, if any. - let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { - freevars.iter().map(|fv| { - let var_id = fv.var_id(); - let var_hir_id = tcx.hir.node_to_hir_id(var_id); - let closure_expr_id = tcx.hir.local_def_id(fn_id); - let capture = hir.tables().upvar_capture(ty::UpvarId { - var_id: var_hir_id, - closure_expr_id: LocalDefId::from_def_id(closure_expr_id), - }); - let by_ref = match capture { - ty::UpvarCapture::ByValue => false, - ty::UpvarCapture::ByRef(..) => true - }; - let mut decl = UpvarDecl { - debug_name: keywords::Invalid.name(), - var_hir_id: ClearCrossCrate::Set(var_hir_id), - by_ref, - mutability: Mutability::Not, - }; - if let Some(hir::map::NodeBinding(pat)) = tcx.hir.find(var_id) { - if let hir::PatKind::Binding(_, _, ident, _) = pat.node { - decl.debug_name = ident.name; - - if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { - if bm == ty::BindByValue(hir::MutMutable) { - decl.mutability = Mutability::Mut; - } else { - decl.mutability = Mutability::Not; - } - } else { - tcx.sess.delay_span_bug(pat.span, "missing binding mode"); - } - } - } - decl - }).collect() - }); - - let mut mir = builder.finish(upvar_decls, yield_ty); + let mut mir = builder.finish(yield_ty); mir.spread_arg = spread_arg; mir } @@ -571,7 +574,7 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir.body_owner(body_id); let span = tcx.hir.span(owner_id); - let mut builder = Builder::new(hir.clone(), span, 0, Safety::Safe, ty); + let mut builder = Builder::new(hir.clone(), span, 0, Safety::Safe, ty, vec![]); let mut block = START_BLOCK; let expr = builder.hir.mirror(ast_expr); @@ -590,7 +593,7 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, TerminatorKind::Unreachable); } - builder.finish(vec![], None) + builder.finish(None) } fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, @@ -599,10 +602,10 @@ fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let owner_id = hir.tcx().hir.body_owner(body_id); let span = hir.tcx().hir.span(owner_id); let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty); + let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, vec![]); let source_info = builder.source_info(span); builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - builder.finish(vec![], None) + builder.finish(None) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -610,7 +613,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: Span, arg_count: usize, safety: Safety, - return_ty: Ty<'tcx>) + return_ty: Ty<'tcx>, + upvar_decls: Vec) -> Builder<'a, 'gcx, 'tcx> { let lint_level = LintLevel::Explicit(hir.root_lint_level); let mut builder = Builder { @@ -628,6 +632,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { breakable_scopes: vec![], local_decls: IndexVec::from_elem_n(LocalDecl::new_return_place(return_ty, span), 1), + upvar_decls, var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -645,7 +650,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } fn finish(self, - upvar_decls: Vec, yield_ty: Option>) -> Mir<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { @@ -661,7 +665,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { yield_ty, self.local_decls, self.arg_count, - upvar_decls, + self.upvar_decls, self.fn_span ) } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index be87365bdbb5d..2d6b6cea03019 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -519,24 +519,35 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } - fn cannot_borrow_path_as_mutable( + fn cannot_borrow_path_as_mutable_because( self, span: Span, path: &str, + reason: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0596, - "cannot borrow {} as mutable{OGN}", + "cannot borrow {} as mutable{}{OGN}", path, - OGN = o + reason, + OGN = o, ); self.cancel_if_wrong_origin(err, o) } + fn cannot_borrow_path_as_mutable( + self, + span: Span, + path: &str, + o: Origin, + ) -> DiagnosticBuilder<'cx> { + self.cannot_borrow_path_as_mutable_because(span, path, "", o) + } + fn cannot_borrow_across_generator_yield( self, span: Span, diff --git a/src/test/compile-fail/E0594.rs b/src/test/compile-fail/E0594.rs index f3fbc3b8b54db..e5e96451d1360 100644 --- a/src/test/compile-fail/E0594.rs +++ b/src/test/compile-fail/E0594.rs @@ -15,5 +15,5 @@ static NUM: i32 = 18; fn main() { NUM = 20; //[ast]~ ERROR E0594 - //[mir]~^ ERROR cannot assign to immutable item `NUM` + //[mir]~^ ERROR cannot assign to immutable static item `NUM` } diff --git a/src/test/compile-fail/borrowck/borrowck-assign-to-constants.rs b/src/test/compile-fail/borrowck/borrowck-assign-to-constants.rs index 76a670af3531c..57002dd40fc95 100644 --- a/src/test/compile-fail/borrowck/borrowck-assign-to-constants.rs +++ b/src/test/compile-fail/borrowck/borrowck-assign-to-constants.rs @@ -16,5 +16,5 @@ static foo: isize = 5; fn main() { // assigning to various global constants foo = 6; //[ast]~ ERROR cannot assign to immutable static item - //[mir]~^ ERROR cannot assign to immutable item `foo` + //[mir]~^ ERROR cannot assign to immutable static item `foo` } diff --git a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs index 8eed61ec8d531..6bd52f00788e6 100644 --- a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs +++ b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs @@ -22,10 +22,10 @@ fn main() { let x = 1; to_fn_once(move|| { x = 2; }); //[ast]~^ ERROR: cannot assign to immutable captured outer variable - //[mir]~^^ ERROR: cannot assign to immutable item `x` + //[mir]~^^ ERROR: cannot assign to `x`, as it is not declared as mutable let s = std::io::stdin(); to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); //[ast]~^ ERROR: cannot borrow immutable captured outer variable - //[mir]~^^ ERROR: cannot borrow immutable item `s` as mutable + //[mir]~^^ ERROR: cannot borrow `s` as mutable, as it is not declared as mutable } diff --git a/src/test/compile-fail/nll/constant-thread-locals-issue-47053.rs b/src/test/compile-fail/nll/constant-thread-locals-issue-47053.rs index c7dc84c1a91c9..7b1dd9265af0d 100644 --- a/src/test/compile-fail/nll/constant-thread-locals-issue-47053.rs +++ b/src/test/compile-fail/nll/constant-thread-locals-issue-47053.rs @@ -17,5 +17,5 @@ static FOO: isize = 5; fn main() { - FOO = 6; //~ ERROR cannot assign to immutable item `FOO` [E0594] + FOO = 6; //~ ERROR cannot assign to immutable static item `FOO` [E0594] } diff --git a/src/test/ui/augmented-assignments.nll.stderr b/src/test/ui/augmented-assignments.nll.stderr index 592f666eff8f3..57a86227f764d 100644 --- a/src/test/ui/augmented-assignments.nll.stderr +++ b/src/test/ui/augmented-assignments.nll.stderr @@ -14,7 +14,7 @@ LL | | x; //~ value moved here | |_____move out of `x` occurs here | borrow later used here -error[E0596]: cannot borrow immutable item `y` as mutable +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/augmented-assignments.rs:30:5 | LL | let y = Int(2); diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index 68a039262c129..5a1f1986fcf05 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -14,21 +14,14 @@ LL | give_any(|y| x = Some(y)); | | | lifetime `'1` appears in this argument -error[E0594]: cannot assign to immutable item `x` +error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-45983.rs:17:18 | -LL | give_any(|y| x = Some(y)); - | ^^^^^^^^^^^ cannot assign - -error[E0596]: cannot borrow immutable item `x` as mutable - --> $DIR/issue-45983.rs:17:14 - | LL | let x = None; | - help: consider changing this to be mutable: `mut x` LL | give_any(|y| x = Some(y)); - | ^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot assign -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr index 0674c8230165a..ece3c62e6a940 100644 --- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr +++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `b` as mutable +error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable --> $DIR/mut-borrow-of-mut-ref.rs:18:7 | LL | fn f(b: &mut i32) { diff --git a/src/test/ui/borrowck/mutability-errors.nll.stderr b/src/test/ui/borrowck/mutability-errors.nll.stderr new file mode 100644 index 0000000000000..14c41bb81b2c6 --- /dev/null +++ b/src/test/ui/borrowck/mutability-errors.nll.stderr @@ -0,0 +1,379 @@ +error[E0594]: cannot assign to `*x` which is behind a `&` reference + --> $DIR/mutability-errors.rs:19:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +LL | *x = (1,); //~ ERROR + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `x.0` which is behind a `&` reference + --> $DIR/mutability-errors.rs:20:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +LL | *x = (1,); //~ ERROR +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:21:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +... +LL | &mut *x; //~ ERROR + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:22:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +... +LL | &mut x.0; //~ ERROR + | ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/mutability-errors.rs:26:5 + | +LL | *f() = (1,); //~ ERROR + | ^^^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/mutability-errors.rs:27:5 + | +LL | f().0 = 1; //~ ERROR + | ^^^^^^^^^ cannot assign + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:28:5 + | +LL | &mut *f(); //~ ERROR + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:29:5 + | +LL | &mut f().0; //~ ERROR + | ^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `*x` which is behind a `*const` pointer + --> $DIR/mutability-errors.rs:33:5 + | +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +LL | *x = (1,); //~ ERROR + | ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written + +error[E0594]: cannot assign to `x.0` which is behind a `*const` pointer + --> $DIR/mutability-errors.rs:34:5 + | +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +LL | *x = (1,); //~ ERROR +LL | (*x).0 = 1; //~ ERROR + | ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:35:5 + | +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +... +LL | &mut *x; //~ ERROR + | ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:36:5 + | +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +... +LL | &mut (*x).0; //~ ERROR + | ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + +error[E0594]: cannot assign to data in a `*const` pointer + --> $DIR/mutability-errors.rs:40:5 + | +LL | *f() = (1,); //~ ERROR + | ^^^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to data in a `*const` pointer + --> $DIR/mutability-errors.rs:41:5 + | +LL | (*f()).0 = 1; //~ ERROR + | ^^^^^^^^^^^^ cannot assign + +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:42:5 + | +LL | &mut *f(); //~ ERROR + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:43:5 + | +LL | &mut (*f()).0; //~ ERROR + | ^^^^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:50:9 + | +LL | x = (1,); //~ ERROR + | ^^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:51:9 + | +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:52:9 + | +LL | &mut x; //~ ERROR + | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:53:9 + | +LL | &mut x.0; //~ ERROR + | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:56:9 + | +LL | x = (1,); //~ ERROR + | ^^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:57:9 + | +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:58:9 + | +LL | &mut x; //~ ERROR + | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:59:9 + | +LL | &mut x.0; //~ ERROR + | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:64:5 + | +LL | fn imm_local(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | &mut x; //~ ERROR + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:65:5 + | +LL | fn imm_local(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | &mut x; //~ ERROR +LL | &mut x.0; //~ ERROR + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/mutability-errors.rs:70:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { //~ ERROR +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:71:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:72:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:73:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/mutability-errors.rs:76:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = (1,); //~ ERROR + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:77:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:78:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; //~ ERROR + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:79:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; //~ ERROR + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to immutable static item `X` + --> $DIR/mutability-errors.rs:86:5 + | +LL | X = (1,); //~ ERROR + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `X.0`, as `X` is an immutable static item + --> $DIR/mutability-errors.rs:87:5 + | +LL | X.0 = 1; //~ ERROR + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/mutability-errors.rs:88:5 + | +LL | &mut X; //~ ERROR + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item + --> $DIR/mutability-errors.rs:89:5 + | +LL | &mut X.0; //~ ERROR + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 38 previous errors + +Some errors occurred: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/mutability-errors.rs b/src/test/ui/borrowck/mutability-errors.rs new file mode 100644 index 0000000000000..0b4548cbebb7d --- /dev/null +++ b/src/test/ui/borrowck/mutability-errors.rs @@ -0,0 +1,92 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// All the possible mutability error cases. + +#![allow(unused)] + +type MakeRef = fn() -> &'static (i32,); +type MakePtr = fn() -> *const (i32,); + +fn named_ref(x: &(i32,)) { + *x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut *x; //~ ERROR + &mut x.0; //~ ERROR +} + +fn unnamed_ref(f: MakeRef) { + *f() = (1,); //~ ERROR + f().0 = 1; //~ ERROR + &mut *f(); //~ ERROR + &mut f().0; //~ ERROR +} + +unsafe fn named_ptr(x: *const (i32,)) { + *x = (1,); //~ ERROR + (*x).0 = 1; //~ ERROR + &mut *x; //~ ERROR + &mut (*x).0; //~ ERROR +} + +unsafe fn unnamed_ptr(f: MakePtr) { + *f() = (1,); //~ ERROR + (*f()).0 = 1; //~ ERROR + &mut *f(); //~ ERROR + &mut (*f()).0; //~ ERROR +} + +fn fn_ref(f: F) -> F { f } + +fn ref_closure(mut x: (i32,)) { + fn_ref(|| { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }); + fn_ref(move || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }); +} + +fn imm_local(x: (i32,)) { + &mut x; //~ ERROR + &mut x.0; //~ ERROR +} + +fn imm_capture(x: (i32,)) { + || { //~ ERROR + x = (1,); + x.0 = 1; + &mut x; + &mut x.0; + }; + move || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }; +} + +static X: (i32,) = (0,); + +fn imm_static() { + X = (1,); //~ ERROR + X.0 = 1; //~ ERROR + &mut X; //~ ERROR + &mut X.0; //~ ERROR +} + +fn main() {} diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr new file mode 100644 index 0000000000000..d77254f31414b --- /dev/null +++ b/src/test/ui/borrowck/mutability-errors.stderr @@ -0,0 +1,308 @@ +error[E0594]: cannot assign to immutable borrowed content `*x` + --> $DIR/mutability-errors.rs:19:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- use `&mut (i32,)` here to make mutable +LL | *x = (1,); //~ ERROR + | ^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to field `x.0` of immutable binding + --> $DIR/mutability-errors.rs:20:5 + | +LL | fn named_ref(x: &(i32,)) { + | ------- use `&mut (i32,)` here to make mutable +LL | *x = (1,); //~ ERROR +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/mutability-errors.rs:21:10 + | +LL | fn named_ref(x: &(i32,)) { + | ------- use `&mut (i32,)` here to make mutable +... +LL | &mut *x; //~ ERROR + | ^^ cannot borrow as mutable + +error[E0596]: cannot borrow field `x.0` of immutable binding as mutable + --> $DIR/mutability-errors.rs:22:10 + | +LL | fn named_ref(x: &(i32,)) { + | ------- use `&mut (i32,)` here to make mutable +... +LL | &mut x.0; //~ ERROR + | ^^^ cannot mutably borrow field of immutable binding + +error[E0594]: cannot assign to immutable borrowed content + --> $DIR/mutability-errors.rs:26:5 + | +LL | *f() = (1,); //~ ERROR + | ^^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to field of immutable binding + --> $DIR/mutability-errors.rs:27:5 + | +LL | f().0 = 1; //~ ERROR + | ^^^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable borrowed content as mutable + --> $DIR/mutability-errors.rs:28:10 + | +LL | &mut *f(); //~ ERROR + | ^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow field of immutable binding as mutable + --> $DIR/mutability-errors.rs:29:10 + | +LL | &mut f().0; //~ ERROR + | ^^^^^ cannot mutably borrow field of immutable binding + +error[E0594]: cannot assign to immutable dereference of raw pointer `*x` + --> $DIR/mutability-errors.rs:33:5 + | +LL | *x = (1,); //~ ERROR + | ^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to field `x.0` of immutable binding + --> $DIR/mutability-errors.rs:34:5 + | +LL | (*x).0 = 1; //~ ERROR + | ^^^^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable dereference of raw pointer `*x` as mutable + --> $DIR/mutability-errors.rs:35:10 + | +LL | &mut *x; //~ ERROR + | ^^ cannot borrow as mutable + +error[E0596]: cannot borrow field `x.0` of immutable binding as mutable + --> $DIR/mutability-errors.rs:36:10 + | +LL | &mut (*x).0; //~ ERROR + | ^^^^^^ cannot mutably borrow field of immutable binding + +error[E0594]: cannot assign to immutable dereference of raw pointer + --> $DIR/mutability-errors.rs:40:5 + | +LL | *f() = (1,); //~ ERROR + | ^^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to field of immutable binding + --> $DIR/mutability-errors.rs:41:5 + | +LL | (*f()).0 = 1; //~ ERROR + | ^^^^^^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable dereference of raw pointer as mutable + --> $DIR/mutability-errors.rs:42:10 + | +LL | &mut *f(); //~ ERROR + | ^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow field of immutable binding as mutable + --> $DIR/mutability-errors.rs:43:10 + | +LL | &mut (*f()).0; //~ ERROR + | ^^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure + --> $DIR/mutability-errors.rs:50:9 + | +LL | x = (1,); //~ ERROR + | ^^^^^^^^ + | +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure + --> $DIR/mutability-errors.rs:51:9 + | +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ + | +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure + --> $DIR/mutability-errors.rs:52:14 + | +LL | &mut x; //~ ERROR + | ^ + | +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure + --> $DIR/mutability-errors.rs:53:14 + | +LL | &mut x.0; //~ ERROR + | ^^^ + | +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:49:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0594]: cannot assign to captured outer variable in an `Fn` closure + --> $DIR/mutability-errors.rs:56:9 + | +LL | x = (1,); //~ ERROR + | ^^^^^^^^ + | + = note: `Fn` closures cannot capture their enclosing environment for modifications +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0594]: cannot assign to field `x.0` of immutable binding + --> $DIR/mutability-errors.rs:57:9 + | +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow captured outer variable in an `Fn` closure as mutable + --> $DIR/mutability-errors.rs:58:14 + | +LL | &mut x; //~ ERROR + | ^ + | +help: consider changing this closure to take self by mutable reference + --> $DIR/mutability-errors.rs:55:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); //~ ERROR +LL | | x.0 = 1; //~ ERROR +LL | | &mut x; //~ ERROR +LL | | &mut x.0; //~ ERROR +LL | | }); + | |_____^ + +error[E0596]: cannot borrow field `x.0` of immutable binding as mutable + --> $DIR/mutability-errors.rs:59:14 + | +LL | &mut x.0; //~ ERROR + | ^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable argument `x` as mutable + --> $DIR/mutability-errors.rs:64:10 + | +LL | fn imm_local(x: (i32,)) { + | - consider changing this to `mut x` +LL | &mut x; //~ ERROR + | ^ cannot borrow mutably + +error[E0596]: cannot borrow field `x.0` of immutable binding as mutable + --> $DIR/mutability-errors.rs:65:10 + | +LL | fn imm_local(x: (i32,)) { + | - consider changing this to `mut x` +LL | &mut x; //~ ERROR +LL | &mut x.0; //~ ERROR + | ^^^ cannot mutably borrow field of immutable binding + +error[E0595]: closure cannot assign to immutable argument `x` + --> $DIR/mutability-errors.rs:69:5 + | +LL | fn imm_capture(x: (i32,)) { + | - consider changing this to `mut x` +LL | || { //~ ERROR + | ^^ cannot borrow mutably + +error[E0594]: cannot assign to captured outer variable in an `FnMut` closure + --> $DIR/mutability-errors.rs:76:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider making `x` mutable: `mut x` +... +LL | x = (1,); //~ ERROR + | ^^^^^^^^ + +error[E0594]: cannot assign to field `x.0` of immutable binding + --> $DIR/mutability-errors.rs:77:9 + | +LL | x.0 = 1; //~ ERROR + | ^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable + --> $DIR/mutability-errors.rs:78:14 + | +LL | &mut x; //~ ERROR + | ^ + +error[E0596]: cannot borrow field `x.0` of immutable binding as mutable + --> $DIR/mutability-errors.rs:79:14 + | +LL | &mut x.0; //~ ERROR + | ^^^ cannot mutably borrow field of immutable binding + +error[E0594]: cannot assign to immutable static item + --> $DIR/mutability-errors.rs:86:5 + | +LL | X = (1,); //~ ERROR + | ^^^^^^^^ + +error[E0594]: cannot assign to field of immutable binding + --> $DIR/mutability-errors.rs:87:5 + | +LL | X.0 = 1; //~ ERROR + | ^^^^^^^ cannot mutably borrow field of immutable binding + +error[E0596]: cannot borrow immutable static item as mutable + --> $DIR/mutability-errors.rs:88:10 + | +LL | &mut X; //~ ERROR + | ^ + +error[E0596]: cannot borrow field of immutable binding as mutable + --> $DIR/mutability-errors.rs:89:10 + | +LL | &mut X.0; //~ ERROR + | ^^^ cannot mutably borrow field of immutable binding + +error: aborting due to 35 previous errors + +Some errors occurred: E0387, E0594, E0595, E0596. +For more information about an error, try `rustc --explain E0387`. diff --git a/src/test/ui/closure-immutable-outer-variable.nll.stderr b/src/test/ui/closure-immutable-outer-variable.nll.stderr index 335ccefe8a0b1..d91c1199b3f82 100644 --- a/src/test/ui/closure-immutable-outer-variable.nll.stderr +++ b/src/test/ui/closure-immutable-outer-variable.nll.stderr @@ -1,6 +1,8 @@ -error[E0594]: cannot assign to immutable item `y` +error[E0594]: cannot assign to `y`, as it is not declared as mutable --> $DIR/closure-immutable-outer-variable.rs:21:26 | +LL | let y = true; + | - help: consider changing this to be mutable: `mut y` LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable | ^^^^^^^^^ cannot assign diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr index da0b201f5d4e1..8251f04d353f7 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/huge_multispan_highlight.rs:100:13 | LL | let x = "foo"; diff --git a/src/test/ui/did_you_mean/issue-31424.nll.stderr b/src/test/ui/did_you_mean/issue-31424.nll.stderr index 21c5e3608c00b..eae834e2b1aa8 100644 --- a/src/test/ui/did_you_mean/issue-31424.nll.stderr +++ b/src/test/ui/did_you_mean/issue-31424.nll.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable item `self` as mutable +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-31424.rs:17:9 | LL | (&mut self).bar(); //~ ERROR cannot borrow | ^^^^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `self` as mutable +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-31424.rs:23:9 | LL | fn bar(self: &mut Self) { diff --git a/src/test/ui/did_you_mean/issue-34126.nll.stderr b/src/test/ui/did_you_mean/issue-34126.nll.stderr index 8dedb6ec4db80..004c43a7343f8 100644 --- a/src/test/ui/did_you_mean/issue-34126.nll.stderr +++ b/src/test/ui/did_you_mean/issue-34126.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `self` as mutable +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-34126.rs:16:18 | LL | self.run(&mut self); //~ ERROR cannot borrow diff --git a/src/test/ui/did_you_mean/issue-34337.nll.stderr b/src/test/ui/did_you_mean/issue-34337.nll.stderr index d2271e8e7de76..38315a067c07f 100644 --- a/src/test/ui/did_you_mean/issue-34337.nll.stderr +++ b/src/test/ui/did_you_mean/issue-34337.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `key` as mutable +error[E0596]: cannot borrow `key` as mutable, as it is not declared as mutable --> $DIR/issue-34337.rs:16:9 | LL | get(&mut key); //~ ERROR cannot borrow diff --git a/src/test/ui/did_you_mean/issue-35937.nll.stderr b/src/test/ui/did_you_mean/issue-35937.nll.stderr index 7eaa4c7d5fea0..804e5f0531f85 100644 --- a/src/test/ui/did_you_mean/issue-35937.nll.stderr +++ b/src/test/ui/did_you_mean/issue-35937.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `f.v` as mutable +error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable --> $DIR/issue-35937.rs:17:5 | LL | let f = Foo { v: Vec::new() }; diff --git a/src/test/ui/did_you_mean/issue-37139.nll.stderr b/src/test/ui/did_you_mean/issue-37139.nll.stderr index e51a1baad25f2..7cc7ca1463814 100644 --- a/src/test/ui/did_you_mean/issue-37139.nll.stderr +++ b/src/test/ui/did_you_mean/issue-37139.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/issue-37139.rs:22:18 | LL | test(&mut x); //~ ERROR cannot borrow immutable diff --git a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr index d156d64b9d693..25613561bbaf8 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*self.s` as mutable +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-1.rs:27:9 | LL | fn f(&self) { diff --git a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr index c8e231ea3b3dc..21fc4079d5b59 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*self.s` as mutable +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-2.rs:17:9 | LL | self.s.push('x'); diff --git a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr index c5d6551b647dd..d426c1f37fc1c 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*self.s` as mutable +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-3.rs:17:9 | LL | self.s.push('x'); diff --git a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr index c875957623b62..eccbe19ac943e 100644 --- a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*f.s` as mutable +error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-4.rs:16:5 | LL | fn f(x: usize, f: &Foo) { diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr index e2d2fcd63db12..00e4cc6b0c35d 100644 --- a/src/test/ui/did_you_mean/issue-39544.nll.stderr +++ b/src/test/ui/did_you_mean/issue-39544.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `z.x` as mutable +error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable --> $DIR/issue-39544.rs:21:13 | LL | let z = Z { x: X::Y }; @@ -6,7 +6,7 @@ LL | let z = Z { x: X::Y }; LL | let _ = &mut z.x; //~ ERROR cannot borrow | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `self.x` as mutable +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:26:17 | LL | fn foo<'z>(&'z self) { @@ -14,7 +14,7 @@ LL | fn foo<'z>(&'z self) { LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `self.x` as mutable +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:30:17 | LL | fn foo1(&self, other: &Z) { @@ -22,7 +22,7 @@ LL | fn foo1(&self, other: &Z) { LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `other.x` as mutable +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:31:17 | LL | fn foo1(&self, other: &Z) { @@ -31,7 +31,7 @@ LL | let _ = &mut self.x; //~ ERROR cannot borrow LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `self.x` as mutable +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:35:17 | LL | fn foo2<'a>(&'a self, other: &Z) { @@ -39,7 +39,7 @@ LL | fn foo2<'a>(&'a self, other: &Z) { LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `other.x` as mutable +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:36:17 | LL | fn foo2<'a>(&'a self, other: &Z) { @@ -48,7 +48,7 @@ LL | let _ = &mut self.x; //~ ERROR cannot borrow LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `self.x` as mutable +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:40:17 | LL | fn foo3<'a>(self: &'a Self, other: &Z) { @@ -56,7 +56,7 @@ LL | fn foo3<'a>(self: &'a Self, other: &Z) { LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `other.x` as mutable +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:41:17 | LL | fn foo3<'a>(self: &'a Self, other: &Z) { @@ -65,7 +65,7 @@ LL | let _ = &mut self.x; //~ ERROR cannot borrow LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `other.x` as mutable +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:45:17 | LL | fn foo4(other: &Z) { @@ -73,7 +73,7 @@ LL | fn foo4(other: &Z) { LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `z.x` as mutable +error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable --> $DIR/issue-39544.rs:51:13 | LL | pub fn with_arg(z: Z, w: &Z) { @@ -81,7 +81,7 @@ LL | pub fn with_arg(z: Z, w: &Z) { LL | let _ = &mut z.x; //~ ERROR cannot borrow | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `w.x` as mutable +error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:52:13 | LL | pub fn with_arg(z: Z, w: &Z) { diff --git a/src/test/ui/did_you_mean/issue-40823.nll.stderr b/src/test/ui/did_you_mean/issue-40823.nll.stderr index 1fd75de81284f..44ae058cc2803 100644 --- a/src/test/ui/did_you_mean/issue-40823.nll.stderr +++ b/src/test/ui/did_you_mean/issue-40823.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*buf` as mutable +error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference --> $DIR/issue-40823.rs:13:5 | LL | let mut buf = &[1, 2, 3, 4]; diff --git a/src/test/ui/error-codes/E0017.nll.stderr b/src/test/ui/error-codes/E0017.nll.stderr index addbbf4434f4f..08708d213d3f6 100644 --- a/src/test/ui/error-codes/E0017.nll.stderr +++ b/src/test/ui/error-codes/E0017.nll.stderr @@ -10,7 +10,7 @@ error[E0017]: references in statics may only refer to immutable values LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error[E0596]: cannot borrow immutable item `X` as mutable +error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:15:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 diff --git a/src/test/ui/error-codes/E0388.nll.stderr b/src/test/ui/error-codes/E0388.nll.stderr index 0238ca6b623da..a048374a49725 100644 --- a/src/test/ui/error-codes/E0388.nll.stderr +++ b/src/test/ui/error-codes/E0388.nll.stderr @@ -10,7 +10,7 @@ error[E0017]: references in statics may only refer to immutable values LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 | ^^^^^^ statics require immutable values -error[E0596]: cannot borrow immutable item `X` as mutable +error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0388.rs:15:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 diff --git a/src/test/ui/fn-closure-mutable-capture.nll.stderr b/src/test/ui/fn-closure-mutable-capture.nll.stderr index 7ef21d3720d88..ff06256088fa2 100644 --- a/src/test/ui/fn-closure-mutable-capture.nll.stderr +++ b/src/test/ui/fn-closure-mutable-capture.nll.stderr @@ -1,8 +1,14 @@ -error[E0594]: cannot assign to `x` which is behind a `&` reference +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/fn-closure-mutable-capture.rs:15:17 | LL | bar(move || x = 1); | ^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/fn-closure-mutable-capture.rs:15:9 + | +LL | bar(move || x = 1); + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issue-21600.nll.stderr b/src/test/ui/issue-21600.nll.stderr index b5b9cefb70639..5fe8dc45ccc72 100644 --- a/src/test/ui/issue-21600.nll.stderr +++ b/src/test/ui/issue-21600.nll.stderr @@ -1,14 +1,33 @@ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:24:20 | LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer | ^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/issue-21600.rs:24:17 + | +LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer + | ^^^^^^^^^^^^^^ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:24:17 | LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^ - mutable borrow occurs due to use of `x` in closure + | | + | cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/issue-21600.rs:22:13 + | +LL | call_it(|| { + | _____________^ +LL | | call_it(|| x.gen()); +LL | | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer +LL | | //~^ ERROR cannot borrow data mutably in a captured outer +LL | | }); + | |_____^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs index 5d445c63ef492..39d54f6e7ae28 100644 --- a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs +++ b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs @@ -24,7 +24,7 @@ fn main() { match b { &mut false => {}, ref mut r if { (|| { let bar = &mut *r; **bar = false; })(); - //~^ ERROR cannot borrow immutable item `*r` as mutable + //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard false } => { &mut *r; }, &mut true => { println!("You might think we should get here"); }, _ => panic!("surely we could never get here, since rustc warns it is unreachable."), diff --git a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr index d767fdde9f217..660902880ac2f 100644 --- a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr +++ b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr @@ -1,8 +1,12 @@ -error[E0596]: cannot borrow immutable item `*r` as mutable - --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:26:24 +error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard + --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:26:25 | LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^ - mutable borrow occurs due to use of `r` in closure + | | + | cannot borrow as mutable + | + = note: variables bound in patterns are immutable until the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/issue-33819.nll.stderr b/src/test/ui/issue-33819.nll.stderr index 8872820792108..78ad31a04c88b 100644 --- a/src/test/ui/issue-33819.nll.stderr +++ b/src/test/ui/issue-33819.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `v` as mutable +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/issue-33819.rs:13:34 | LL | Some(ref v) => { let a = &mut v; }, diff --git a/src/test/ui/issue-36400.nll.stderr b/src/test/ui/issue-36400.nll.stderr index be10b1d517bdc..e4347f0ece831 100644 --- a/src/test/ui/issue-36400.nll.stderr +++ b/src/test/ui/issue-36400.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/issue-36400.rs:15:7 | LL | let x = Box::new(3); diff --git a/src/test/ui/issue-41726.nll.stderr b/src/test/ui/issue-41726.nll.stderr index feeb63e1ebb1b..06ff743a0f5ed 100644 --- a/src/test/ui/issue-41726.nll.stderr +++ b/src/test/ui/issue-41726.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/issue-41726.rs:15:9 | LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable diff --git a/src/test/ui/issue-42344.nll.stderr b/src/test/ui/issue-42344.nll.stderr index 02f6ffe173462..1abc448dbb090 100644 --- a/src/test/ui/issue-42344.nll.stderr +++ b/src/test/ui/issue-42344.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*TAB[..]` as mutable +error[E0596]: cannot borrow `*TAB[..]` as mutable, as `TAB` is an immutable static item --> $DIR/issue-42344.rs:14:5 | LL | TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389] diff --git a/src/test/ui/issue-46023.ast.nll.stderr b/src/test/ui/issue-46023.ast.nll.stderr index 2fc2924c2ec37..bda629d48affc 100644 --- a/src/test/ui/issue-46023.ast.nll.stderr +++ b/src/test/ui/issue-46023.ast.nll.stderr @@ -1,6 +1,9 @@ -error[E0594]: cannot assign to immutable item `x` +error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-46023.rs:18:9 | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... LL | x = 1; | ^^^^^ cannot assign diff --git a/src/test/ui/issue-46023.mir.stderr b/src/test/ui/issue-46023.mir.stderr index 2fc2924c2ec37..bda629d48affc 100644 --- a/src/test/ui/issue-46023.mir.stderr +++ b/src/test/ui/issue-46023.mir.stderr @@ -1,6 +1,9 @@ -error[E0594]: cannot assign to immutable item `x` +error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-46023.rs:18:9 | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... LL | x = 1; | ^^^^^ cannot assign diff --git a/src/test/ui/issue-46023.rs b/src/test/ui/issue-46023.rs index d51d92570fd67..d5c8cd6d0f8fc 100644 --- a/src/test/ui/issue-46023.rs +++ b/src/test/ui/issue-46023.rs @@ -16,7 +16,7 @@ fn main() { (move || { x = 1; - //[mir]~^ ERROR cannot assign to immutable item `x` [E0594] + //[mir]~^ ERROR cannot assign to `x`, as it is not declared as mutable [E0594] //[ast]~^^ ERROR cannot assign to captured outer variable in an `FnMut` closure [E0594] })() } diff --git a/src/test/ui/issue-46604.ast.nll.stderr b/src/test/ui/issue-46604.ast.nll.stderr index b947bec639737..a4ee0d4e2a3a9 100644 --- a/src/test/ui/issue-46604.ast.nll.stderr +++ b/src/test/ui/issue-46604.ast.nll.stderr @@ -4,7 +4,7 @@ error[E0017]: references in statics may only refer to immutable values LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values -error[E0594]: cannot assign to immutable item `buf[..]` +error[E0594]: cannot assign to `buf[..]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:20:5 | LL | buf[0]=2; //[ast]~ ERROR E0389 diff --git a/src/test/ui/issue-46604.mir.stderr b/src/test/ui/issue-46604.mir.stderr index b947bec639737..a4ee0d4e2a3a9 100644 --- a/src/test/ui/issue-46604.mir.stderr +++ b/src/test/ui/issue-46604.mir.stderr @@ -4,7 +4,7 @@ error[E0017]: references in statics may only refer to immutable values LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values -error[E0594]: cannot assign to immutable item `buf[..]` +error[E0594]: cannot assign to `buf[..]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:20:5 | LL | buf[0]=2; //[ast]~ ERROR E0389 diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr index 01e2698032394..d5bba6649a2c7 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -12,7 +12,7 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { LL | y.push(z); //~ ERROR lifetime mismatch | ^ ...but data from `z` flows into `y` here -error[E0596]: cannot borrow immutable item `y` as mutable +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:3 | LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr index a61d49fc953db..0608b3be8b33a 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -12,7 +12,7 @@ LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { LL | y.push(z); //~ ERROR lifetime mismatch | ^ ...but data from `z` flows into `y` here -error[E0596]: cannot borrow immutable item `y` as mutable +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:3 | LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { diff --git a/src/test/ui/macros/span-covering-argument-1.nll.stderr b/src/test/ui/macros/span-covering-argument-1.nll.stderr index 213eddee720d3..3947f6c0f11fc 100644 --- a/src/test/ui/macros/span-covering-argument-1.nll.stderr +++ b/src/test/ui/macros/span-covering-argument-1.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `foo` as mutable +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable --> $DIR/span-covering-argument-1.rs:15:14 | LL | let $s = 0; diff --git a/src/test/ui/nll/closure-captures.rs b/src/test/ui/nll/closure-captures.rs new file mode 100644 index 0000000000000..03a22bb79a86b --- /dev/null +++ b/src/test/ui/nll/closure-captures.rs @@ -0,0 +1,68 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Some cases with closures that might be problems + +#![allow(unused)] +#![feature(nll)] + +// Should have one error per assigment + +fn one_closure(x: i32) { + || + x = 1; //~ ERROR + move || + x = 1; //~ ERROR +} + +fn two_closures(x: i32) { + || { + || + x = 1; //~ ERROR + }; + move || { + || + x = 1; //~ ERROR + }; +} + +fn fn_ref(f: F) -> F { f } + +fn two_closures_ref_mut(mut x: i32) { + fn_ref(|| { + || //~ ERROR + x = 1;} + ); + fn_ref(move || { + || //~ ERROR + x = 1;}); +} + +// This still gives two messages, but it requires two things to be fixed. +fn two_closures_ref(x: i32) { + fn_ref(|| { + || //~ ERROR + x = 1;} //~ ERROR + ); + fn_ref(move || { + || //~ ERROR + x = 1;}); //~ ERROR +} + +fn two_closures_two_refs(x: &mut i32) { + fn_ref(|| { + || //~ ERROR + *x = 1;}); + fn_ref(move || { + || //~ ERROR + *x = 1;}); +} + +fn main() {} diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr new file mode 100644 index 0000000000000..a03e104a1b1fb --- /dev/null +++ b/src/test/ui/nll/closure-captures.stderr @@ -0,0 +1,160 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:20:5 + | +LL | fn one_closure(x: i32) { + | - help: consider changing this to be mutable: `mut x` +LL | || +LL | x = 1; //~ ERROR + | ^^^^^ cannot assign + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:22:5 + | +LL | fn one_closure(x: i32) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1; //~ ERROR + | ^^^^^ cannot assign + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:28:9 + | +LL | fn two_closures(x: i32) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1; //~ ERROR + | ^^^^^ cannot assign + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:32:9 + | +LL | fn two_closures(x: i32) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1; //~ ERROR + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:40:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | x = 1;} + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:39:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | || //~ ERROR +LL | | x = 1;} + | |________________^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:44:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | x = 1;}); + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:43:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | || //~ ERROR +LL | | x = 1;}); + | |___________^ + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:52:10 + | +LL | fn two_closures_ref(x: i32) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1;} //~ ERROR + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:51:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | x = 1;} //~ ERROR + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:50:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | || //~ ERROR +LL | | x = 1;} //~ ERROR + | |________________^ + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-captures.rs:56:5 + | +LL | fn two_closures_ref(x: i32) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1;}); //~ ERROR + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:55:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | x = 1;}); //~ ERROR + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:54:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | || //~ ERROR +LL | | x = 1;}); //~ ERROR + | |___________^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:61:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | *x = 1;}); + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:60:12 + | +LL | fn_ref(|| { + | ____________^ +LL | | || //~ ERROR +LL | | *x = 1;}); + | |________________^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/closure-captures.rs:64:9 + | +LL | || //~ ERROR + | ^^ cannot borrow as mutable +LL | *x = 1;}); + | - mutable borrow occurs due to use of `x` in closure + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/closure-captures.rs:63:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | || //~ ERROR +LL | | *x = 1;}); + | |________________^ + +error: aborting due to 12 previous errors + +Some errors occurred: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/generator-upvar-mutability.stderr b/src/test/ui/nll/generator-upvar-mutability.stderr index 9c5c57687a2ea..180a330a30e74 100644 --- a/src/test/ui/nll/generator-upvar-mutability.stderr +++ b/src/test/ui/nll/generator-upvar-mutability.stderr @@ -1,6 +1,9 @@ -error[E0594]: cannot assign to immutable item `x` +error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/generator-upvar-mutability.rs:18:9 | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +LL | move || { LL | x = 1; | ^^^^^ cannot assign diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr index 3282fbba6c5cf..366bfc8fa20a5 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 | LL | fn deref_mut_field1(x: Own) { @@ -6,7 +6,7 @@ LL | fn deref_mut_field1(x: Own) { LL | let __isize = &mut x.y; //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10 | LL | fn deref_extend_mut_field1(x: &Own) -> &mut isize { @@ -14,7 +14,7 @@ LL | fn deref_extend_mut_field1(x: &Own) -> &mut isize { LL | &mut x.y //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 | LL | fn assign_field1<'a>(x: Own) { @@ -22,7 +22,7 @@ LL | fn assign_field1<'a>(x: Own) { LL | x.y = 3; //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5 | LL | fn assign_field2<'a>(x: &'a Own) { @@ -30,7 +30,7 @@ LL | fn assign_field2<'a>(x: &'a Own) { LL | x.y = 3; //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 | LL | fn deref_mut_method1(x: Own) { @@ -38,7 +38,7 @@ LL | fn deref_mut_method1(x: Own) { LL | x.set(0, 0); //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5 | LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { @@ -46,7 +46,7 @@ LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { LL | x.y_mut() //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 | LL | fn assign_method1<'a>(x: Own) { @@ -54,7 +54,7 @@ LL | fn assign_method1<'a>(x: Own) { LL | *x.y_mut() = 3; //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6 | LL | fn assign_method2<'a>(x: &'a Own) { diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr index 0b1bfd8cee673..69bf246ff3fef 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 | LL | fn deref_mut1(x: Own) { @@ -6,7 +6,7 @@ LL | fn deref_mut1(x: Own) { LL | let __isize = &mut *x; //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11 | LL | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { @@ -14,7 +14,7 @@ LL | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { LL | &mut **x //~ ERROR cannot borrow | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 | LL | fn assign1<'a>(x: Own) { @@ -22,7 +22,7 @@ LL | fn assign1<'a>(x: Own) { LL | *x = 3; //~ ERROR cannot borrow | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6 | LL | fn assign2<'a>(x: &'a Own) { diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr index c4bdef21de4ba..f752015c650b9 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -12,7 +12,7 @@ LL | | f((Box::new(|| {}))) LL | | })); | |_______- borrow later used here -error[E0596]: cannot borrow immutable item `*f` as mutable +error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5 | LL | fn test2(f: &F) where F: FnMut() { @@ -20,7 +20,7 @@ LL | fn test2(f: &F) where F: FnMut() { LL | (*f)(); | ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `*f.f` as mutable +error[E0596]: cannot borrow `*f.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 | LL | fn test4(f: &Test) { diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr index 0bc614589e3d2..e9c0505af68b2 100644 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5 | LL | fn b(x: &Foo) { diff --git a/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr b/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr index 1cb2c92833c16..5e47d3271d49f 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-fn-in-const-b.rs:17:9 | LL | fn broken(x: &Vec) { diff --git a/src/test/ui/span/borrowck-object-mutability.nll.stderr b/src/test/ui/span/borrowck-object-mutability.nll.stderr index b318e778f8766..3f0eb97c7af29 100644 --- a/src/test/ui/span/borrowck-object-mutability.nll.stderr +++ b/src/test/ui/span/borrowck-object-mutability.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-object-mutability.rs:19:5 | LL | fn borrowed_receiver(x: &Foo) { @@ -7,7 +7,7 @@ LL | x.borrowed(); LL | x.borrowed_mut(); //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | LL | fn owned_receiver(x: Box) { diff --git a/src/test/ui/span/mut-arg-hint.nll.stderr b/src/test/ui/span/mut-arg-hint.nll.stderr index cd19059fdae32..f264ea1f91676 100644 --- a/src/test/ui/span/mut-arg-hint.nll.stderr +++ b/src/test/ui/span/mut-arg-hint.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:13:9 | LL | fn foo(mut a: &String) { @@ -6,7 +6,7 @@ LL | fn foo(mut a: &String) { LL | a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:18:5 | LL | pub fn foo<'a>(mut a: &'a String) { @@ -14,7 +14,7 @@ LL | pub fn foo<'a>(mut a: &'a String) { LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:25:9 | LL | pub fn foo(mut a: &String) { diff --git a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr index 1a36b0c4839b6..215faf6c73c36 100644 --- a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr +++ b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable item `**t` as mutable +error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5 | LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { @@ -6,7 +6,7 @@ LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: C LL | *t //~ ERROR | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable item `**t` as mutable +error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6 | LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {