diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 19d121843cbfa..ec3954f734923 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -271,6 +271,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.access_lvalue(context, (output, span), (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, flow_state); self.check_if_path_is_moved(context, InitializationRequiringAction::Use, (output, span), flow_state); @@ -300,7 +301,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx StatementKind::StorageDead(local) => { self.access_lvalue(ContextKind::StorageDead.new(location), (&Lvalue::Local(local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state); + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state); } } } @@ -322,6 +325,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.access_lvalue(ContextKind::Drop.new(loc), (drop_lvalue, span), (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, flow_state); } TerminatorKind::DropAndReplace { location: ref drop_lvalue, @@ -391,6 +395,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ContextKind::StorageDead.new(loc), (&root_lvalue, self.mir.source_info(borrow.location).span), (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, flow_state ); } @@ -399,6 +404,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ContextKind::StorageDead.new(loc), (&root_lvalue, self.mir.source_info(borrow.location).span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, flow_state ); } @@ -445,6 +451,8 @@ enum ShallowOrDeep { Deep, } +/// Kind of access to a value: read or write +/// (For informational purposes only) #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ReadOrWrite { /// From the RFC: "A *read* means that the existing data may be @@ -457,12 +465,16 @@ enum ReadOrWrite { Write(WriteKind), } +/// Kind of read access to a value +/// (For informational purposes only) #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ReadKind { Borrow(BorrowKind), Copy, } +/// Kind of write access to a value +/// (For informational purposes only) #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteKind { StorageDeadOrDrop, @@ -471,6 +483,20 @@ enum WriteKind { Move, } +/// When checking permissions for an lvalue access, this flag is used to indicate that an immutable +/// local lvalue can be mutated. +/// +/// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications: +/// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()` +/// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and +/// `is_declared_mutable()` +/// - Take flow state into consideration in `is_assignable()` for local variables +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum LocalMutationIsAllowed { + Yes, + No +} + #[derive(Copy, Clone)] enum InitializationRequiringAction { Update, @@ -510,6 +536,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context: Context, lvalue_span: (&Lvalue<'tcx>, Span), kind: (ShallowOrDeep, ReadOrWrite), + is_local_mutation_allowed: LocalMutationIsAllowed, flow_state: &InProgress<'cx, 'gcx, 'tcx>) { let (sd, rw) = kind; @@ -526,9 +553,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } // Check permissions - self.check_access_permissions(lvalue_span, rw); + let mut error_reported = self.check_access_permissions(lvalue_span, + rw, + is_local_mutation_allowed); - let mut error_reported = false; self.each_borrow_involving_path( context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| { match (rw, borrow.kind) { @@ -614,7 +642,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - self.access_lvalue(context, lvalue_span, (kind, Write(WriteKind::Mutate)), flow_state); + self.access_lvalue(context, + lvalue_span, + (kind, Write(WriteKind::Mutate)), + LocalMutationIsAllowed::Yes, + flow_state); // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state(context, lvalue_span, flow_state); @@ -632,7 +664,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { BorrowKind::Unique | BorrowKind::Mut => (Deep, Write(WriteKind::MutableBorrow(bk))), }; - self.access_lvalue(context, (lvalue, span), access_kind, flow_state); + self.access_lvalue(context, + (lvalue, span), + access_kind, + LocalMutationIsAllowed::No, + flow_state); self.check_if_path_is_moved(context, InitializationRequiringAction::Borrow, (lvalue, span), flow_state); } @@ -651,8 +687,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Rvalue::Discriminant(..) => ArtificialField::Discriminant, _ => unreachable!(), }; - self.access_lvalue( - context, (lvalue, span), (Shallow(Some(af)), Read(ReadKind::Copy)), flow_state); + self.access_lvalue(context, + (lvalue, span), + (Shallow(Some(af)), Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state); self.check_if_path_is_moved(context, InitializationRequiringAction::Use, (lvalue, span), flow_state); } @@ -690,6 +729,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.access_lvalue(context, (lvalue, span), (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, flow_state); // Finally, check if path was already moved. @@ -701,6 +741,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.access_lvalue(context, (lvalue, span), (Deep, Write(WriteKind::Move)), + LocalMutationIsAllowed::Yes, flow_state); // Finally, check if path was already moved. @@ -735,9 +776,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } Lvalue::Static(ref static_) => { // mutation of non-mut static is always illegal, - // independent of dataflow. + // independent of dataflow. However it will be catched by + // `check_access_permissions()`, we call delay_span_bug here + // to be sure that no case has been missed if !self.tcx.is_static_mut(static_.def_id) { - self.report_assignment_to_static(context, (lvalue, span)); + let item_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("immutable static item `{}`", name), + None => "immutable static item".to_owned() + }; + self.tcx.sess.delay_span_bug(span, + &format!("cannot assign to {}, should have been caught by \ + `check_access_permissions()`", item_msg)); } return; } @@ -949,41 +998,101 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// Check the permissions for the given lvalue and read or write kind - fn check_access_permissions(&self, (lvalue, span): (&Lvalue<'tcx>, Span), kind: ReadOrWrite) { + /// + /// Returns true if an error is reported, false otherwise. + fn check_access_permissions(&self, + (lvalue, span): (&Lvalue<'tcx>, Span), + kind: ReadOrWrite, + is_local_mutation_allowed: LocalMutationIsAllowed) + -> bool { + debug!("check_access_permissions({:?}, {:?}, {:?})", + lvalue, kind, is_local_mutation_allowed); + let mut error_reported = false; match kind { Write(WriteKind::MutableBorrow(BorrowKind::Unique)) => { if let Err(_lvalue_err) = self.is_unique(lvalue) { - span_bug!(span, "&unique borrow for `{}` should not fail", - self.describe_lvalue(lvalue)); + span_bug!(span, "&unique borrow for {:?} should not fail", lvalue); } }, Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => { - if let Err(lvalue_err) = self.is_mutable(lvalue) { + if let Err(lvalue_err) = self.is_mutable(lvalue, is_local_mutation_allowed) { + error_reported = true; + + let item_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("immutable item `{}`", name), + None => "immutable item".to_owned() + }; + let mut err = self.tcx.cannot_borrow_path_as_mutable(span, - &format!("immutable item `{}`", - self.describe_lvalue(lvalue)), + &item_msg, Origin::Mir); err.span_label(span, "cannot borrow as mutable"); if lvalue != lvalue_err { - err.note(&format!("Value not mutable causing this error: `{}`", - self.describe_lvalue(lvalue_err))); + if let Some(name) = self.describe_lvalue(lvalue_err) { + err.note(&format!("Value not mutable causing this error: `{}`", name)); + } + } + + err.emit(); + } + }, + Write(WriteKind::Mutate) => { + if let Err(lvalue_err) = self.is_mutable(lvalue, is_local_mutation_allowed) { + error_reported = true; + + let item_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("immutable item `{}`", name), + None => "immutable item".to_owned() + }; + + let mut err = self.tcx.cannot_assign(span, + &item_msg, + Origin::Mir); + err.span_label(span, "cannot mutate"); + + if lvalue != lvalue_err { + if let Some(name) = self.describe_lvalue(lvalue_err) { + err.note(&format!("Value not mutable causing this error: `{}`", name)); + } } err.emit(); } }, - _ => {}// Access authorized + Write(WriteKind::Move) | + Write(WriteKind::StorageDeadOrDrop) | + Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => { + if let Err(_lvalue_err) = self.is_mutable(lvalue, is_local_mutation_allowed) { + self.tcx.sess.delay_span_bug(span, + &format!("Accessing `{:?}` with the kind `{:?}` shouldn't be possible", + lvalue, + kind)); + } + }, + Read(ReadKind::Borrow(BorrowKind::Unique)) | + Read(ReadKind::Borrow(BorrowKind::Mut)) | + Read(ReadKind::Borrow(BorrowKind::Shared)) | + Read(ReadKind::Copy) => {} // Access authorized } + + error_reported } /// Can this value be written or borrowed mutably - fn is_mutable<'d>(&self, lvalue: &'d Lvalue<'tcx>) -> Result<(), &'d Lvalue<'tcx>> { + fn is_mutable<'d>(&self, + lvalue: &'d Lvalue<'tcx>, + is_local_mutation_allowed: LocalMutationIsAllowed) + -> Result<(), &'d Lvalue<'tcx>> { match *lvalue { Lvalue::Local(local) => { let local = &self.mir.local_decls[local]; match local.mutability { - Mutability::Not => Err(lvalue), + Mutability::Not => + match is_local_mutation_allowed { + LocalMutationIsAllowed::Yes => Ok(()), + LocalMutationIsAllowed::No => Err(lvalue), + }, Mutability::Mut => Ok(()) } }, @@ -1001,7 +1110,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // `Box` owns its content, so mutable if its location is mutable if base_ty.is_box() { - return self.is_mutable(&proj.base); + return self.is_mutable(&proj.base, LocalMutationIsAllowed::No); } // Otherwise we check the kind of deref to decide @@ -1035,7 +1144,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ProjectionElem::ConstantIndex{..} | ProjectionElem::Subslice{..} | ProjectionElem::Downcast(..) => - self.is_mutable(&proj.base) + self.is_mutable(&proj.base, LocalMutationIsAllowed::No) } } } @@ -1343,12 +1452,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { |moi| curr_move_out.contains(moi)).collect::>(); if mois.is_empty() { + let item_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("`{}`", name), + None => "value".to_owned() + }; self.tcx.cannot_act_on_uninitialized_variable(span, desired_action.as_noun(), - &self.describe_lvalue(lvalue), + &self.describe_lvalue(lvalue) + .unwrap_or("_".to_owned()), Origin::Mir) - .span_label(span, format!("use of possibly uninitialized `{}`", - self.describe_lvalue(lvalue))) + .span_label(span, format!("use of possibly uninitialized {}", item_msg)) .emit(); } else { let msg = ""; //FIXME: add "partially " or "collaterally " @@ -1356,7 +1469,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut err = self.tcx.cannot_act_on_moved_value(span, desired_action.as_noun(), msg, - &self.describe_lvalue(lvalue), + &self.describe_lvalue(lvalue) + .unwrap_or("_".to_owned()), Origin::Mir); err.span_label(span, format!("value {} here after move", @@ -1381,14 +1495,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _context: Context, (lvalue, span): (&Lvalue<'tcx>, Span), borrow: &BorrowData<'tcx>) { + let value_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("`{}`", name), + None => "value".to_owned() + }; + let borrow_msg = match self.describe_lvalue(&borrow.lvalue) { + Some(name) => format!("`{}`", name), + None => "value".to_owned() + }; self.tcx.cannot_move_when_borrowed(span, - &self.describe_lvalue(lvalue), + &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()), Origin::Mir) .span_label(self.retrieve_borrow_span(borrow), - format!("borrow of `{}` occurs here", - self.describe_lvalue(&borrow.lvalue))) - .span_label(span, format!("move out of `{}` occurs here", - self.describe_lvalue(lvalue))) + format!("borrow of {} occurs here", borrow_msg)) + .span_label(span, format!("move out of {} occurs here", value_msg)) .emit(); } @@ -1398,8 +1518,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { borrow : &BorrowData<'tcx>) { let mut err = self.tcx.cannot_use_when_mutably_borrowed( - span, &self.describe_lvalue(lvalue), - self.retrieve_borrow_span(borrow), &self.describe_lvalue(&borrow.lvalue), + span, + &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()), + self.retrieve_borrow_span(borrow), + &self.describe_lvalue(&borrow.lvalue).unwrap_or("_".to_owned()), Origin::Mir); err.emit(); @@ -1488,7 +1610,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location); let issued_span = old_closure_span.map(|(args, _)| args).unwrap_or(issued_span); - let desc_lvalue = self.describe_lvalue(lvalue); + let desc_lvalue = self.describe_lvalue(lvalue).unwrap_or("_".to_owned()); // FIXME: supply non-"" `opt_via` when appropriate let mut err = match (gen_borrow_kind, "immutable", "mutable", @@ -1566,7 +1688,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (lvalue, span): (&Lvalue<'tcx>, Span), loan: &BorrowData) { let mut err = self.tcx.cannot_assign_to_borrowed( - span, self.retrieve_borrow_span(loan), &self.describe_lvalue(lvalue), Origin::Mir); + span, + self.retrieve_borrow_span(loan), + &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()), + Origin::Mir); err.emit(); } @@ -1576,31 +1701,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (lvalue, span): (&Lvalue<'tcx>, Span), assigned_span: Span) { let mut err = self.tcx.cannot_reassign_immutable(span, - &self.describe_lvalue(lvalue), + &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()), Origin::Mir); err.span_label(span, "cannot assign twice to immutable variable"); if span != assigned_span { - err.span_label(assigned_span, format!("first assignment to `{}`", - self.describe_lvalue(lvalue))); + let value_msg = match self.describe_lvalue(lvalue) { + Some(name) => format!("`{}`", name), + None => "value".to_owned() + }; + err.span_label(assigned_span, format!("first assignment to {}", value_msg)); } err.emit(); } - - fn report_assignment_to_static(&mut self, - _context: Context, - (lvalue, span): (&Lvalue<'tcx>, Span)) { - let mut err = self.tcx.cannot_assign_static( - span, &self.describe_lvalue(lvalue), Origin::Mir); - err.emit(); - } } impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - // End-user visible description of `lvalue` - fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> String { + // End-user visible description of `lvalue` if one can be found. If the + // lvalue is a temporary for instance, None will be returned. + fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> Option { let mut buf = String::new(); - self.append_lvalue_to_string(lvalue, &mut buf, false); - buf + match self.append_lvalue_to_string(lvalue, &mut buf, false) { + Ok(()) => Some(buf), + Err(()) => None + } } /// If this is a field projection, and the field is being projected from a closure type, @@ -1632,10 +1755,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn append_lvalue_to_string(&self, lvalue: &Lvalue<'tcx>, buf: &mut String, - mut autoderef: bool) { + mut autoderef: bool) -> Result<(), ()> { match *lvalue { Lvalue::Local(local) => { - self.append_local_to_string(local, buf, "_"); + self.append_local_to_string(local, buf,)?; } Lvalue::Static(ref static_) => { buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id))); @@ -1653,15 +1776,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } else { if autoderef { - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; } else { buf.push_str(&"*"); - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; } } }, ProjectionElem::Downcast(..) => { - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; }, ProjectionElem::Field(field, _ty) => { autoderef = true; @@ -1672,16 +1795,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { buf.push_str(&name); } else { let field_name = self.describe_field(&proj.base, field); - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; buf.push_str(&format!(".{}", field_name)); } }, ProjectionElem::Index(index) => { autoderef = true; - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; buf.push_str("["); - self.append_local_to_string(index, buf, ".."); + if let Err(_) = self.append_local_to_string(index, buf) { + buf.push_str(".."); + } buf.push_str("]"); }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -1689,21 +1814,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Since it isn't possible to borrow an element on a particular index and // then use another while the borrow is held, don't output indices details // to avoid confusing the end-user - self.append_lvalue_to_string(&proj.base, buf, autoderef); + self.append_lvalue_to_string(&proj.base, buf, autoderef)?; buf.push_str(&"[..]"); }, }; } } + + Ok(()) } // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have - // a name, then `none_string` is appended instead - fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) { + // a name, then `Err` is returned + fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> { let local = &self.mir.local_decls[local_index]; match local.name { - Some(name) => buf.push_str(&format!("{}", name)), - None => buf.push_str(none_string) + Some(name) => { + buf.push_str(&format!("{}", name)); + Ok(()) + }, + None => Err(()) } } diff --git a/src/test/compile-fail/E0594.rs b/src/test/compile-fail/E0594.rs index 50f115306c8fa..f3fbc3b8b54db 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 static item + //[mir]~^ ERROR cannot assign to immutable 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 57002dd40fc95..76a670af3531c 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 static item `foo` + //[mir]~^ ERROR cannot assign to immutable item `foo` } diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs index 8b7ccedd6974f..8a09ab3fd06c8 100644 --- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs +++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs @@ -14,6 +14,9 @@ // Also includes tests of the errors reported when the Box in question // is immutable (#14270). +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + #![feature(box_syntax)] struct A { a: isize } @@ -23,7 +26,8 @@ fn indirect_write_to_imm_box() { let mut x: isize = 1; let y: Box<_> = box &mut x; let p = &y; - ***p = 2; //~ ERROR cannot assign to data in a `&` reference + ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference + //[mir]~^ ERROR cannot assign to immutable item `***p` drop(p); } @@ -32,7 +36,8 @@ fn borrow_in_var_from_var() { let mut y: Box<_> = box &mut x; let p = &y; let q = &***p; - **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -42,7 +47,8 @@ fn borrow_in_var_from_var_via_imm_box() { let y: Box<_> = box &mut x; let p = &y; let q = &***p; - **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -52,7 +58,8 @@ fn borrow_in_var_from_field() { let mut y: Box<_> = box &mut x.a; let p = &y; let q = &***p; - **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -62,7 +69,8 @@ fn borrow_in_var_from_field_via_imm_box() { let y: Box<_> = box &mut x.a; let p = &y; let q = &***p; - **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -72,7 +80,8 @@ fn borrow_in_field_from_var() { let mut y = B { a: box &mut x }; let p = &y.a; let q = &***p; - **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -82,7 +91,8 @@ fn borrow_in_field_from_var_via_imm_box() { let y = B { a: box &mut x }; let p = &y.a; let q = &***p; - **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -92,7 +102,8 @@ fn borrow_in_field_from_field() { let mut y = B { a: box &mut x.a }; let p = &y.a; let q = &***p; - **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -102,7 +113,8 @@ fn borrow_in_field_from_field_via_imm_box() { let y = B { a: box &mut x.a }; let p = &y.a; let q = &***p; - **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed + //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } diff --git a/src/test/compile-fail/borrowck/borrowck-overloaded-index-ref-index.rs b/src/test/compile-fail/borrowck/borrowck-overloaded-index-ref-index.rs index edffa9a8311ac..3a4c22eb1395a 100644 --- a/src/test/compile-fail/borrowck/borrowck-overloaded-index-ref-index.rs +++ b/src/test/compile-fail/borrowck/borrowck-overloaded-index-ref-index.rs @@ -70,5 +70,5 @@ fn main() { }; s[2] = 20; //[ast]~^ ERROR cannot assign to immutable indexed content - // FIXME Error for MIR + //[mir]~^^ ERROR cannot assign to immutable item } 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 5ddde6460b01f..8eed61ec8d531 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 @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + #![feature(unboxed_closures)] use std::io::Read; @@ -17,9 +21,11 @@ fn to_fn_once>(f: F) -> F { f } fn main() { let x = 1; to_fn_once(move|| { x = 2; }); - //~^ ERROR: cannot assign to immutable captured outer variable + //[ast]~^ ERROR: cannot assign to immutable captured outer variable + //[mir]~^^ ERROR: cannot assign to immutable item `x` let s = std::io::stdin(); to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - //~^ ERROR: cannot borrow immutable captured outer variable + //[ast]~^ ERROR: cannot borrow immutable captured outer variable + //[mir]~^^ ERROR: cannot borrow immutable item `s` as mutable } diff --git a/src/test/compile-fail/issue-5500-1.rs b/src/test/compile-fail/issue-5500-1.rs index 77f4e0bfd891b..75ff0a1210142 100644 --- a/src/test/compile-fail/issue-5500-1.rs +++ b/src/test/compile-fail/issue-5500-1.rs @@ -20,6 +20,7 @@ fn main() { let _iter = TrieMapIterator{node: &a}; _iter.node = & //[ast]~ ERROR cannot assign to immutable field `_iter.node` //[mir]~^ ERROR cannot assign to immutable field `_iter.node` (Ast) - // FIXME Error for MIR + // MIR doesn't generate an error because the code isn't reachable. This is OK + // because the test is here to check that the compiler doesn't ICE (cf. #5500). panic!() } diff --git a/src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs b/src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs index 432c7fa5d1b20..0dbd61413e053 100644 --- a/src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs +++ b/src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + // Test that a by-ref `FnMut` closure gets an error when it tries to // mutate a value. @@ -19,6 +22,7 @@ fn main() { let mut counter = 0; call(|| { counter += 1; - //~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure + //[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure + //[mir]~^^ ERROR cannot assign to immutable item `counter` }); }