mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
rollup merge of #20751: nikomatsakis/issue-20232
Issue #20232. Fun. r? @eddyb you prob know this system best
This commit is contained in:
commit
8ed88c11af
@ -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;
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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) => {
|
||||
@ -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)))
|
||||
@ -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,
|
||||
@ -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()));
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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()
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
@ -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))
|
||||
@ -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!("*")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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(()));
|
||||
@ -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
|
||||
@ -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 {
|
||||
@ -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,
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
@ -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>,
|
||||
|
@ -2268,12 +2268,17 @@ pub enum LvaluePreference {
|
||||
pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
sp: Span,
|
||||
base_ty: Ty<'tcx>,
|
||||
expr_id: Option<ast::NodeId>,
|
||||
opt_expr: Option<&ast::Expr>,
|
||||
mut lvalue_pref: LvaluePreference,
|
||||
mut should_stop: F)
|
||||
-> (Ty<'tcx>, uint, Option<T>) where
|
||||
F: FnMut(Ty<'tcx>, uint) -> Option<T>,
|
||||
-> (Ty<'tcx>, uint, Option<T>)
|
||||
where F: FnMut(Ty<'tcx>, uint) -> Option<T>,
|
||||
{
|
||||
debug!("autoderef(base_ty={}, opt_expr={}, lvalue_pref={:?})",
|
||||
base_ty.repr(fcx.tcx()),
|
||||
opt_expr.repr(fcx.tcx()),
|
||||
lvalue_pref);
|
||||
|
||||
let mut t = base_ty;
|
||||
for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
|
||||
let resolved_t = structurally_resolved_type(fcx, sp, t);
|
||||
@ -2291,7 +2296,19 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
let mt = match ty::deref(resolved_t, false) {
|
||||
Some(mt) => Some(mt),
|
||||
None => {
|
||||
let method_call = expr_id.map(|id| MethodCall::autoderef(id, autoderefs));
|
||||
let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs));
|
||||
|
||||
// Super subtle: it might seem as though we should
|
||||
// pass `opt_expr` to `try_overloaded_deref`, so that
|
||||
// the (implicit) autoref of using an overloaded deref
|
||||
// would get added to the adjustment table. However we
|
||||
// do not do that, because it's kind of a
|
||||
// "meta-adjustment" -- instead, we just leave it
|
||||
// unrecorded and know that there "will be" an
|
||||
// autoref. regionck and other bits of the code base,
|
||||
// when they encounter an overloaded autoderef, have
|
||||
// to do some reconstructive surgery. This is a pretty
|
||||
// complex mess that is begging for a proper MIR.
|
||||
try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
|
||||
}
|
||||
};
|
||||
@ -2324,7 +2341,7 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// Try DerefMut first, if preferred.
|
||||
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
|
||||
(PreferMutLvalue, Some(trait_did)) => {
|
||||
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||
method::lookup_in_trait(fcx, span, base_expr,
|
||||
token::intern("deref_mut"), trait_did,
|
||||
base_ty, None)
|
||||
}
|
||||
@ -2334,7 +2351,7 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// Otherwise, fall back to Deref.
|
||||
let method = match (method, fcx.tcx().lang_items.deref_trait()) {
|
||||
(None, Some(trait_did)) => {
|
||||
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||
method::lookup_in_trait(fcx, span, base_expr,
|
||||
token::intern("deref"), trait_did,
|
||||
base_ty, None)
|
||||
}
|
||||
@ -2390,7 +2407,7 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// consolidated.
|
||||
|
||||
let (ty, autoderefs, final_mt) =
|
||||
autoderef(fcx, base_expr.span, base_ty, Some(base_expr.id), lvalue_pref, |adj_ty, idx| {
|
||||
autoderef(fcx, base_expr.span, base_ty, Some(base_expr), lvalue_pref, |adj_ty, idx| {
|
||||
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
||||
step(adj_ty, autoderefref)
|
||||
});
|
||||
@ -3360,7 +3377,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
fcx.expr_ty(base));
|
||||
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||
let (_, autoderefs, field_ty) =
|
||||
autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
|
||||
autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
|
||||
match base_t.sty {
|
||||
ty::ty_struct(base_id, substs) => {
|
||||
debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
|
||||
@ -3421,7 +3438,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
let mut tuple_like = false;
|
||||
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||
let (_, autoderefs, field_ty) =
|
||||
autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
|
||||
autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
|
||||
match base_t.sty {
|
||||
ty::ty_struct(base_id, substs) => {
|
||||
tuple_like = ty::is_tuple_struct(tcx, base_id);
|
||||
|
@ -936,29 +936,47 @@ fn constrain_call<'a, I: Iterator<Item=&'a ast::Expr>>(rcx: &mut Rcx,
|
||||
fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||
deref_expr: &ast::Expr,
|
||||
derefs: uint,
|
||||
mut derefd_ty: Ty<'tcx>) {
|
||||
mut derefd_ty: Ty<'tcx>)
|
||||
{
|
||||
debug!("constrain_autoderefs(deref_expr={}, derefs={}, derefd_ty={})",
|
||||
deref_expr.repr(rcx.tcx()),
|
||||
derefs,
|
||||
derefd_ty.repr(rcx.tcx()));
|
||||
|
||||
let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
|
||||
for i in range(0u, derefs) {
|
||||
debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={}/{}",
|
||||
rcx.fcx.infcx().ty_to_string(derefd_ty),
|
||||
i, derefs);
|
||||
|
||||
let method_call = MethodCall::autoderef(deref_expr.id, i);
|
||||
debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
|
||||
|
||||
derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
|
||||
Some(method) => {
|
||||
debug!("constrain_autoderefs: #{} is overloaded, method={}",
|
||||
i, method.repr(rcx.tcx()));
|
||||
|
||||
// Treat overloaded autoderefs as if an AutoRef adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let fn_sig = ty::ty_fn_sig(method.ty);
|
||||
let self_ty = fn_sig.0.inputs[0];
|
||||
let fn_sig = // late-bound regions should have been instantiated
|
||||
ty::assert_no_late_bound_regions(rcx.tcx(), fn_sig);
|
||||
let self_ty = fn_sig.inputs[0];
|
||||
let (m, r) = match self_ty.sty {
|
||||
ty::ty_rptr(r, ref m) => (m.mutbl, r),
|
||||
_ => rcx.tcx().sess.span_bug(deref_expr.span,
|
||||
_ => {
|
||||
rcx.tcx().sess.span_bug(
|
||||
deref_expr.span,
|
||||
&format!("bad overloaded deref type {}",
|
||||
method.ty.repr(rcx.tcx()))[])
|
||||
method.ty.repr(rcx.tcx()))[])
|
||||
}
|
||||
};
|
||||
|
||||
debug!("constrain_autoderefs: receiver r={:?} m={:?}",
|
||||
r.repr(rcx.tcx()), m);
|
||||
|
||||
{
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
|
||||
debug!("constrain_autoderefs: self_cmt={:?}",
|
||||
self_cmt.repr(rcx.tcx()));
|
||||
link_region(rcx, deref_expr.span, *r,
|
||||
ty::BorrowKind::from_mutbl(m), self_cmt);
|
||||
}
|
||||
@ -966,7 +984,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||
// Specialized version of constrain_call.
|
||||
type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
|
||||
self_ty, r_deref_expr);
|
||||
match fn_sig.0.output {
|
||||
match fn_sig.output {
|
||||
ty::FnConverging(return_type) => {
|
||||
type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
|
||||
return_type, r_deref_expr);
|
||||
@ -1049,13 +1067,16 @@ fn type_of_node_must_outlive<'a, 'tcx>(
|
||||
/// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the
|
||||
/// resulting pointer is linked to the lifetime of its guarantor (if any).
|
||||
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
||||
mutability: ast::Mutability, base: &ast::Expr) {
|
||||
debug!("link_addr_of(base=?)");
|
||||
mutability: ast::Mutability, base: &ast::Expr) {
|
||||
debug!("link_addr_of(expr={}, base={})", expr.repr(rcx.tcx()), base.repr(rcx.tcx()));
|
||||
|
||||
let cmt = {
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
ignore_err!(mc.cat_expr(base))
|
||||
};
|
||||
|
||||
debug!("link_addr_of: cmt={}", cmt.repr(rcx.tcx()));
|
||||
|
||||
link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
|
||||
}
|
||||
|
||||
@ -1182,6 +1203,9 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
id: ast::NodeId,
|
||||
mutbl: ast::Mutability,
|
||||
cmt_borrowed: mc::cmt<'tcx>) {
|
||||
debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={})",
|
||||
id, mutbl, cmt_borrowed.repr(rcx.tcx()));
|
||||
|
||||
let rptr_ty = rcx.resolve_node_type(id);
|
||||
if !ty::type_is_error(rptr_ty) {
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
|
@ -37,9 +37,9 @@ fn illegal_dereference<T: Add<Output=()>>(mut x: T, y: T) {
|
||||
let m = &mut x;
|
||||
let n = &y;
|
||||
|
||||
*m //~ ERROR: cannot move out of dereference of `&mut`-pointer
|
||||
*m //~ ERROR: cannot move out of borrowed content
|
||||
+
|
||||
*n; //~ ERROR: cannot move out of dereference of `&`-pointer
|
||||
*n; //~ ERROR: cannot move out of borrowed content
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
|
@ -20,5 +20,5 @@ impl A {
|
||||
pub fn main() {
|
||||
let a = box A;
|
||||
a.foo();
|
||||
//~^ ERROR cannot borrow immutable dereference of `Box` `*a` as mutable
|
||||
//~^ ERROR cannot borrow immutable `Box` content `*a` as mutable
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ fn test1() {
|
||||
}
|
||||
|
||||
fn test2<F>(f: &F) where F: FnMut() {
|
||||
(*f)(); //~ ERROR: cannot borrow immutable dereference of `&`-pointer `*f` as mutable
|
||||
(*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
|
||||
}
|
||||
|
||||
fn test3<F>(f: &mut F) where F: FnMut() {
|
||||
@ -41,7 +41,7 @@ fn test3<F>(f: &mut F) where F: FnMut() {
|
||||
}
|
||||
|
||||
fn test4(f: &Test) {
|
||||
f.f.call_mut(()) //~ ERROR: cannot borrow immutable dereference of `Box` `*f.f` as mutable
|
||||
f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
|
||||
}
|
||||
|
||||
fn test5(f: &mut Test) {
|
||||
|
@ -11,16 +11,16 @@
|
||||
fn with<F>(f: F) where F: FnOnce(&String) {}
|
||||
|
||||
fn arg_item(&_x: &String) {}
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
|
||||
fn arg_closure() {
|
||||
with(|&_x| ())
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
}
|
||||
|
||||
fn let_pat() {
|
||||
let &_x = &"hi".to_string();
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -12,5 +12,5 @@ use std::rc::Rc;
|
||||
|
||||
pub fn main() {
|
||||
let _x = Rc::new(vec!(1i, 2)).into_iter();
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ use std::rc::Rc;
|
||||
|
||||
pub fn main() {
|
||||
let _x = *Rc::new("hi".to_string());
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ pub fn main() {
|
||||
match x {
|
||||
[_, tail..] => {
|
||||
match tail {
|
||||
[Foo { string: a }, //~ ERROR cannot move out of dereference of `&`-pointer
|
||||
[Foo { string: a }, //~ ERROR cannot move out of borrowed content
|
||||
Foo { string: b }] => {
|
||||
//~^^ NOTE attempting to move value to here
|
||||
//~^^ NOTE and here
|
||||
|
@ -28,5 +28,5 @@ fn main() {
|
||||
let v = MyVec { data: vec!(box 1i, box 2, box 3) };
|
||||
let good = &v[0]; // Shouldn't fail here
|
||||
let bad = v[0];
|
||||
//~^ ERROR cannot move out of dereference (dereference is implicit, due to indexing)
|
||||
//~^ ERROR cannot move out of indexed content
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that we properly record borrows when we are doing an
|
||||
// overloaded, autoderef of a value obtained via an overloaded index
|
||||
// operator. The accounting of the all the implicit things going on
|
||||
// here is rather subtle. Issue #20232.
|
||||
|
||||
use std::ops::{Deref, Index};
|
||||
|
||||
struct MyVec<T> { x: T }
|
||||
|
||||
impl<T> Index<usize> for MyVec<T> {
|
||||
type Output = T;
|
||||
fn index(&self, _: &usize) -> &T {
|
||||
&self.x
|
||||
}
|
||||
}
|
||||
|
||||
struct MyPtr<T> { x: T }
|
||||
|
||||
impl<T> Deref for MyPtr<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
&self.x
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo { f: usize }
|
||||
|
||||
fn main() {
|
||||
let mut v = MyVec { x: MyPtr { x: Foo { f: 22 } } };
|
||||
let i = &v[0].f;
|
||||
v = MyVec { x: MyPtr { x: Foo { f: 23 } } };
|
||||
//~^ ERROR cannot assign to `v`
|
||||
read(*i);
|
||||
}
|
||||
|
||||
fn read(_: usize) { }
|
||||
|
@ -66,5 +66,5 @@ fn main() {
|
||||
x: 1,
|
||||
};
|
||||
s[2] = 20;
|
||||
//~^ ERROR cannot assign to immutable dereference (dereference is implicit, due to indexing)
|
||||
//~^ ERROR cannot assign to immutable indexed content
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ impl Index<uint> for T {
|
||||
|
||||
fn main() {
|
||||
S[0];
|
||||
//~^ ERROR cannot move out of dereference
|
||||
//~^ ERROR cannot move out of indexed content
|
||||
//~^^ ERROR E0161
|
||||
T[0];
|
||||
//~^ ERROR cannot move out of dereference
|
||||
//~^ ERROR cannot move out of indexed content
|
||||
//~^^ ERROR E0161
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
pub fn main() {
|
||||
let _x: Box<str> = box *"hello world";
|
||||
//~^ ERROR E0161
|
||||
//~^^ ERROR cannot move out of dereference
|
||||
//~^^ ERROR cannot move out of borrowed content
|
||||
|
||||
let array: &[int] = &[1, 2, 3];
|
||||
let _x: Box<[int]> = box *array;
|
||||
//~^ ERROR E0161
|
||||
//~^^ ERROR cannot move out of dereference
|
||||
//~^^ ERROR cannot move out of borrowed content
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
|
||||
match (l1, l2) {
|
||||
([], []) => println!("both empty"),
|
||||
([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"),
|
||||
//~^ ERROR: cannot move out of dereference
|
||||
//~^^ ERROR: cannot move out of dereference
|
||||
//~^ ERROR: cannot move out of borrowed content
|
||||
//~^^ ERROR: cannot move out of borrowed content
|
||||
([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"),
|
||||
//~^ ERROR: cannot move out of dereference
|
||||
//~^^ ERROR: cannot move out of dereference
|
||||
//~^ ERROR: cannot move out of borrowed content
|
||||
//~^^ ERROR: cannot move out of borrowed content
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,6 @@
|
||||
|
||||
fn main() {
|
||||
(|&:| box *[0us].as_slice())();
|
||||
//~^ ERROR cannot move out of dereference
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
//~^^ ERROR cannot move a value of type [usize]
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ trait parse {
|
||||
|
||||
impl parse for parser {
|
||||
fn parse(&self) -> Vec<int> {
|
||||
self.tokens //~ ERROR cannot move out of dereference of `&`-pointer
|
||||
self.tokens //~ ERROR cannot move out of borrowed content
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,5 +23,5 @@ fn main() {
|
||||
Foo::bar(&x); //~ERROR cannot borrow `x`
|
||||
|
||||
let x = Foo;
|
||||
Foo::baz(&x); //~ERROR cannot borrow immutable dereference of `&`-pointer as mutable
|
||||
Foo::baz(&x); //~ERROR cannot borrow immutable borrowed content as mutable
|
||||
}
|
||||
|
@ -14,5 +14,5 @@ fn main() {
|
||||
let x: &[int] = &[1, 2, 3, 4, 5];
|
||||
// Can't mutably slice an immutable slice
|
||||
let slice: &mut [int] = &mut [0, 1];
|
||||
let _ = &mut x[2..4]; //~ERROR cannot borrow immutable dereference of `&`-pointer `*x` as mutabl
|
||||
let _ = &mut x[2..4]; //~ERROR cannot borrow immutable borrowed content `*x` as mutable
|
||||
}
|
||||
|
@ -13,5 +13,5 @@
|
||||
fn main() {
|
||||
let x: &[int] = &[1, 2, 3, 4, 5];
|
||||
// Immutable slices are not mutable.
|
||||
let y: &mut[_] = &x[2..4]; //~ ERROR cannot borrow immutable dereference of `&`-pointer as mutab
|
||||
let y: &mut[_] = &x[2..4]; //~ ERROR cannot borrow immutable borrowed content as mutable
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ use std::ptr;
|
||||
|
||||
fn main() {
|
||||
let x = ATOMIC_BOOL_INIT;
|
||||
let x = *&x; //~ ERROR: cannot move out of dereference
|
||||
let x = *&x; //~ ERROR: cannot move out of borrowed content
|
||||
let x = ATOMIC_INT_INIT;
|
||||
let x = *&x; //~ ERROR: cannot move out of dereference
|
||||
let x = *&x; //~ ERROR: cannot move out of borrowed content
|
||||
let x = ATOMIC_UINT_INIT;
|
||||
let x = *&x; //~ ERROR: cannot move out of dereference
|
||||
let x = *&x; //~ ERROR: cannot move out of borrowed content
|
||||
let x: AtomicPtr<uint> = AtomicPtr::new(ptr::null_mut());
|
||||
let x = *&x; //~ ERROR: cannot move out of dereference
|
||||
let x = *&x; //~ ERROR: cannot move out of borrowed content
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ fn illegal_dereference<T: Not<Output=T>>(mut x: T, y: T) {
|
||||
let m = &mut x;
|
||||
let n = &y;
|
||||
|
||||
!*m; //~ ERROR: cannot move out of dereference of `&mut`-pointer
|
||||
!*m; //~ ERROR: cannot move out of borrowed content
|
||||
|
||||
!*n; //~ ERROR: cannot move out of dereference of `&`-pointer
|
||||
!*n; //~ ERROR: cannot move out of borrowed content
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user