about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBasile Desloges <basile.desloges@gmail.com>2017-11-22 17:35:52 +0100
committerBasile Desloges <basile.desloges@gmail.com>2017-11-28 13:44:09 +0100
commit503d25cbfdad2e31e4aac9491660bf33c14a85e5 (patch)
tree830f42d28429dc9d618fd3c596ea9bcc6af34ad3
parent436ac8928aa2e94f621111d6d99901713060b568 (diff)
mir-borrowck: `describe_lvalue()` can fail if a local doesn't have a name
-rw-r--r--src/librustc_mir/borrow_check.rs95
1 files changed, 62 insertions, 33 deletions
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 19d121843cb..d83656dc25a 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -1343,12 +1343,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 +1360,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 +1386,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 +1409,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 +1501,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 +1579,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,12 +1592,15 @@ 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();
     }
@@ -1596,11 +1615,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 }
 
 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 +1654,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 +1675,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 +1694,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 +1713,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(())
         }
     }