]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #20751: nikomatsakis/issue-20232
authorAlex Crichton <alex@alexcrichton.com>
Thu, 8 Jan 2015 17:22:10 +0000 (09:22 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 8 Jan 2015 17:22:10 +0000 (09:22 -0800)
Issue #20232. Fun.

r? @eddyb you prob know this system best

28 files changed:
src/librustc/middle/mem_categorization.rs
src/librustc_borrowck/borrowck/gather_loans/move_error.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/test/compile-fail/binop-move-semantics.rs
src/test/compile-fail/borrowck-borrow-immut-deref-of-box-as-mut.rs
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
src/test/compile-fail/borrowck-move-in-irrefut-pat.rs
src/test/compile-fail/borrowck-move-out-of-overloaded-auto-deref.rs
src/test/compile-fail/borrowck-move-out-of-overloaded-deref.rs
src/test/compile-fail/borrowck-move-out-of-vec-tail.rs
src/test/compile-fail/borrowck-overloaded-index-2.rs
src/test/compile-fail/borrowck-overloaded-index-and-overloaded-deref.rs [new file with mode: 0644]
src/test/compile-fail/borrowck-overloaded-index.rs
src/test/compile-fail/dst-index.rs
src/test/compile-fail/dst-rvalue.rs
src/test/compile-fail/issue-12567.rs
src/test/compile-fail/issue-17651.rs
src/test/compile-fail/issue-2590.rs
src/test/compile-fail/method-self-arg-2.rs
src/test/compile-fail/slice-mut-2.rs
src/test/compile-fail/slice-mut.rs
src/test/compile-fail/std-uncopyable-atomics.rs
src/test/compile-fail/unop-move-semantics.rs

index fb9a16f86e5bcb730a4805155de58a871d969d4d..51ec75284326c4f76f9b790ef99b19cc654b76a4 100644 (file)
@@ -75,7 +75,7 @@
 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 @@ pub fn cat_expr_autoderefd(&self,
                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 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
         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 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
                     // 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 @@ pub fn cat_tup_field<N:ast_node>(&self,
     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 @@ fn cat_deref<N:ast_node>(&self,
         };
         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 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
             // 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 @@ pub fn upvar(&self) -> Option<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 @@ fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
                 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 @@ fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
             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 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
                 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)
+    }
+}
+
index a7771fefec412c4453643eee6d4b70a60d7682e0..28d02161eebd7e470ef93c3e76679e9d7a4bd2d0 100644 (file)
@@ -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")
+        }
     }
 }
 
index e734e8fb6ffb70c24b668becfb587d4485d4aeb1..b87fed1601c51a3db3a33906464774547cec731d 100644 (file)
@@ -681,6 +681,10 @@ pub fn span_err(&self, s: Span, m: &str) {
         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);
     }
index dff216ac2935f99ff386fb77b2cca799adbc5385..19a88dfc553b68159675280fc4f9195c8e54f5a7 100644 (file)
@@ -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 };
index 7e72f300f417847ba7f071564d4710c5ae46d87a..7946077485976e4cd3bbfa8128f4f7b97865f8b0 100644 (file)
@@ -143,7 +143,7 @@ fn adjust_self_ty(&mut self,
         // 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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
                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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
             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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
                         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 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
                         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);
                         }
                     }
index bb000742def9290918c004e8273a133abfa136a5..0c53a16a8118b2a76d746d6f0e749b2aa02c311d 100644 (file)
@@ -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>,
index b98b327100cdb7e1abb2e8344298679638cca359..084a457909c5ce5dacd9e2f8afc4dfd2418d9a54 100644 (file)
@@ -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_field(fcx: &FnCtxt,
                                                 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_tup_field(fcx: &FnCtxt,
         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);
index 112e00536422c2f26556addc082e2d29380c3771..3b5027dbb9e69c22a0eedc4a26e9354386ba0928 100644 (file)
@@ -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;
index ffc38cc0a6005557eb0f2c17214fb03005848aae..cff0064497aff34ac814b8be55d4a1b9c4e64b9d 100644 (file)
@@ -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;
index 84f4e4f8817ca320dbe94837ed014a4f41d22a04..794e0fc6e3aba95ab10168acd24d51a96b0d0ffd 100644 (file)
@@ -20,5 +20,5 @@ fn foo(&mut self) {
 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
 }
index 9aec8de46b6d994151c9c9be9304d5fee5071217..d5df12513465644ac06031915856439635158720 100644 (file)
@@ -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) {
index c5d23925a89b1f2d25c5470e2b43ea00a318457c..ec505faf88502ca3de07e5014f1b0c75dcd84f33 100644 (file)
 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() {}
index a6723a04611af3ed0ef87d9092bfc8507b0e2257..a13efdea5621e1e8c96d2716dfa4dd908ae97d61 100644 (file)
@@ -12,5 +12,5 @@
 
 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
 }
index 8a93790d5a2989f9f8930a068684da86b331b57f..fffcf575ab08e49318f50d2325da200465d31f6c 100644 (file)
@@ -12,5 +12,5 @@
 
 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
 }
index 23ef5331b495f0fabcbee953aee4da5a4f22df9e..75596af10d70ede28c6702cf690f32141fe3b97a 100644 (file)
@@ -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
index 5e6d235574e69e1e68130086ad9f497943b6977b..334f14349d723dd219e1a5191ebeab07a9c4ce66 100644 (file)
@@ -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 (file)
index 0000000..4188cf0
--- /dev/null
@@ -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) { }
+
index 80b68dbf519eefb62325a0f1383778e1a4d2cb9c..f4f4d983e009b998c0f01f44a470f3d40d51eab1 100644 (file)
@@ -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
 }
index e297ecaac233e49da769b1e22cde3f875ce57f6d..c64cc13bbe2eaab5ae6f38de3a0fb84fc81d2026 100644 (file)
@@ -41,9 +41,9 @@ fn index<'a>(&'a self, idx: &uint) -> &'a (Show + 'static) {
 
 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
 }
index 74e952364cd4523dd8fed3f751eda3bfa88c3671..faae0009a934c4eb4d6adb0ff8fab3e2ef06274c 100644 (file)
 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
 }
index 26866cbbc6033c85e5de3a9536caf879226b0491..d186a83676a804abf601b48d5372eaa6eacfe09b 100644 (file)
@@ -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
     }
 }
 
index d3678f7d87fdbd9ca085d551bf48da9f2176b36b..fbecd0487bf6f5d7811752cfd71c9a24a3d12e80 100644 (file)
@@ -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]
 }
index 79a66e30fdb916cc8ba22daf31009fd188ce678c..07aea4fd633b427d5b6b6f495e5d8d8acba05d72 100644 (file)
@@ -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
     }
 }
 
index 0ac0851619c59e4f094ca6cd3bd4bf2a99ff94ca..ad255ecd9c0642f96c1e6782f5ac04c1e0f91ab9 100644 (file)
@@ -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
 }
index 12f184d410c900e3539021c81c6a77c115941c0e..09357d328cd18c08f27831e72953dcfd6505b135 100644 (file)
@@ -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
 }
index 9bd9a752e4e890e0574db32ca22e0975d7871f77..f68554b9ec79e256eb04925c56037f869612690c 100644 (file)
@@ -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
 }
index 5ebabc2e3548c1032eb007b08db97dc2e9b09d48..81cf9c1bdcf1a1b5953c728eaa5feb0d93c5744a 100644 (file)
 
 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
 }
index f8cbdb4e160bf4cc18cfa7fc3eddd1a3f0b4dce2..946566675981e7020327aa8aca735f9e14490e75 100644 (file)
@@ -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() {}