about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-23 14:48:14 +0000
committerbors <bors@rust-lang.org>2017-11-23 14:48:14 +0000
commit0916bbc00027626e4ae6027ee08a8dd46036e8b2 (patch)
tree41623ef58f2ad06942ceccefbc4e89e45e8ea25c
parentb9b82fde7c72e47bd76829bd5322f427bf3f9900 (diff)
parentd059b57c7878f2503b11727fb7e8bb919de542c4 (diff)
downloadrust-0916bbc00027626e4ae6027ee08a8dd46036e8b2.tar.gz
rust-0916bbc00027626e4ae6027ee08a8dd46036e8b2.zip
Auto merge of #46087 - vramana:fix-46003, r=arielb1
Fix borrowck compiler errors for upvars contain "spurious" dereferences

Fixes #46003
-rw-r--r--src/librustc_mir/borrow_check.rs57
-rw-r--r--src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs15
2 files changed, 59 insertions, 13 deletions
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 352e7ef7010..ddaade98be1 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -15,9 +15,9 @@ use rustc::hir::def_id::{DefId};
 use rustc::infer::{InferCtxt};
 use rustc::ty::{self, TyCtxt, ParamEnv};
 use rustc::ty::maps::Providers;
-use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Field, Location, Lvalue, Local};
+use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local};
 use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
-use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
+use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
 use transform::nll;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -1581,6 +1581,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         buf
     }
 
+    /// If this is a field projection, and the field is being projected from a closure type,
+    /// then returns the index of the field being projected. Note that this closure will always
+    /// be `self` in the current MIR, because that is the only time we directly access the fields
+    /// of a closure type.
+    fn is_upvar_field_projection(&self, lvalue: &Lvalue<'tcx>) -> Option<Field> {
+        match *lvalue {
+            Lvalue::Projection(ref proj) => {
+                match proj.elem {
+                    ProjectionElem::Field(field, _ty) => {
+                        let is_projection_from_ty_closure = proj.base.ty(self.mir, self.tcx)
+                                .to_ty(self.tcx).is_closure();
+
+                        if is_projection_from_ty_closure {
+                            Some(field)
+                        } else {
+                            None
+                        }
+                    },
+                    _ => None
+                }
+            },
+            _ => None
+        }
+    }
+
     // Appends end-user visible description of `lvalue` to `buf`.
     fn append_lvalue_to_string(&self,
                                lvalue: &Lvalue<'tcx>,
@@ -1596,11 +1621,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Lvalue::Projection(ref proj) => {
                 match proj.elem {
                     ProjectionElem::Deref => {
-                        if autoderef {
-                            self.append_lvalue_to_string(&proj.base, buf, autoderef);
+                        if let Some(field) = self.is_upvar_field_projection(&proj.base) {
+                            let var_index = field.index();
+                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
+                            if self.mir.upvar_decls[var_index].by_ref {
+                                buf.push_str(&name);
+                            } else {
+                                buf.push_str(&format!("*{}", &name));
+                            }
                         } else {
-                            buf.push_str(&"*");
-                            self.append_lvalue_to_string(&proj.base, buf, autoderef);
+                            if autoderef {
+                                self.append_lvalue_to_string(&proj.base, buf, autoderef);
+                            } else {
+                                buf.push_str(&"*");
+                                self.append_lvalue_to_string(&proj.base, buf, autoderef);
+                            }
                         }
                     },
                     ProjectionElem::Downcast(..) => {
@@ -1608,13 +1643,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     },
                     ProjectionElem::Field(field, _ty) => {
                         autoderef = true;
-                        let is_projection_from_ty_closure = proj.base.ty(self.mir, self.tcx)
-                                .to_ty(self.tcx).is_closure();
 
-                        let field_name = self.describe_field(&proj.base, field);
-                        if is_projection_from_ty_closure {
-                            buf.push_str(&format!("{}", field_name));
+                        if let Some(field) = self.is_upvar_field_projection(lvalue) {
+                            let var_index = field.index();
+                            let name = self.mir.upvar_decls[var_index].debug_name.to_string();
+                            buf.push_str(&name);
                         } else {
+                            let field_name = self.describe_field(&proj.base, field);
                             self.append_lvalue_to_string(&proj.base, buf, autoderef);
                             buf.push_str(&format!(".{}", field_name));
                         }
diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
index 009819f0bb5..32052fff90d 100644
--- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
+++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
@@ -300,7 +300,7 @@ fn main() {
             let y = &mut x;
             &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
                     //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast)
-                    //[mir]~| ERROR cannot borrow `*x` as mutable more than once at a time (Mir)
+                    //[mir]~| ERROR cannot borrow `x` as mutable more than once at a time (Mir)
             *y = 1;
         };
     }
@@ -312,9 +312,20 @@ fn main() {
                 let y = &mut x;
                 &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
                         //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast)
-                        //[mir]~| ERROR cannot borrow `*x` as mutable more than once at a time (Mir)
+                        //[mir]~| ERROR cannot borrow `x` as mutable more than once at a time (Mir)
                 *y = 1;
                 }
            };
     }
+    {
+        fn foo(x: Vec<i32>) {
+            let c = || {
+                drop(x);
+                drop(x); //[ast]~ ERROR use of moved value: `x`
+                         //[mir]~^ ERROR use of moved value: `x` (Ast)
+                         //[mir]~| ERROR use of moved value: `x` (Mir)
+            };
+            c();
+        }
+    }
 }