Skip to content

Commit

Permalink
Fix borrowck compiler errors for upvars contain "spurious" dereferences
Browse files Browse the repository at this point in the history
Fixes #46003
  • Loading branch information
vramana committed Nov 23, 2017
1 parent 247d98e commit d059b57
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
57 changes: 46 additions & 11 deletions src/librustc_mir/borrow_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,
Expand All @@ -1596,25 +1621,35 @@ 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(..) => {
self.append_lvalue_to_string(&proj.base, buf, autoderef);
},
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));
}
Expand Down
15 changes: 13 additions & 2 deletions src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}
Expand All @@ -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();
}
}
}

0 comments on commit d059b57

Please sign in to comment.