mir-borrowck: describe_lvalue() can fail if a local doesn't have a name

This commit is contained in:
Basile Desloges 2017-11-22 17:35:52 +01:00
parent 436ac8928a
commit 503d25cbfd

View File

@ -1343,12 +1343,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|moi| curr_move_out.contains(moi)).collect::<Vec<_>>(); |moi| curr_move_out.contains(moi)).collect::<Vec<_>>();
if mois.is_empty() { 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, self.tcx.cannot_act_on_uninitialized_variable(span,
desired_action.as_noun(), desired_action.as_noun(),
&self.describe_lvalue(lvalue), &self.describe_lvalue(lvalue)
.unwrap_or("_".to_owned()),
Origin::Mir) Origin::Mir)
.span_label(span, format!("use of possibly uninitialized `{}`", .span_label(span, format!("use of possibly uninitialized {}", item_msg))
self.describe_lvalue(lvalue)))
.emit(); .emit();
} else { } else {
let msg = ""; //FIXME: add "partially " or "collaterally " let msg = ""; //FIXME: add "partially " or "collaterally "
@ -1356,7 +1360,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let mut err = self.tcx.cannot_act_on_moved_value(span, let mut err = self.tcx.cannot_act_on_moved_value(span,
desired_action.as_noun(), desired_action.as_noun(),
msg, msg,
&self.describe_lvalue(lvalue), &self.describe_lvalue(lvalue)
.unwrap_or("_".to_owned()),
Origin::Mir); Origin::Mir);
err.span_label(span, format!("value {} here after move", err.span_label(span, format!("value {} here after move",
@ -1381,14 +1386,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
_context: Context, _context: Context,
(lvalue, span): (&Lvalue<'tcx>, Span), (lvalue, span): (&Lvalue<'tcx>, Span),
borrow: &BorrowData<'tcx>) { 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.tcx.cannot_move_when_borrowed(span,
&self.describe_lvalue(lvalue), &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()),
Origin::Mir) Origin::Mir)
.span_label(self.retrieve_borrow_span(borrow), .span_label(self.retrieve_borrow_span(borrow),
format!("borrow of `{}` occurs here", format!("borrow of {} occurs here", borrow_msg))
self.describe_lvalue(&borrow.lvalue))) .span_label(span, format!("move out of {} occurs here", value_msg))
.span_label(span, format!("move out of `{}` occurs here",
self.describe_lvalue(lvalue)))
.emit(); .emit();
} }
@ -1398,8 +1409,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
borrow : &BorrowData<'tcx>) { borrow : &BorrowData<'tcx>) {
let mut err = self.tcx.cannot_use_when_mutably_borrowed( let mut err = self.tcx.cannot_use_when_mutably_borrowed(
span, &self.describe_lvalue(lvalue), span,
self.retrieve_borrow_span(borrow), &self.describe_lvalue(&borrow.lvalue), &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()),
self.retrieve_borrow_span(borrow),
&self.describe_lvalue(&borrow.lvalue).unwrap_or("_".to_owned()),
Origin::Mir); Origin::Mir);
err.emit(); err.emit();
@ -1488,7 +1501,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location); 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 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 // FIXME: supply non-"" `opt_via` when appropriate
let mut err = match (gen_borrow_kind, "immutable", "mutable", let mut err = match (gen_borrow_kind, "immutable", "mutable",
@ -1566,7 +1579,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(lvalue, span): (&Lvalue<'tcx>, Span), (lvalue, span): (&Lvalue<'tcx>, Span),
loan: &BorrowData) { loan: &BorrowData) {
let mut err = self.tcx.cannot_assign_to_borrowed( 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(); err.emit();
} }
@ -1576,12 +1592,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(lvalue, span): (&Lvalue<'tcx>, Span), (lvalue, span): (&Lvalue<'tcx>, Span),
assigned_span: Span) { assigned_span: Span) {
let mut err = self.tcx.cannot_reassign_immutable(span, let mut err = self.tcx.cannot_reassign_immutable(span,
&self.describe_lvalue(lvalue), &self.describe_lvalue(lvalue).unwrap_or("_".to_owned()),
Origin::Mir); Origin::Mir);
err.span_label(span, "cannot assign twice to immutable variable"); err.span_label(span, "cannot assign twice to immutable variable");
if span != assigned_span { if span != assigned_span {
err.span_label(assigned_span, format!("first assignment to `{}`", let value_msg = match self.describe_lvalue(lvalue) {
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(); err.emit();
} }
@ -1596,11 +1615,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// End-user visible description of `lvalue` // End-user visible description of `lvalue` if one can be found. If the
fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> String { // lvalue is a temporary for instance, None will be returned.
fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> Option<String> {
let mut buf = String::new(); let mut buf = String::new();
self.append_lvalue_to_string(lvalue, &mut buf, false); match self.append_lvalue_to_string(lvalue, &mut buf, false) {
buf Ok(()) => Some(buf),
Err(()) => None
}
} }
/// If this is a field projection, and the field is being projected from a closure type, /// If this is a field projection, and the field is being projected from a closure type,
@ -1632,10 +1654,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
fn append_lvalue_to_string(&self, fn append_lvalue_to_string(&self,
lvalue: &Lvalue<'tcx>, lvalue: &Lvalue<'tcx>,
buf: &mut String, buf: &mut String,
mut autoderef: bool) { mut autoderef: bool) -> Result<(), ()> {
match *lvalue { match *lvalue {
Lvalue::Local(local) => { Lvalue::Local(local) => {
self.append_local_to_string(local, buf, "_"); self.append_local_to_string(local, buf,)?;
} }
Lvalue::Static(ref static_) => { Lvalue::Static(ref static_) => {
buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id))); buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
@ -1653,15 +1675,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
} else { } else {
if autoderef { if autoderef {
self.append_lvalue_to_string(&proj.base, buf, autoderef); self.append_lvalue_to_string(&proj.base, buf, autoderef)?;
} else { } else {
buf.push_str(&"*"); buf.push_str(&"*");
self.append_lvalue_to_string(&proj.base, buf, autoderef); self.append_lvalue_to_string(&proj.base, buf, autoderef)?;
} }
} }
}, },
ProjectionElem::Downcast(..) => { ProjectionElem::Downcast(..) => {
self.append_lvalue_to_string(&proj.base, buf, autoderef); self.append_lvalue_to_string(&proj.base, buf, autoderef)?;
}, },
ProjectionElem::Field(field, _ty) => { ProjectionElem::Field(field, _ty) => {
autoderef = true; autoderef = true;
@ -1672,16 +1694,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
buf.push_str(&name); buf.push_str(&name);
} else { } else {
let field_name = self.describe_field(&proj.base, field); 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)); buf.push_str(&format!(".{}", field_name));
} }
}, },
ProjectionElem::Index(index) => { ProjectionElem::Index(index) => {
autoderef = true; autoderef = true;
self.append_lvalue_to_string(&proj.base, buf, autoderef); self.append_lvalue_to_string(&proj.base, buf, autoderef)?;
buf.push_str("["); 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("]"); buf.push_str("]");
}, },
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
@ -1689,21 +1713,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// Since it isn't possible to borrow an element on a particular index and // 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 // then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user // 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(&"[..]"); buf.push_str(&"[..]");
}, },
}; };
} }
} }
Ok(())
} }
// Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have
// a name, then `none_string` is appended instead // a name, then `Err` is returned
fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) { fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
let local = &self.mir.local_decls[local_index]; let local = &self.mir.local_decls[local_index];
match local.name { match local.name {
Some(name) => buf.push_str(&format!("{}", name)), Some(name) => {
None => buf.push_str(none_string) buf.push_str(&format!("{}", name));
Ok(())
},
None => Err(())
} }
} }