Skip to content

Fix mem-categorization of an overloaded autoderef applied to result of an overloaded index #20751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 97 additions & 39 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ use middle::def;
use middle::region;
use middle::ty::{self, Ty};
use util::nodemap::{NodeMap};
use util::ppaux::{Repr};
use util::ppaux::{Repr, UserString};

use syntax::ast::{MutImmutable, MutMutable};
use syntax::ast;
Expand Down Expand Up @@ -113,10 +113,17 @@ pub struct Upvar {
// different kinds of pointers:
#[derive(Clone, Copy, PartialEq, Eq, Hash, Show)]
pub enum PointerKind {
/// `Box<T>`
Unique,

/// `&T`
BorrowedPtr(ty::BorrowKind, ty::Region),
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
UnsafePtr(ast::Mutability)

/// `*T`
UnsafePtr(ast::Mutability),

/// Implicit deref of the `&T` that results from an overloaded index `[]`.
Implicit(ty::BorrowKind, ty::Region),
}

// We use the term "interior" to mean "something reachable from the
Expand Down Expand Up @@ -453,7 +460,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
autoderefs,
cmt.repr(self.tcx()));
for deref in range(1u, autoderefs + 1) {
cmt = try!(self.cat_deref(expr, cmt, deref, false));
cmt = try!(self.cat_deref(expr, cmt, deref));
}
return Ok(cmt);
}
Expand All @@ -465,7 +472,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
match expr.node {
ast::ExprUnary(ast::UnDeref, ref e_base) => {
let base_cmt = try!(self.cat_expr(&**e_base));
self.cat_deref(expr, base_cmt, 0, false)
self.cat_deref(expr, base_cmt, 0)
}

ast::ExprField(ref base, f_name) => {
Expand All @@ -489,10 +496,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
// If this is an index implemented by a method call, then it
// will include an implicit deref of the result.
let ret_ty = self.overloaded_method_return_ty(method_ty);
self.cat_deref(expr,
self.cat_rvalue_node(expr.id(),
expr.span(),
ret_ty), 1, true)

// The index method always returns an `&T`, so
// dereference it to find the result type.
let elem_ty = match ret_ty.sty {
ty::ty_rptr(_, mt) => mt.ty,
_ => {
debug!("cat_expr_unadjusted: return type of overloaded index is {}?",
ret_ty.repr(self.tcx()));
return Err(());
}
};

// The call to index() returns a `&T` value, which
// is an rvalue. That is what we will be
// dereferencing.
let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)
}
None => {
self.cat_index(expr, try!(self.cat_expr(&**base)))
Expand Down Expand Up @@ -837,8 +857,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
fn cat_deref<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
deref_cnt: uint,
implicit: bool)
deref_cnt: uint)
-> McResult<cmt<'tcx>> {
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
Expand Down Expand Up @@ -866,7 +885,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
};
let base_cmt_ty = base_cmt.ty;
match ty::deref(base_cmt_ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty,
/* implicit: */ false),
None => {
debug!("Explicit deref of non-derefable type: {}",
base_cmt_ty.repr(self.tcx()));
Expand Down Expand Up @@ -1236,7 +1256,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
// box p1, &p1, &mut p1. we can ignore the mutability of
// PatRegion since that information is already contained
// in the type.
let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
let subcmt = try!(self.cat_deref(pat, cmt, 0));
try!(self.cat_pattern_(subcmt, &**subpat, op));
}

Expand Down Expand Up @@ -1392,22 +1412,6 @@ impl<'tcx> cmt_<'tcx> {


pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
if upvar.is_unboxed {
let kind = match upvar.kind {
ty::FnUnboxedClosureKind => "Fn",
ty::FnMutUnboxedClosureKind => "FnMut",
ty::FnOnceUnboxedClosureKind => "FnOnce"
};
format!("captured outer variable in an `{}` closure", kind)
} else {
(match (upvar.kind, is_copy) {
(ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
_ => "captured outer variable"
}).to_string()
}
}

match self.cat {
cat_static_item => {
"static item".to_string()
Expand All @@ -1427,16 +1431,23 @@ impl<'tcx> cmt_<'tcx> {
let upvar = self.upvar();
match upvar.as_ref().map(|i| &i.cat) {
Some(&cat_upvar(ref var)) => {
upvar_to_string(var, false)
var.user_string(tcx)
}
Some(_) => unreachable!(),
None => {
match pk {
Implicit(..) => {
"dereference (dereference is implicit, due to indexing)".to_string()
format!("indexed content")
}
Unique => {
format!("`Box` content")
}
UnsafePtr(..) => {
format!("dereference of unsafe pointer")
}
BorrowedPtr(..) => {
format!("borrowed content")
}
Unique => format!("dereference of `{}`", ptr_sigil(pk)),
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
}
}
}
Expand All @@ -1447,14 +1458,12 @@ impl<'tcx> cmt_<'tcx> {
cat_interior(_, InteriorField(PositionalField(_))) => {
"anonymous field".to_string()
}
cat_interior(_, InteriorElement(VecElement)) => {
"vec content".to_string()
}
cat_interior(_, InteriorElement(VecElement)) |
cat_interior(_, InteriorElement(OtherElement)) => {
"indexed content".to_string()
}
cat_upvar(ref var) => {
upvar_to_string(var, true)
var.user_string(tcx)
}
cat_downcast(ref cmt, _) => {
cmt.descriptive_string(tcx)
Expand Down Expand Up @@ -1483,7 +1492,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> {
format!("{:?}", *self)
}
cat_deref(ref cmt, derefs, ptr) => {
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs)
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr.repr(tcx), derefs)
}
cat_interior(ref cmt, interior) => {
format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
Expand All @@ -1504,7 +1513,32 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
Implicit(ty::MutBorrow, _) => "&mut",
BorrowedPtr(ty::UniqueImmBorrow, _) |
Implicit(ty::UniqueImmBorrow, _) => "&unique",
UnsafePtr(_) => "*"
UnsafePtr(_) => "*",
}
}

impl<'tcx> Repr<'tcx> for PointerKind {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
Unique => {
format!("Box")
}
BorrowedPtr(ty::ImmBorrow, ref r) |
Implicit(ty::ImmBorrow, ref r) => {
format!("&{}", r.repr(tcx))
}
BorrowedPtr(ty::MutBorrow, ref r) |
Implicit(ty::MutBorrow, ref r) => {
format!("&{} mut", r.repr(tcx))
}
BorrowedPtr(ty::UniqueImmBorrow, ref r) |
Implicit(ty::UniqueImmBorrow, ref r) => {
format!("&{} uniq", r.repr(tcx))
}
UnsafePtr(_) => {
format!("*")
}
}
}
}

Expand All @@ -1531,3 +1565,27 @@ fn element_kind(t: Ty) -> ElementKind {
_ => OtherElement
}
}

impl<'tcx> Repr<'tcx> for ty::UnboxedClosureKind {
fn repr(&self, _: &ty::ctxt) -> String {
format!("Upvar({:?})", self)
}
}

impl<'tcx> Repr<'tcx> for Upvar {
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("Upvar({})", self.kind.repr(tcx))
}
}

impl<'tcx> UserString<'tcx> for Upvar {
fn user_string(&self, _: &ty::ctxt) -> String {
let kind = match self.kind {
ty::FnUnboxedClosureKind => "Fn",
ty::FnMutUnboxedClosureKind => "FnMut",
ty::FnOnceUnboxedClosureKind => "FnOnce",
};
format!("captured outer variable in an `{}` closure", kind)
}
}

20 changes: 11 additions & 9 deletions src/librustc_borrowck/borrowck/gather_loans/move_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,31 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
match move_from.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_static_item => {
bccx.span_err(
move_from.span,
&format!("cannot move out of {}",
bccx.cmt_to_string(&*move_from))[]);
bccx.span_err(move_from.span,
&format!("cannot move out of {}",
move_from.descriptive_string(bccx.tcx))[]);
}

mc::cat_downcast(ref b, _) |
mc::cat_interior(ref b, _) => {
match b.ty.sty {
ty::ty_struct(did, _)
| ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
ty::ty_struct(did, _) |
ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
bccx.span_err(
move_from.span,
&format!("cannot move out of type `{}`, \
which defines the `Drop` trait",
b.ty.user_string(bccx.tcx))[]);
},
_ => panic!("this path should not cause illegal move")
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
}
}
}
_ => panic!("this path should not cause illegal move")
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
self.tcx.sess.span_err(s, m);
}

pub fn span_bug(&self, s: Span, m: &str) {
self.tcx.sess.span_bug(s, m);
}

pub fn span_note(&self, s: Span, m: &str) {
self.tcx.sess.span_note(s, m);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
autoderef(fcx,
callee_expr.span,
original_callee_ty,
Some(callee_expr.id),
Some(callee_expr),
LvaluePreference::NoPreference,
|adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
// time writing the results into the various tables.
let (autoderefd_ty, n, result) =
check::autoderef(
self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr.id), NoPreference,
self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr), NoPreference,
|_, n| if n == auto_deref_ref.autoderefs { Some(()) } else { None });
assert_eq!(n, auto_deref_ref.autoderefs);
assert_eq!(result, Some(()));
Expand Down Expand Up @@ -492,7 +492,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
exprs.repr(self.tcx()));

// Fix up autoderefs and derefs.
for (i, expr) in exprs.iter().rev().enumerate() {
for (i, &expr) in exprs.iter().rev().enumerate() {
// Count autoderefs.
let autoderef_count = match self.fcx
.inh
Expand All @@ -512,8 +512,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
if autoderef_count > 0 {
check::autoderef(self.fcx,
expr.span,
self.fcx.expr_ty(*expr),
Some(expr.id),
self.fcx.expr_ty(expr),
Some(expr),
PreferMutLvalue,
|_, autoderefs| {
if autoderefs == autoderef_count + 1 {
Expand Down Expand Up @@ -567,7 +567,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
let result = check::try_index_step(
self.fcx,
MethodCall::expr(expr.id),
*expr,
expr,
&**base_expr,
adjusted_base_ty,
base_adjustment,
Expand All @@ -577,7 +577,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
if let Some((input_ty, return_ty)) = result {
demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);

let expr_ty = self.fcx.expr_ty(&**expr);
let expr_ty = self.fcx.expr_ty(&*expr);
demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
}

pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
self_expr: Option<&'a ast::Expr>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
Expand All @@ -125,9 +125,9 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
/// method-lookup code. In particular, autoderef on index is basically identical to autoderef with
/// normal probes, except that the test also looks for built-in indexing. Also, the second half of
/// this method is basically the same as confirmation.
pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
self_expr: Option<&'a ast::Expr>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
autoderefref: ty::AutoDerefRef<'tcx>,
Expand Down
Loading