Auto merge of #46041 - zilbuz:issue-44837, r=arielb1
MIR borrowck: finalize `check_access_permissions()` Fix #44837 (hopefully for good) r? @arielb1
This commit is contained in:
commit
909b94b5cc
8 changed files with 232 additions and 79 deletions
|
@ -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();
|
||||
}
|
||||
},
|
||||
_ => {}// Access authorized
|
||||
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();
|
||||
}
|
||||
},
|
||||
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<T>` 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::<Vec<_>>();
|
||||
|
||||
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<String> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<A,F:FnOnce<A>>(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
|
||||
}
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue