Auto merge of #51275 - pnkfelix:nll-diagnostics-revise-check-access-permissions, r=nikomatsakis

NLL diagnostics: revise `fn check_access_permissions`

NLL: revise `fn check_access_permissions` so that its (still branchy) shares more code paths between the different cases, and also provide more diagnostics in more cases (though the added diagnostics still do not always meet the quality bar established by AST-borrowck)

----

Transcribing "checklist" suggested by Niko, except I am rendering it as a table to make it clear that I do not regard every item in the list to be a "must have" for landing this PR.

goal | does this PR do it?
-----|------------------------------
no suggestions for `ref mut` |  yes
suggestions for direct local assignment (`{ let x = 3; x = 4; }`) | yes (see commits at end)
suggestions for direct field assignment (`{ let x = (3, 4); x.0 = 5; }` | yes (see commits at end)
suggestions for upvars (`let x = 3; let c = \|\| { &mut x; }`) | yes

Note that I added support for a couple of rows via changes that are not strictly part of `fn check_access_permissions`. If desired I can remove those commits from this PR and leave them for a later PR.

Fix #51031
Fix #51032
(bug #51191 needs a little more investigation before closing.)
Fix #51578
This commit is contained in:
bors 2018-06-19 21:31:36 +00:00
commit f28c7aef7f
58 changed files with 670 additions and 263 deletions

View file

@ -170,6 +170,40 @@ impl<'hir> MapEntry<'hir> {
})
}
fn fn_decl(&self) -> Option<&FnDecl> {
match self {
EntryItem(_, _, ref item) => {
match item.node {
ItemFn(ref fn_decl, _, _, _, _, _) => Some(&fn_decl),
_ => None,
}
}
EntryTraitItem(_, _, ref item) => {
match item.node {
TraitItemKind::Method(ref method_sig, _) => Some(&method_sig.decl),
_ => None
}
}
EntryImplItem(_, _, ref item) => {
match item.node {
ImplItemKind::Method(ref method_sig, _) => Some(&method_sig.decl),
_ => None,
}
}
EntryExpr(_, _, ref expr) => {
match expr.node {
ExprClosure(_, ref fn_decl, ..) => Some(&fn_decl),
_ => None,
}
}
_ => None
}
}
fn associated_body(self) -> Option<BodyId> {
match self {
EntryItem(_, _, item) => {
@ -502,6 +536,14 @@ impl<'hir> Map<'hir> {
self.forest.krate.body(id)
}
pub fn fn_decl(&self, node_id: ast::NodeId) -> Option<FnDecl> {
if let Some(entry) = self.find_entry(node_id) {
entry.fn_decl().map(|fd| fd.clone())
} else {
bug!("no entry for node_id `{}`", node_id)
}
}
/// Returns the `NodeId` that corresponds to the definition of
/// which this is the body of, i.e. a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`.

View file

@ -228,7 +228,7 @@ impl<'tcx> Mir<'tcx> {
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
if self.local_decls[local].is_user_variable {
if self.local_decls[local].is_user_variable.is_some() {
None
} else {
Some(local)
@ -241,7 +241,7 @@ impl<'tcx> Mir<'tcx> {
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
if self.local_decls[local].is_user_variable {
if self.local_decls[local].is_user_variable.is_some() {
Some(local)
} else {
None
@ -255,7 +255,7 @@ impl<'tcx> Mir<'tcx> {
(1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
let decl = &self.local_decls[local];
if (decl.is_user_variable || index < self.arg_count + 1)
if (decl.is_user_variable.is_some() || index < self.arg_count + 1)
&& decl.mutability == Mutability::Mut
{
Some(local)
@ -351,7 +351,7 @@ impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
}
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum ClearCrossCrate<T> {
Clear,
Set(T)
@ -382,6 +382,16 @@ pub enum Mutability {
Not,
}
impl From<Mutability> for hir::Mutability {
fn from(m: Mutability) -> Self {
match m {
Mutability::Mut => hir::MutMutable,
Mutability::Not => hir::MutImmutable,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
@ -463,6 +473,33 @@ pub enum LocalKind {
ReturnPointer,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct VarBindingForm {
/// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
pub binding_mode: ty::BindingMode,
/// If an explicit type was provided for this variable binding,
/// this holds the source Span of that type.
///
/// NOTE: If you want to change this to a `HirId`, be wary that
/// doing so breaks incremental compilation (as of this writing),
/// while a `Span` does not cause our tests to fail.
pub opt_ty_info: Option<Span>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum BindingForm {
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
Var(VarBindingForm),
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
ImplicitSelf,
}
CloneTypeFoldableAndLiftImpls! { BindingForm, }
impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info });
impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, });
/// A MIR local.
///
/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
@ -474,8 +511,14 @@ pub struct LocalDecl<'tcx> {
/// Temporaries and the return place are always mutable.
pub mutability: Mutability,
/// True if this corresponds to a user-declared local variable.
pub is_user_variable: bool,
/// Some(binding_mode) if this corresponds to a user-declared local variable.
///
/// This is solely used for local diagnostics when generating
/// warnings/errors when compiling the current crate, and
/// therefore it need not be visible across crates. pnkfelix
/// currently hypothesized we *need* to wrap this in a
/// `ClearCrossCrate` as long as it carries as `HirId`.
pub is_user_variable: Option<ClearCrossCrate<BindingForm>>,
/// True if this is an internal local
///
@ -592,6 +635,45 @@ pub struct LocalDecl<'tcx> {
}
impl<'tcx> LocalDecl<'tcx> {
/// Returns true only if local is a binding that can itself be
/// made mutable via the addition of the `mut` keyword, namely
/// something like the occurrences of `x` in:
/// - `fn foo(x: Type) { ... }`,
/// - `let x = ...`,
/// - or `match ... { C(x) => ... }`
pub fn can_be_made_mutable(&self) -> bool
{
match self.is_user_variable {
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
}))) => true,
// FIXME: might be able to thread the distinction between
// `self`/`mut self`/`&self`/`&mut self` into the
// `BindingForm::ImplicitSelf` variant, (and then return
// true here for solely the first case).
_ => false,
}
}
/// Returns true if local is definitely not a `ref ident` or
/// `ref mut ident` binding. (Such bindings cannot be made into
/// mutable bindings, but the inverse does not necessarily hold).
pub fn is_nonref_binding(&self) -> bool
{
match self.is_user_variable {
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
}))) => true,
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
_ => false,
}
}
/// Create a new `LocalDecl` for a temporary.
#[inline]
pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
@ -605,7 +687,7 @@ impl<'tcx> LocalDecl<'tcx> {
},
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal: false,
is_user_variable: false
is_user_variable: None,
}
}
@ -622,7 +704,7 @@ impl<'tcx> LocalDecl<'tcx> {
},
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal: true,
is_user_variable: false
is_user_variable: None,
}
}
@ -641,7 +723,7 @@ impl<'tcx> LocalDecl<'tcx> {
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal: false,
name: None, // FIXME maybe we do want some name here?
is_user_variable: false
is_user_variable: None,
}
}
}

View file

@ -18,6 +18,8 @@ pub enum BindingMode {
BindByValue(Mutability),
}
CloneTypeFoldableAndLiftImpls! { BindingMode, }
impl BindingMode {
pub fn convert(ba: BindingAnnotation) -> BindingMode {
match ba {

View file

@ -593,11 +593,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err.emit();
}
/// Reports an illegal reassignment; for example, an assignment to
/// (part of) a non-`mut` local that occurs potentially after that
/// local has already been initialized. `place` is the path being
/// assigned; `err_place` is a place providing a reason why
/// `place` is not mutable (e.g. the non-`mut` local `x` in an
/// assignment to `x.f`).
pub(super) fn report_illegal_reassignment(
&mut self,
_context: Context,
(place, span): (&Place<'tcx>, Span),
assigned_span: Span,
err_place: &Place<'tcx>,
) {
let is_arg = if let Place::Local(local) = place {
if let LocalKind::Arg = self.mir.local_kind(*local) {
@ -621,9 +628,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"cannot assign twice to immutable variable"
};
if span != assigned_span {
if is_arg {
err.span_label(assigned_span, "argument not declared as `mut`");
} else {
if !is_arg {
let value_msg = match self.describe_place(place) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
@ -631,6 +636,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err.span_label(assigned_span, format!("first assignment to {}", value_msg));
}
}
if let Place::Local(local) = err_place {
let local_decl = &self.mir.local_decls[*local];
if let Some(name) = local_decl.name {
if local_decl.can_be_made_mutable() {
err.span_label(local_decl.source_info.span,
format!("consider changing this to `mut {}`", name));
}
}
}
err.span_label(span, msg);
err.emit();
}

View file

@ -18,7 +18,7 @@ use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::query::Providers;
use rustc::lint::builtin::UNUSED_MUT;
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{self, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand};
use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
@ -278,7 +278,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// to the set.
let temporary_used_locals: FxHashSet<Local> =
mbcx.used_mut.iter()
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable)
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some())
.cloned()
.collect();
@ -1398,9 +1398,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
) {
debug!("check_if_reassignment_to_immutable_state({:?})", place);
// determine if this path has a non-mut owner (and thus needs checking).
if let Ok(..) = self.is_mutable(place, LocalMutationIsAllowed::No) {
return;
}
let err_place = match self.is_mutable(place, LocalMutationIsAllowed::No) {
Ok(..) => return,
Err(place) => place,
};
debug!(
"check_if_reassignment_to_immutable_state({:?}) - is an imm local",
place
@ -1410,7 +1411,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let init = self.move_data.inits[i];
let init_place = &self.move_data.move_paths[init.path].place;
if places_conflict(self.tcx, self.mir, &init_place, place, Deep) {
self.report_illegal_reassignment(context, (place, span), init.span);
self.report_illegal_reassignment(context, (place, span), init.span, err_place);
break;
}
}
@ -1658,36 +1659,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
fn specialized_description(&self, place:&Place<'tcx>) -> Option<String>{
if let Some(_name) = self.describe_place(place) {
Some(format!("data in a `&` reference"))
} else {
None
}
}
fn get_default_err_msg(&self, place:&Place<'tcx>) -> String{
match self.describe_place(place) {
Some(name) => format!("immutable item `{}`", name),
None => "immutable item".to_owned(),
}
}
fn get_secondary_err_msg(&self, place:&Place<'tcx>) -> String{
match self.specialized_description(place) {
Some(_) => format!("data in a `&` reference"),
None => self.get_default_err_msg(place)
}
}
fn get_primary_err_msg(&self, place:&Place<'tcx>) -> String{
if let Some(name) = self.describe_place(place) {
format!("`{}` is a `&` reference, so the data it refers to cannot be written", name)
} else {
format!("cannot assign through `&`-reference")
}
}
/// Check the permissions for the given place and read or write kind
///
/// Returns true if an error is reported, false otherwise.
@ -1702,7 +1673,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"check_access_permissions({:?}, {:?}, {:?})",
place, kind, is_local_mutation_allowed
);
let mut error_reported = false;
#[derive(Copy, Clone, Debug)]
enum AccessKind {
MutableBorrow,
Mutate,
}
let error_access;
let the_place_err;
match kind {
Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
| Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
@ -1715,91 +1694,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
BorrowKind::Shared => unreachable!(),
};
match self.is_mutable(place, is_local_mutation_allowed) {
Ok(root_place) => self.add_used_mut(root_place, flow_state),
Ok(root_place) => {
self.add_used_mut(root_place, flow_state);
return false;
}
Err(place_err) => {
error_reported = true;
let item_msg = self.get_default_err_msg(place);
let mut err = self.tcx
.cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir);
err.span_label(span, "cannot borrow as mutable");
if place != place_err {
if let Some(name) = self.describe_place(place_err) {
err.note(&format!("the value which is causing this path not to be \
mutable is...: `{}`", name));
}
}
err.emit();
error_access = AccessKind::MutableBorrow;
the_place_err = place_err;
}
}
}
Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
match self.is_mutable(place, is_local_mutation_allowed) {
Ok(root_place) => self.add_used_mut(root_place, flow_state),
Ok(root_place) => {
self.add_used_mut(root_place, flow_state);
return false;
}
Err(place_err) => {
error_reported = true;
let err_info = if let Place::Projection(
box Projection {
base: Place::Local(local),
elem: ProjectionElem::Deref
}
) = *place_err {
let locations = self.mir.find_assignments(local);
if locations.len() > 0 {
let item_msg = if error_reported {
self.get_secondary_err_msg(&Place::Local(local))
} else {
self.get_default_err_msg(place)
};
let sp = self.mir.source_info(locations[0]).span;
let mut to_suggest_span = String::new();
if let Ok(src) =
self.tcx.sess.codemap().span_to_snippet(sp) {
to_suggest_span = src[1..].to_string();
};
Some((sp,
"consider changing this to be a \
mutable reference",
to_suggest_span,
item_msg,
self.get_primary_err_msg(&Place::Local(local))))
} else {
None
}
} else {
None
};
if let Some((err_help_span,
err_help_stmt,
to_suggest_span,
item_msg,
sec_span)) = err_info {
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
err.span_suggestion(err_help_span,
err_help_stmt,
format!("&mut {}", to_suggest_span));
if place != place_err {
err.span_label(span, sec_span);
}
err.emit()
} else {
let item_msg = self.get_default_err_msg(place);
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
err.span_label(span, "cannot mutate");
if place != place_err {
if let Some(name) = self.describe_place(place_err) {
err.note(&format!("the value which is causing this path not \
to be mutable is...: `{}`", name));
}
}
err.emit();
}
error_access = AccessKind::Mutate;
the_place_err = place_err;
}
}
}
Reservation(WriteKind::Move)
| Write(WriteKind::Move)
| Reservation(WriteKind::StorageDeadOrDrop)
@ -1815,15 +1732,174 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
),
);
}
return false;
}
Activation(..) => {
// permission checks are done at Reservation point.
return false;
}
Activation(..) => {} // permission checks are done at Reservation point.
Read(ReadKind::Borrow(BorrowKind::Unique))
| Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
| Read(ReadKind::Borrow(BorrowKind::Shared))
| Read(ReadKind::Copy) => {} // Access authorized
| Read(ReadKind::Copy) => {
// Access authorized
return false;
}
}
error_reported
// 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_nonref_binding() =>
{
let (err_help_span, suggested_code) =
find_place_to_suggest_ampmut(self.tcx, self.mir, *local);
err.span_suggestion(err_help_span,
"consider changing this to be a mutable reference",
suggested_code);
let local_decl = &self.mir.local_decls[*local];
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();
return true;
// Returns the span to highlight and the associated text to
// present when suggesting that the user use an `&mut`.
//
// 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] [= RightHandSideExresssion];
// ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
// (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).
fn find_place_to_suggest_ampmut<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
local: Local) -> (Span, String)
{
// This implementation attempts to emulate AST-borrowck prioritization
// by trying (3.), then (2.) and finally falling back on (1.).
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 {
// pnkfelix inherited code; believes intention is
// highlighted text will always be `&<expr>` and
// thus can transform to `&mut` by slicing off
// first ASCII character and prepending "&mut ".
let borrowed_expr = src[1..].to_string();
return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
}
}
let local_decl = &mir.local_decls[local];
let highlight_span = match local_decl.is_user_variable {
// if this is a variable binding with an explicit type,
// try to highlight that for the suggestion.
Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
opt_ty_info: Some(ty_span), .. }))) => ty_span,
Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"),
// otherwise, just highlight the span associated with
// the (MIR) LocalDecl.
_ => local_decl.source_info.span,
};
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::MutImmutable);
return (highlight_span, format!("&mut {}", ty_mut.ty));
}
}
/// Adds the place into the used mutable variables set

View file

@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})

View file

@ -249,7 +249,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
source_info,
visibility_scope: source_info.scope,
internal: true,
is_user_variable: false
is_user_variable: None,
});
let ptr_temp = Place::Local(ptr_temp);
let block = unpack!(this.into(&ptr_temp, block, ptr));

View file

@ -307,7 +307,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
assert!(!(visibility_scope.is_some() && lint_level.is_explicit()),
"can't have both a visibility and a lint scope at the same time");
let mut scope = self.source_scope;
self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| {
self.visit_bindings(pattern, &mut |this, mutability, name, mode, var, span, ty| {
if visibility_scope.is_none() {
visibility_scope = Some(this.new_source_scope(scope_span,
LintLevel::Inherited,
@ -325,7 +325,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
scope,
};
let visibility_scope = visibility_scope.unwrap();
this.declare_binding(source_info, visibility_scope, mutability, name, var,
this.declare_binding(source_info, visibility_scope, mutability, name, mode, var,
ty, has_guard);
});
visibility_scope
@ -359,11 +359,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>)
where F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>)
{
match *pattern.kind {
PatternKind::Binding { mutability, name, var, ty, ref subpattern, .. } => {
f(self, mutability, name, var, pattern.span, ty);
PatternKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => {
f(self, mutability, name, mode, var, pattern.span, ty);
if let Some(subpattern) = subpattern.as_ref() {
self.visit_bindings(subpattern, f);
}
@ -1118,15 +1118,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
visibility_scope: SourceScope,
mutability: Mutability,
name: Name,
mode: BindingMode,
var_id: NodeId,
var_ty: Ty<'tcx>,
has_guard: ArmHasGuard)
{
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, visibility_scope={:?}, \
source_info={:?})",
var_id, name, var_ty, visibility_scope, source_info);
debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
visibility_scope={:?}, source_info={:?})",
var_id, name, mode, var_ty, visibility_scope, source_info);
let tcx = self.hir.tcx();
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()),
};
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty.clone(),
@ -1134,7 +1139,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
source_info,
visibility_scope,
internal: false,
is_user_variable: true,
is_user_variable: Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode,
// hypothetically, `visit_bindings` could try to unzip
// an outermost hir::Ty as we descend, matching up
// idents in pat; but complex w/ unclear UI payoff.
// Instead, just abandon providing diagnostic info.
opt_ty_info: None,
}))),
};
let for_arm_body = self.local_decls.push(local.clone());
let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() {
@ -1145,8 +1157,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
name: Some(name),
source_info,
visibility_scope,
// FIXME: should these secretly injected ref_for_guard's be marked as `internal`?
internal: false,
is_user_variable: true,
is_user_variable: None,
});
LocalsForNode::Three { val_for_guard, ref_for_guard, for_arm_body }
} else {

View file

@ -70,11 +70,11 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
// HACK(eddyb) Avoid having RustCall on closures,
// as it adds unnecessary (and wrong) auto-tupling.
abi = Abi::Rust;
Some((liberated_closure_env_ty(tcx, id, body_id), None))
Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None))
}
ty::TyGenerator(..) => {
let gen_ty = tcx.body_tables(body_id).node_id_to_type(fn_hir_id);
Some((gen_ty, None))
Some(ArgInfo(gen_ty, None, None, None))
}
_ => None,
};
@ -91,7 +91,23 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
let owner_id = tcx.hir.body_owner(body_id);
let opt_ty_info;
let self_arg;
if let Some(ref fn_decl) = tcx.hir.fn_decl(owner_id) {
let ty_hir_id = fn_decl.inputs[index].hir_id;
let ty_span = tcx.hir.span(tcx.hir.hir_to_node_id(ty_hir_id));
opt_ty_info = Some(ty_span);
self_arg = if index == 0 && fn_decl.has_implicit_self {
Some(ImplicitSelfBinding)
} else {
None
};
} else {
opt_ty_info = None;
self_arg = None;
}
ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg)
});
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
@ -433,6 +449,13 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
struct ImplicitSelfBinding;
struct ArgInfo<'gcx>(Ty<'gcx>,
Option<Span>,
Option<&'gcx hir::Pat>,
Option<ImplicitSelfBinding>);
fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
arguments: A,
@ -442,7 +465,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
yield_ty: Option<Ty<'gcx>>,
body: &'gcx hir::Body)
-> Mir<'tcx>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
where A: Iterator<Item=ArgInfo<'gcx>>
{
let arguments: Vec<_> = arguments.collect();
@ -642,13 +665,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn args_and_body(&mut self,
mut block: BasicBlock,
arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
arguments: &[ArgInfo<'gcx>],
argument_scope: region::Scope,
ast_body: &'gcx hir::Expr)
-> BlockAnd<()>
{
// Allocate locals for the function arguments
for &(ty, pattern) in arguments.iter() {
for &ArgInfo(ty, _, pattern, _) in arguments.iter() {
// If this is a simple binding pattern, give the local a nice name for debuginfo.
let mut name = None;
if let Some(pat) = pattern {
@ -668,16 +691,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
visibility_scope: source_info.scope,
name,
internal: false,
is_user_variable: false,
is_user_variable: None,
});
}
let mut scope = None;
// Bind the argument patterns
for (index, &(ty, pattern)) in arguments.iter().enumerate() {
for (index, arg_info) in arguments.iter().enumerate() {
// Function arguments always get the first Local indices after the return place
let local = Local::new(index + 1);
let place = Place::Local(local);
let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info;
if let Some(pattern) = pattern {
let pattern = self.hir.pattern_from_hir(pattern);
@ -686,6 +710,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Don't introduce extra copies for simple bindings
PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => {
self.local_decls[local].mutability = mutability;
self.local_decls[local].is_user_variable =
if let Some(ImplicitSelfBinding) = self_binding {
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf))
} else {
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode, opt_ty_info })))
};
self.var_indices.insert(var, LocalsForNode::One(local));
}
_ => {

View file

@ -144,7 +144,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
source_info,
visibility_scope: source_info.scope,
internal: false,
is_user_variable: false
is_user_variable: None,
}
}

View file

@ -303,7 +303,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
source_info,
visibility_scope: source_info.scope,
internal: false,
is_user_variable: false,
is_user_variable: None,
};
let new_ret_local = Local::new(mir.local_decls.len());
mir.local_decls.push(new_ret);
@ -644,7 +644,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
source_info,
visibility_scope: source_info.scope,
internal: false,
is_user_variable: false,
is_user_variable: None,
};
make_generator_state_argument_indirect(tcx, def_id, &mut mir);
@ -660,7 +660,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
source_info,
visibility_scope: source_info.scope,
internal: false,
is_user_variable: false,
is_user_variable: None,
};
no_landing_pads(tcx, &mut mir);

View file

@ -13,6 +13,7 @@
fn test() {
let v: isize;
//[mir]~^ NOTE consider changing this to `mut v`
v = 1; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
println!("v={}", v);

View file

@ -27,7 +27,7 @@ fn indirect_write_to_imm_box() {
let y: Box<_> = box &mut x;
let p = &y;
***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference
//[mir]~^ ERROR cannot assign to data in a `&` reference
//[mir]~^ ERROR cannot assign to `***p`
drop(p);
}

View file

@ -70,6 +70,6 @@ fn main() {
};
s[2] = 20;
//[ast]~^ ERROR cannot assign to immutable indexed content
//[mir]~^^ ERROR cannot assign to immutable item
//[mir]~^^ ERROR cannot assign to data in a `&` reference
drop(rs);
}

View file

@ -13,6 +13,7 @@
fn test_drop_replace() {
let b: Box<isize>;
//[mir]~^ NOTE consider changing this to `mut b`
b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
@ -24,6 +25,7 @@ fn test_drop_replace() {
fn test_call() {
let b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
//[mir]~| NOTE consider changing this to `mut b`
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `b`
//[ast]~| NOTE cannot assign twice to immutable
@ -31,7 +33,7 @@ fn test_call() {
}
fn test_args(b: Box<i32>) { //[ast]~ NOTE first assignment
//[mir]~^ NOTE argument not declared as `mut`
//[mir]~^ NOTE consider changing this to `mut b`
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign to immutable argument `b`
//[ast]~| NOTE cannot assign twice to immutable

View file

@ -13,6 +13,7 @@
fn test() {
let v: isize;
//[mir]~^ NOTE consider changing this to `mut v`
loop {
v = 1; //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `v`

View file

@ -13,6 +13,7 @@
fn test() {
let v: isize;
//[mir]~^ NOTE consider changing this to `mut v`
v = 2; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
v += 1; //[ast]~ ERROR cannot assign twice to immutable variable

View file

@ -14,6 +14,7 @@
fn test() {
let b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
//[mir]~| NOTE consider changing this to `mut b`
drop(b);
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `b`

View file

@ -14,6 +14,7 @@
fn test() {
let v: isize = 1; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
//[mir]~| NOTE consider changing this to `mut v`
v.clone();
v = 2; //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `v`

View file

@ -23,6 +23,6 @@ fn main() {
call(|| {
counter += 1;
//[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure
//[mir]~^^ ERROR cannot assign to immutable item `counter`
//[mir]~^^ ERROR cannot assign to `counter`
});
}

View file

@ -0,0 +1,14 @@
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/asm-out-assign-imm.rs:33:9
|
LL | let x: isize;
| - consider changing this to `mut x`
LL | x = 1;
| ----- first assignment to `x`
...
LL | asm!("mov $1, $0" : "=r"(x) : "r"(5));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0384`.

View file

@ -17,6 +17,9 @@ LL | | x; //~ value moved here
error[E0596]: cannot borrow immutable item `y` as mutable
--> $DIR/augmented-assignments.rs:30:5
|
LL | let y = Int(2);
| - help: consider changing this to be mutable: `mut y`
LL | //~^ consider changing this to `mut y`
LL | y //~ error: cannot borrow immutable local variable `y` as mutable
| ^ cannot borrow as mutable

View file

@ -10,7 +10,7 @@ error[E0384]: cannot assign to immutable argument `_x` (Mir)
--> $DIR/immutable-arg.rs:14:5
|
LL | fn foo(_x: u32) {
| -- argument not declared as `mut`
| -- consider changing this to `mut _x`
LL | _x = 4;
| ^^^^^^ cannot assign to immutable argument

View file

@ -14,13 +14,13 @@ error[E0594]: cannot assign to immutable item `x`
--> $DIR/issue-45983.rs:17:18
|
LL | give_any(|y| x = Some(y));
| ^^^^^^^^^^^ cannot mutate
|
= note: the value which is causing this path not to be mutable is...: `x`
| ^^^^^^^^^^^ 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

View file

@ -1,6 +1,8 @@
error[E0596]: cannot borrow immutable item `b` as mutable
--> $DIR/mut-borrow-of-mut-ref.rs:18:7
|
LL | fn f(b: &mut i32) {
| - help: consider changing this to be mutable: `mut b`
LL | g(&mut b) //~ ERROR cannot borrow
| ^^^^^^ cannot borrow as mutable

View file

@ -1,6 +1,9 @@
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/huge_multispan_highlight.rs:100:13
|
LL | let x = "foo";
| - help: consider changing this to be mutable: `mut x`
...
LL | let y = &mut x; //~ ERROR cannot borrow
| ^^^^^^ cannot borrow as mutable

View file

@ -2,7 +2,9 @@ error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/command-line-diagnostics.rs:16:5
|
LL | let x = 42;
| -- first assignment to `x`
| - -- first assignment to `x`
| |
| consider changing this to `mut x`
LL | x = 43;
| ^^^^^^ cannot assign twice to immutable variable

View file

@ -7,6 +7,8 @@ LL | (&mut self).bar(); //~ ERROR cannot borrow
error[E0596]: cannot borrow immutable item `self` as mutable
--> $DIR/issue-31424.rs:23:9
|
LL | fn bar(self: &mut Self) {
| ---- help: consider changing this to be mutable: `mut self`
LL | (&mut self).bar(); //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable

View file

@ -2,7 +2,10 @@ error[E0596]: cannot borrow immutable item `self` as mutable
--> $DIR/issue-34126.rs:16:18
|
LL | self.run(&mut self); //~ ERROR cannot borrow
| ^^^^^^^^^ cannot borrow as mutable
| ^^^^^^^^^
| |
| cannot borrow as mutable
| try removing `&mut` here
error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
--> $DIR/issue-34126.rs:16:18

View file

@ -2,7 +2,10 @@ error[E0596]: cannot borrow immutable item `key` as mutable
--> $DIR/issue-34337.rs:16:9
|
LL | get(&mut key); //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
| ^^^^^^^^
| |
| cannot borrow as mutable
| try removing `&mut` here
error: aborting due to previous error

View file

@ -1,16 +1,18 @@
error[E0596]: cannot borrow immutable item `f.v` as mutable
--> $DIR/issue-35937.rs:17:5
|
LL | let f = Foo { v: Vec::new() };
| - help: consider changing this to be mutable: `mut f`
LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow
| ^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `f`
error[E0384]: cannot assign twice to immutable variable `s.x`
--> $DIR/issue-35937.rs:26:5
|
LL | let s = S { x: 42 };
| ----------- first assignment to `s.x`
| - ----------- first assignment to `s.x`
| |
| consider changing this to `mut s`
LL | s.x += 1; //~ ERROR cannot assign
| ^^^^^^^^ cannot assign twice to immutable variable
@ -18,7 +20,10 @@ error[E0384]: cannot assign twice to immutable variable `s.x`
--> $DIR/issue-35937.rs:30:5
|
LL | fn bar(s: S) {
| - first assignment to `s.x`
| -
| |
| first assignment to `s.x`
| consider changing this to `mut s`
LL | s.x += 1; //~ ERROR cannot assign
| ^^^^^^^^ cannot assign twice to immutable variable

View file

@ -2,7 +2,10 @@ error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/issue-37139.rs:22:18
|
LL | test(&mut x); //~ ERROR cannot borrow immutable
| ^^^^^^ cannot borrow as mutable
| ^^^^^^
| |
| cannot borrow as mutable
| try removing `&mut` here
error: aborting due to previous error

View file

@ -1,10 +1,10 @@
error[E0596]: cannot borrow immutable item `*self.s` as mutable
--> $DIR/issue-38147-1.rs:27:9
|
LL | fn f(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut Foo<'_>`
LL | self.s.push('x'); //~ ERROR cannot borrow data mutably
| ^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*self`
| ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to previous error

View file

@ -1,10 +1,10 @@
error[E0596]: cannot borrow immutable item `*f.s` as mutable
--> $DIR/issue-38147-4.rs:16:5
|
LL | fn f(x: usize, f: &Foo) {
| ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>`
LL | f.s.push('x'); //~ ERROR cannot borrow data mutably
| ^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*f`
| ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to previous error

View file

@ -1,96 +1,100 @@
error[E0596]: cannot borrow immutable item `z.x` as mutable
--> $DIR/issue-39544.rs:21:13
|
LL | let z = Z { x: X::Y };
| - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `z`
error[E0596]: cannot borrow immutable item `self.x` as mutable
--> $DIR/issue-39544.rs:26:17
|
LL | fn foo<'z>(&'z self) {
| -------- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*self`
| ^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:30:17
|
LL | fn foo1(&self, other: &Z) {
| ----- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*self`
| ^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:31:17
|
LL | fn foo1(&self, other: &Z) {
| -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*other`
| ^^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:35:17
|
LL | fn foo2<'a>(&'a self, other: &Z) {
| -------- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*self`
| ^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:36:17
|
LL | fn foo2<'a>(&'a self, other: &Z) {
| -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*other`
| ^^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:40:17
|
LL | fn foo3<'a>(self: &'a Self, other: &Z) {
| -------- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*self`
| ^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:41:17
|
LL | fn foo3<'a>(self: &'a Self, other: &Z) {
| -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*other`
| ^^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:45:17
|
LL | fn foo4(other: &Z) {
| -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*other`
| ^^^^^^^^^^^^ `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
--> $DIR/issue-39544.rs:51:13
|
LL | pub fn with_arg(z: Z, w: &Z) {
| - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `z`
error[E0596]: cannot borrow immutable item `w.x` as mutable
--> $DIR/issue-39544.rs:52:13
|
LL | pub fn with_arg(z: Z, w: &Z) {
| -- help: consider changing this to be a mutable reference: `&mut Z`
LL | let _ = &mut z.x; //~ ERROR cannot borrow
LL | let _ = &mut w.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*w`
| ^^^^^^^^ `w` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0594]: cannot assign to immutable item `*x.0`
error[E0594]: cannot assign to `*x.0` which is behind a `&` reference
--> $DIR/issue-39544.rs:58:5
|
LL | *x.0 = 1;
| ^^^^^^^^ cannot mutate
| ^^^^^^^^ cannot assign
error: aborting due to 12 previous errors

View file

@ -1,8 +1,10 @@
error[E0596]: cannot borrow immutable item `*buf` as mutable
--> $DIR/issue-40823.rs:13:5
|
LL | let mut buf = &[1, 2, 3, 4];
| ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]`
LL | buf.iter_mut(); //~ ERROR cannot borrow immutable borrowed content
| ^^^ cannot borrow as mutable
| ^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to previous error

View file

@ -1,4 +1,4 @@
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference
--> $DIR/E0389.rs:18:5
|
LL | let fancy_ref = &(&mut fancy);

View file

@ -1,10 +1,10 @@
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/issue-36400.rs:15:7
|
LL | let x = Box::new(3);
| - help: consider changing this to be mutable: `mut x`
LL | f(&mut *x); //~ ERROR cannot borrow immutable
| ^^^^^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `x`
error: aborting due to previous error

View file

@ -18,7 +18,7 @@ error[E0384]: cannot assign to immutable argument `y`
--> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:5
|
LL | fn foo(mut x: Ref, y: &u32) {
| - argument not declared as `mut`
| - consider changing this to `mut y`
LL | y = x.b; //~ ERROR lifetime mismatch
| ^^^^^^^ cannot assign to immutable argument

View file

@ -15,6 +15,8 @@ LL | y.push(z); //~ ERROR lifetime mismatch
error[E0596]: cannot borrow immutable item `y` 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) {
| - help: consider changing this to be mutable: `mut y`
LL | y.push(z); //~ ERROR lifetime mismatch
| ^ cannot borrow as mutable

View file

@ -15,6 +15,8 @@ LL | y.push(z); //~ ERROR lifetime mismatch
error[E0596]: cannot borrow immutable item `y` as mutable
--> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:3
|
LL | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
| - help: consider changing this to be mutable: `mut y`
LL | y.push(z); //~ ERROR lifetime mismatch
| ^ cannot borrow as mutable

View file

@ -32,6 +32,9 @@ LL | x = 2; //~ ERROR (Ast) [E0384]
error[E0384]: cannot assign twice to immutable variable `x` (Mir)
--> $DIR/liveness-assign-imm-local-notes.rs:23:9
|
LL | let x;
| - consider changing this to `mut x`
...
LL | x = 2;
| ----- first assignment to `x`
LL | x = 3; //~ ERROR (Ast) [E0384]
@ -40,6 +43,9 @@ LL | x = 3; //~ ERROR (Ast) [E0384]
error[E0384]: cannot assign twice to immutable variable `x` (Mir)
--> $DIR/liveness-assign-imm-local-notes.rs:35:13
|
LL | let x;
| - consider changing this to `mut x`
...
LL | x = 2;
| ----- first assignment to `x`
LL | x = 3; //~ ERROR (Ast) [E0384]
@ -48,12 +54,18 @@ LL | x = 3; //~ ERROR (Ast) [E0384]
error[E0384]: cannot assign twice to immutable variable `x` (Mir)
--> $DIR/liveness-assign-imm-local-notes.rs:45:13
|
LL | let x;
| - consider changing this to `mut x`
...
LL | x = 1; //~ ERROR (Ast) [E0384]
| ^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `x` (Mir)
--> $DIR/liveness-assign-imm-local-notes.rs:48:13
|
LL | let x;
| - consider changing this to `mut x`
...
LL | x = 1; //~ ERROR (Ast) [E0384]
| ----- first assignment to `x`
...

View file

@ -1,6 +1,8 @@
error[E0596]: cannot borrow immutable item `foo` as mutable
--> $DIR/span-covering-argument-1.rs:15:14
|
LL | let $s = 0;
| -- help: consider changing this to be mutable: `mut foo`
LL | *&mut $s = 0;
| ^^^^^^^ cannot borrow as mutable
...

View file

@ -1,4 +1,4 @@
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference
--> $DIR/issue-47388.rs:18:5
|
LL | let fancy_ref = &(&mut fancy);

View file

@ -0,0 +1,26 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests how we behave when the user attempts to mutate an immutable
// binding that was introduced by either `ref` or `ref mut`
// patterns.
//
// Such bindings cannot be made mutable via the mere addition of the
// `mut` keyword, and thus we want to check that the compiler does not
// suggest doing so.
fn main() {
let (mut one_two, mut three_four) = ((1, 2), (3, 4));
let &mut (ref a, ref mut b) = &mut one_two;
a = &three_four.0;
//~^ ERROR cannot assign twice to immutable variable `a` [E0384]
b = &mut three_four.1;
//~^ ERROR cannot assign twice to immutable variable `b` [E0384]
}

View file

@ -0,0 +1,20 @@
error[E0384]: cannot assign twice to immutable variable `a`
--> $DIR/reassign-ref-mut.rs:22:5
|
LL | let &mut (ref a, ref mut b) = &mut one_two;
| ----- first assignment to `a`
LL | a = &three_four.0;
| ^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
--> $DIR/reassign-ref-mut.rs:24:5
|
LL | let &mut (ref a, ref mut b) = &mut one_two;
| --------- first assignment to `b`
...
LL | b = &mut three_four.1;
| ^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0384`.

View file

@ -1,26 +1,20 @@
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*x` which is behind a `&` reference
--> $DIR/enum.rs:19:5
|
LL | let Wrap(x) = &Wrap(3);
| - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*x` which is behind a `&` reference
--> $DIR/enum.rs:23:9
|
LL | if let Some(x) = &Some(3) {
| - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*x` which is behind a `&` reference
--> $DIR/enum.rs:29:9
|
LL | while let Some(x) = &Some(3) {
| - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error: aborting due to 3 previous errors

View file

@ -1,26 +1,20 @@
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*n` which is behind a `&` reference
--> $DIR/explicit-mut.rs:17:13
|
LL | Some(n) => {
| - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*n` which is behind a `&` reference
--> $DIR/explicit-mut.rs:25:13
|
LL | Some(n) => {
| - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error[E0594]: cannot assign to data in a `&` reference
error[E0594]: cannot assign to `*n` which is behind a `&` reference
--> $DIR/explicit-mut.rs:33:13
|
LL | Some(n) => {
| - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
| ^^^^^^^
| ^^^^^^^ cannot assign
error: aborting due to 3 previous errors

View file

@ -1,50 +1,66 @@
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
|
LL | fn deref_mut_field1(x: Own<Point>) {
| - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut x.y; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10
|
LL | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
| ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | &mut x.y //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
|
LL | fn assign_field1<'a>(x: Own<Point>) {
| - help: consider changing this to be mutable: `mut x`
LL | x.y = 3; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5
|
LL | fn assign_field2<'a>(x: &'a Own<Point>) {
| -------------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | x.y = 3; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
|
LL | fn deref_mut_method1(x: Own<Point>) {
| - help: consider changing this to be mutable: `mut x`
LL | x.set(0, 0); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5
|
LL | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
| ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | x.y_mut() //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
|
LL | fn assign_method1<'a>(x: Own<Point>) {
| - help: consider changing this to be mutable: `mut x`
LL | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6
|
LL | fn assign_method2<'a>(x: &'a Own<Point>) {
| -------------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
LL | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to 8 previous errors

View file

@ -1,26 +1,34 @@
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
|
LL | fn deref_mut1(x: Own<isize>) {
| - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut *x; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11
|
LL | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
| -------------- help: consider changing this to be a mutable reference: `&mut Own<isize>`
LL | &mut **x //~ ERROR cannot borrow
| ^^ cannot borrow as mutable
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
|
LL | fn assign1<'a>(x: Own<isize>) {
| - help: consider changing this to be mutable: `mut x`
LL | *x = 3; //~ ERROR cannot borrow
| ^ cannot borrow as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6
|
LL | fn assign2<'a>(x: &'a Own<isize>) {
| -------------- help: consider changing this to be a mutable reference: `&mut Own<isize>`
LL | **x = 3; //~ ERROR cannot borrow
| ^^ cannot borrow as mutable
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to 4 previous errors

View file

@ -15,16 +15,18 @@ LL | | }));
error[E0596]: cannot borrow immutable item `*f` as mutable
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5
|
LL | fn test2<F>(f: &F) where F: FnMut() {
| -- help: consider changing this to be a mutable reference: `&mut F`
LL | (*f)();
| ^^^^ cannot borrow as mutable
| ^^^^ `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
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
|
LL | fn test4(f: &Test) {
| ----- help: consider changing this to be a mutable reference: `&mut Test<'_>`
LL | f.f.call_mut(())
| ^^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*f`
| ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0507]: cannot move out of borrowed content
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13

View file

@ -1,8 +1,11 @@
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5
|
LL | fn b(x: &Foo) {
| ---- help: consider changing this to be a mutable reference: `&mut Foo`
LL | x.f();
LL | x.h(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to previous error

View file

@ -1,8 +1,10 @@
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-fn-in-const-b.rs:17:9
|
LL | fn broken(x: &Vec<String>) {
| ------------ help: consider changing this to be a mutable reference: `&mut std::vec::Vec<std::string::String>`
LL | x.push(format!("this is broken"));
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to previous error

View file

@ -1,16 +1,20 @@
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-object-mutability.rs:19:5
|
LL | fn borrowed_receiver(x: &Foo) {
| ---- help: consider changing this to be a mutable reference: `&mut Foo`
LL | x.borrowed();
LL | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `*x` as mutable
--> $DIR/borrowck-object-mutability.rs:29:5
|
LL | fn owned_receiver(x: Box<Foo>) {
| - help: consider changing this to be mutable: `mut x`
LL | x.borrowed();
LL | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `x`
error: aborting due to 2 previous errors

View file

@ -1,20 +1,26 @@
error[E0596]: cannot borrow immutable item `*a` as mutable
--> $DIR/mut-arg-hint.rs:13:9
|
LL | fn foo(mut a: &String) {
| ------- help: consider changing this to be a mutable reference: `&mut std::string::String`
LL | a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content
| ^ cannot borrow as mutable
| ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `*a` as mutable
--> $DIR/mut-arg-hint.rs:18:5
|
LL | pub fn foo<'a>(mut a: &'a String) {
| ---------- help: consider changing this to be a mutable reference: `&mut std::string::String`
LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content
| ^ cannot borrow as mutable
| ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `*a` as mutable
--> $DIR/mut-arg-hint.rs:25:9
|
LL | pub fn foo(mut a: &String) {
| ------- help: consider changing this to be a mutable reference: `&mut std::string::String`
LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content
| ^ cannot borrow as mutable
| ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to 3 previous errors

View file

@ -2,7 +2,7 @@ error[E0594]: cannot assign to immutable item `y`
--> $DIR/closure-immutable-outer-variable.rs:21:26
|
LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable
| ^^^^^^^^^ cannot mutate
| ^^^^^^^^^ cannot assign
error: aborting due to previous error

View file

@ -1,8 +1,8 @@
error[E0594]: cannot assign to immutable item `x`
error[E0594]: cannot assign to `x` which is behind a `&` reference
--> $DIR/fn-closure-mutable-capture.rs:15:17
|
LL | bar(move || x = 1);
| ^^^^^ cannot mutate
| ^^^^^ cannot assign
error: aborting due to previous error

View file

@ -1,18 +1,18 @@
error[E0596]: cannot borrow immutable item `**t` as mutable
--> $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 {
| --------------- help: consider changing this to be a mutable reference: `&mut &mut i32`
LL | *t //~ ERROR
| ^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*t`
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow immutable item `**t` as mutable
--> $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 {
| --------------- help: consider changing this to be a mutable reference: `&mut &mut i32`
LL | {*t} //~ ERROR
| ^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*t`
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to 2 previous errors