diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fb9a16f86e5b..51ec75284326 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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` 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(&self, node: &N, base_cmt: cmt<'tcx>, - deref_cnt: uint, - implicit: bool) + deref_cnt: uint) -> McResult> { 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) + } +} + diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index a7771fefec41..28d02161eebd 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -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") + } } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e734e8fb6ffb..b87fed1601c5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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); } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index dff216ac2935..19a88dfc553b 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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 }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7e72f300f417..794607748597 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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); } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index bb000742def9..0c53a16a8118 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b98b327100cd..084a457909c5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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, + opt_expr: Option<&ast::Expr>, mut lvalue_pref: LvaluePreference, mut should_stop: F) - -> (Ty<'tcx>, uint, Option) where - F: FnMut(Ty<'tcx>, uint) -> Option, + -> (Ty<'tcx>, uint, Option) + where F: FnMut(Ty<'tcx>, uint) -> Option, { + 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); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 112e00536422..3b5027dbb9e6 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -936,29 +936,47 @@ fn constrain_call<'a, I: Iterator>(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; diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index ffc38cc0a600..cff0064497af 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -37,9 +37,9 @@ fn illegal_dereference>(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; diff --git a/src/test/compile-fail/borrowck-borrow-immut-deref-of-box-as-mut.rs b/src/test/compile-fail/borrowck-borrow-immut-deref-of-box-as-mut.rs index 84f4e4f8817c..794e0fc6e3ab 100644 --- a/src/test/compile-fail/borrowck-borrow-immut-deref-of-box-as-mut.rs +++ b/src/test/compile-fail/borrowck-borrow-immut-deref-of-box-as-mut.rs @@ -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 } diff --git a/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs b/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs index 9aec8de46b6d..d5df12513465 100644 --- a/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs @@ -33,7 +33,7 @@ fn test1() { } fn test2(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: &mut F) where F: FnMut() { @@ -41,7 +41,7 @@ fn test3(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) { diff --git a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs index c5d23925a89b..ec505faf8850 100644 --- a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs +++ b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs @@ -11,16 +11,16 @@ fn with(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() {} diff --git a/src/test/compile-fail/borrowck-move-out-of-overloaded-auto-deref.rs b/src/test/compile-fail/borrowck-move-out-of-overloaded-auto-deref.rs index a6723a04611a..a13efdea5621 100644 --- a/src/test/compile-fail/borrowck-move-out-of-overloaded-auto-deref.rs +++ b/src/test/compile-fail/borrowck-move-out-of-overloaded-auto-deref.rs @@ -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 } diff --git a/src/test/compile-fail/borrowck-move-out-of-overloaded-deref.rs b/src/test/compile-fail/borrowck-move-out-of-overloaded-deref.rs index 8a93790d5a29..fffcf575ab08 100644 --- a/src/test/compile-fail/borrowck-move-out-of-overloaded-deref.rs +++ b/src/test/compile-fail/borrowck-move-out-of-overloaded-deref.rs @@ -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 } diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs index 23ef5331b495..75596af10d70 100644 --- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs @@ -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 diff --git a/src/test/compile-fail/borrowck-overloaded-index-2.rs b/src/test/compile-fail/borrowck-overloaded-index-2.rs index 5e6d235574e6..334f14349d72 100644 --- a/src/test/compile-fail/borrowck-overloaded-index-2.rs +++ b/src/test/compile-fail/borrowck-overloaded-index-2.rs @@ -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 } diff --git a/src/test/compile-fail/borrowck-overloaded-index-and-overloaded-deref.rs b/src/test/compile-fail/borrowck-overloaded-index-and-overloaded-deref.rs new file mode 100644 index 000000000000..4188cf001423 --- /dev/null +++ b/src/test/compile-fail/borrowck-overloaded-index-and-overloaded-deref.rs @@ -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 or the MIT license +// , 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 { x: T } + +impl Index for MyVec { + type Output = T; + fn index(&self, _: &usize) -> &T { + &self.x + } +} + +struct MyPtr { x: T } + +impl Deref for MyPtr { + 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) { } + diff --git a/src/test/compile-fail/borrowck-overloaded-index.rs b/src/test/compile-fail/borrowck-overloaded-index.rs index 80b68dbf519e..f4f4d983e009 100644 --- a/src/test/compile-fail/borrowck-overloaded-index.rs +++ b/src/test/compile-fail/borrowck-overloaded-index.rs @@ -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 } diff --git a/src/test/compile-fail/dst-index.rs b/src/test/compile-fail/dst-index.rs index e297ecaac233..c64cc13bbe2e 100644 --- a/src/test/compile-fail/dst-index.rs +++ b/src/test/compile-fail/dst-index.rs @@ -41,9 +41,9 @@ impl Index 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 } diff --git a/src/test/compile-fail/dst-rvalue.rs b/src/test/compile-fail/dst-rvalue.rs index 74e952364cd4..faae0009a934 100644 --- a/src/test/compile-fail/dst-rvalue.rs +++ b/src/test/compile-fail/dst-rvalue.rs @@ -15,10 +15,10 @@ pub fn main() { let _x: Box = 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 } diff --git a/src/test/compile-fail/issue-12567.rs b/src/test/compile-fail/issue-12567.rs index 26866cbbc603..d186a83676a8 100644 --- a/src/test/compile-fail/issue-12567.rs +++ b/src/test/compile-fail/issue-12567.rs @@ -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 } } diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index d3678f7d87fd..fbecd0487bf6 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -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] } diff --git a/src/test/compile-fail/issue-2590.rs b/src/test/compile-fail/issue-2590.rs index 79a66e30fdb9..07aea4fd633b 100644 --- a/src/test/compile-fail/issue-2590.rs +++ b/src/test/compile-fail/issue-2590.rs @@ -19,7 +19,7 @@ trait parse { impl parse for parser { fn parse(&self) -> Vec { - self.tokens //~ ERROR cannot move out of dereference of `&`-pointer + self.tokens //~ ERROR cannot move out of borrowed content } } diff --git a/src/test/compile-fail/method-self-arg-2.rs b/src/test/compile-fail/method-self-arg-2.rs index 0ac0851619c5..ad255ecd9c06 100644 --- a/src/test/compile-fail/method-self-arg-2.rs +++ b/src/test/compile-fail/method-self-arg-2.rs @@ -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 } diff --git a/src/test/compile-fail/slice-mut-2.rs b/src/test/compile-fail/slice-mut-2.rs index 12f184d410c9..09357d328cd1 100644 --- a/src/test/compile-fail/slice-mut-2.rs +++ b/src/test/compile-fail/slice-mut-2.rs @@ -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 } diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs index 9bd9a752e4e8..f68554b9ec79 100644 --- a/src/test/compile-fail/slice-mut.rs +++ b/src/test/compile-fail/slice-mut.rs @@ -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 } diff --git a/src/test/compile-fail/std-uncopyable-atomics.rs b/src/test/compile-fail/std-uncopyable-atomics.rs index 5ebabc2e3548..81cf9c1bdcf1 100644 --- a/src/test/compile-fail/std-uncopyable-atomics.rs +++ b/src/test/compile-fail/std-uncopyable-atomics.rs @@ -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 = AtomicPtr::new(ptr::null_mut()); - let x = *&x; //~ ERROR: cannot move out of dereference + let x = *&x; //~ ERROR: cannot move out of borrowed content } diff --git a/src/test/compile-fail/unop-move-semantics.rs b/src/test/compile-fail/unop-move-semantics.rs index f8cbdb4e160b..946566675981 100644 --- a/src/test/compile-fail/unop-move-semantics.rs +++ b/src/test/compile-fail/unop-move-semantics.rs @@ -31,9 +31,9 @@ fn illegal_dereference>(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() {}