about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-02 03:51:49 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-03 07:00:51 -0500
commitf7abf47058e73ea4a95031fb80d92f636e5a18f9 (patch)
treed0bb9e145ab3ed2c82ad58cf755eeeca9b8f63c0
parentfc2ba13939aa9672d886beb06efde7aeda2d5f7f (diff)
downloadrust-f7abf47058e73ea4a95031fb80d92f636e5a18f9.tar.gz
rust-f7abf47058e73ea4a95031fb80d92f636e5a18f9.zip
Re-introduce `McResult<>` as a way of aborting mem-categorization (and
expr-use-visitor) early.  Turns out I was wrong to remove this; it
causes a lot of pain trying to run EUV etc during typeck without
ICEing on erroneous programs.
-rw-r--r--src/librustc/middle/expr_use_visitor.rs79
-rw-r--r--src/librustc/middle/mem_categorization.rs167
-rw-r--r--src/librustc/middle/ty.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs23
-rw-r--r--src/librustc_typeck/check/regionck.rs31
5 files changed, 175 insertions, 130 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index d36c85342ce..06815266266 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -300,6 +300,20 @@ pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> {
     mc: mc::MemCategorizationContext<'t,TYPER>,
     delegate: &'d mut (Delegate<'tcx>+'d),
     param_env: &'t ParameterEnvironment<'tcx>,
+// If the TYPER results in an error, it's because the type check
+// failed (or will fail, when the error is uncovered and reported
+// during writeback). In this case, we just ignore this part of the
+// code.
+//
+// Note that this macro appears similar to try!(), but, unlike try!(),
+// it does not propagate the error.
+macro_rules! return_if_err {
+    ($inp: expr) => (
+        match $inp {
+            Ok(v) => v,
+            Err(()) => return
+        }
+    )
 }
 
 /// Whether the elements of an overloaded operation are passed by value or by reference
@@ -332,7 +346,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                          decl: &ast::FnDecl,
                          body: &ast::Block) {
         for arg in decl.inputs.iter() {
-            let arg_ty = self.typer.node_ty(arg.pat.id);
+            let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id));
 
             let fn_body_scope = region::CodeExtent::from_node_id(body.id);
             let arg_cmt = self.mc.cat_rvalue(
@@ -369,7 +383,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     pub fn consume_expr(&mut self, expr: &ast::Expr) {
         debug!("consume_expr(expr={})", expr.repr(self.tcx()));
 
-        let cmt = self.mc.cat_expr(expr);
+        let cmt = return_if_err!(self.mc.cat_expr(expr));
         self.delegate_consume(expr.id, expr.span, cmt);
         self.walk_expr(expr);
     }
@@ -378,7 +392,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                    assignment_expr: &ast::Expr,
                    expr: &ast::Expr,
                    mode: MutateMode) {
-        let cmt = self.mc.cat_expr(expr);
+        let cmt = return_if_err!(self.mc.cat_expr(expr));
         self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
         self.walk_expr(expr);
     }
@@ -391,7 +405,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
         debug!("borrow_expr(expr={}, r={}, bk={})",
                expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
 
-        let cmt = self.mc.cat_expr(expr);
+        let cmt = return_if_err!(self.mc.cat_expr(expr));
         self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
 
         // Note: Unlike consume, we can ignore ExprParen. cat_expr
@@ -491,7 +505,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             }
 
             ast::ExprMatch(ref discr, ref arms, _) => {
-                let discr_cmt = self.mc.cat_expr(&**discr);
+                let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr));
                 self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
 
                 // treatment of the discriminant is handled while walking the arms.
@@ -509,7 +523,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             ast::ExprAddrOf(m, ref base) => {   // &base
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
-                let expr_ty = ty::expr_ty(self.tcx(), expr);
+                let expr_ty = return_if_err!(self.typer.node_ty(expr.id));
                 let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
                 let bk = ty::BorrowKind::from_mutbl(m);
                 self.borrow_expr(&**base, r, bk, AddrOf);
@@ -550,7 +564,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
 
                 // Fetch the type of the value that the iteration yields to
                 // produce the pattern's categorized mutable type.
-                let pattern_type = self.typer.node_ty(pat.id);
+                let pattern_type = return_if_err!(self.typer.node_ty(pat.id));
                 let blk_scope = region::CodeExtent::from_node_id(blk.id);
                 let pat_cmt = self.mc.cat_rvalue(pat.id,
                                                  pat.span,
@@ -638,7 +652,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     }
 
     fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
-        let callee_ty = self.typer.expr_ty_adjusted(callee);
+        let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
         debug!("walk_callee: callee={} callee_ty={}",
                callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
         let call_scope = region::CodeExtent::from_node_id(call.id);
@@ -735,7 +749,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                 // "assigns", which is handled by
                 // `walk_pat`:
                 self.walk_expr(&**expr);
-                let init_cmt = self.mc.cat_expr(&**expr);
+                let init_cmt = return_if_err!(self.mc.cat_expr(&**expr));
                 self.walk_irrefutable_pat(init_cmt, &*local.pat);
             }
         }
@@ -769,7 +783,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             None => { return; }
         };
 
-        let with_cmt = self.mc.cat_expr(&*with_expr);
+        let with_cmt = return_if_err!(self.mc.cat_expr(&*with_expr));
 
         // Select just those fields of the `with`
         // expression that will actually be used
@@ -824,7 +838,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         // rvalue.
                         debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
                         let cmt_unadjusted =
-                            self.mc.cat_expr_unadjusted(expr);
+                            return_if_err!(self.mc.cat_expr_unadjusted(expr));
                         self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
                     }
                     ty::AdjustDerefRef(ty::AutoDerefRef {
@@ -858,7 +872,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             match self.typer.node_method_ty(deref_id) {
                 None => {}
                 Some(method_ty) => {
-                    let cmt = self.mc.cat_expr_autoderefd(expr, i);
+                    let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
                     let self_ty = ty::ty_fn_args(method_ty)[0];
                     let (m, r) = match self_ty.sty {
                         ty::ty_rptr(r, ref m) => (m.mutbl, r),
@@ -888,14 +902,15 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                 assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
                                          AutoRefs, found: {}", n));
                 let cmt_unadjusted =
-                    self.mc.cat_expr_unadjusted(expr);
+                    return_if_err!(self.mc.cat_expr_unadjusted(expr));
                 self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
                 return;
             }
             _ => {}
         }
 
-        let cmt_derefd = self.mc.cat_expr_autoderefd(expr, n);
+        let cmt_derefd = return_if_err!(
+            self.mc.cat_expr_autoderefd(expr, n));
         debug!("walk_adjustment: cmt_derefd={}",
                cmt_derefd.repr(self.tcx()));
 
@@ -988,7 +1003,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                                mode: &mut TrackMatchMode<Span>) {
         debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
                pat.repr(self.tcx()));
-        self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
+        return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
             let tcx = self.typer.tcx();
             let def_map = &self.typer.tcx().def_map;
             if pat_util::pat_is_binding(def_map, pat) {
@@ -1011,7 +1026,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     }
                 }
             }
-        });
+        }));
     }
 
     /// The core driver for walking a pattern; `match_mode` must be
@@ -1028,8 +1043,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
         let typer = self.typer;
         let def_map = &self.typer.tcx().def_map;
         let delegate = &mut self.delegate;
-        let param_env = self.param_env;
-        mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
+        return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
             if pat_util::pat_is_binding(def_map, pat) {
                 let tcx = typer.tcx();
 
@@ -1039,7 +1053,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                        match_mode);
 
                 // pat_ty: the type of the binding being produced.
-                let pat_ty = typer.node_ty(pat.id);
+                let pat_ty = return_if_err!(typer.node_ty(pat.id));
 
                 // Each match binding is effectively an assignment to the
                 // binding being produced.
@@ -1080,7 +1094,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         // matched.
 
                         let (slice_cmt, slice_mutbl, slice_r) =
-                            mc.cat_slice_pattern(cmt_pat, &**slice_pat);
+                            return_if_err!(mc.cat_slice_pattern(cmt_pat, &**slice_pat));
 
                         // Note: We declare here that the borrow
                         // occurs upon entering the `[...]`
@@ -1110,13 +1124,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     _ => { }
                 }
             }
-        });
+        }));
 
         // Do a second pass over the pattern, calling `matched_pat` on
         // the interior nodes (enum variants and structs), as opposed
         // to the above loop's visit of than the bindings that form
         // the leaves of the pattern tree structure.
-        mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
+        return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
             let def_map = def_map.borrow();
             let tcx = typer.tcx();
 
@@ -1197,7 +1211,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     // cases either.
                 }
             }
-        });
+        }));
     }
 
     fn walk_captures(&mut self, closure_expr: &ast::Expr) {
@@ -1221,9 +1235,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                             freevars: &[ty::Freevar]) {
         for freevar in freevars.iter() {
             let id_var = freevar.def.def_id().node;
-            let cmt_var = self.cat_captured_var(closure_expr.id,
-                                                closure_expr.span,
-                                                freevar.def);
+            let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
+                                                               closure_expr.span,
+                                                               freevar.def));
 
             // Lookup the kind of borrow the callee requires, as
             // inferred by regionbk
@@ -1244,11 +1258,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                               closure_expr: &ast::Expr,
                               freevars: &[ty::Freevar]) {
         for freevar in freevars.iter() {
-            let cmt_var = self.cat_captured_var(closure_expr.id,
-                                                closure_expr.span,
-                                                freevar.def);
-            let mode = copy_or_move(self.tcx(), cmt_var.ty,
-                                    self.param_env, CaptureMove);
+            let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
+                                                               closure_expr.span,
+                                                               freevar.def));
+            let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
             self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
         }
     }
@@ -1257,11 +1270,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         closure_id: ast::NodeId,
                         closure_span: Span,
                         upvar_def: def::Def)
-                        -> mc::cmt<'tcx> {
+                        -> mc::McResult<mc::cmt<'tcx>> {
         // Create the cmt for the variable being borrowed, from the
         // caller's perspective
         let var_id = upvar_def.def_id().node;
-        let var_ty = self.typer.node_ty(var_id);
+        let var_ty = try!(self.typer.node_ty(var_id));
         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
     }
 }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 70942a950e3..dbe005ea63d 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::{mod, Ty};
 use util::nodemap::{NodeMap};
-use util::ppaux::{ty_to_string, Repr};
+use util::ppaux::{Repr};
 
 use syntax::ast::{MutImmutable, MutMutable};
 use syntax::ast;
@@ -264,6 +264,8 @@ pub struct MemCategorizationContext<'t,TYPER:'t> {
 
 impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
 
+pub type McResult<T> = Result<T, ()>;
+
 /// The `Typer` trait provides the interface for the mem-categorization
 /// module to the results of the type check. It can be used to query
 /// the type assigned to an expression node, to inquire after adjustments,
@@ -282,8 +284,10 @@ impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
 /// can be sure that only `Ok` results will occur.
 pub trait Typer<'tcx> : ty::UnboxedClosureTyper<'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
-    fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx>;
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx>;
+    fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
+    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>;
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>>;
+    fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool;
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>>;
     fn node_method_origin(&self, method_call: ty::MethodCall)
                           -> Option<ty::MethodOrigin<'tcx>>;
@@ -382,22 +386,22 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         self.typer.tcx()
     }
 
-    fn expr_ty(&self, expr: &ast::Expr) -> Ty<'tcx> {
+    fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
         self.typer.node_ty(expr.id)
     }
 
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
-        let unadjusted_ty = self.expr_ty(expr);
-        ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty,
-                      self.typer.adjustments().borrow().get(&expr.id),
-                      |method_call| self.typer.node_method_ty(method_call))
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
+        let unadjusted_ty = try!(self.expr_ty(expr));
+        Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty,
+                         self.typer.adjustments().borrow().get(&expr.id),
+                         |method_call| self.typer.node_method_ty(method_call)))
     }
 
-    fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
+    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
         self.typer.node_ty(id)
     }
 
-    fn pat_ty(&self, pat: &ast::Pat) -> Ty<'tcx> {
+    fn pat_ty(&self, pat: &ast::Pat) -> McResult<Ty<'tcx>> {
         let tcx = self.typer.tcx();
         let base_ty = self.typer.node_ty(pat.id);
         // FIXME (Issue #18207): This code detects whether we are
@@ -420,7 +424,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         ret_ty
     }
 
-    pub fn cat_expr(&self, expr: &ast::Expr) -> cmt<'tcx> {
+    pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
         match self.typer.adjustments().borrow().get(&expr.id) {
             None => {
                 // No adjustments.
@@ -434,8 +438,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                expr.repr(self.tcx()));
                         // Convert a bare fn to a closure by adding NULL env.
                         // Result is an rvalue.
-                        let expr_ty = self.expr_ty_adjusted(expr);
-                        self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
+                        let expr_ty = try!(self.expr_ty_adjusted(expr));
+                        Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
                     }
 
                     ty::AdjustDerefRef(
@@ -445,8 +449,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                expr.repr(self.tcx()));
                         // Equivalent to &*expr or something similar.
                         // Result is an rvalue.
-                        let expr_ty = self.expr_ty_adjusted(expr);
-                        self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
+                        let expr_ty = try!(self.expr_ty_adjusted(expr));
+                        Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
                     }
 
                     ty::AdjustDerefRef(
@@ -463,46 +467,46 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     pub fn cat_expr_autoderefd(&self,
                                expr: &ast::Expr,
                                autoderefs: uint)
-                               -> cmt<'tcx> {
-        let mut cmt = self.cat_expr_unadjusted(expr);
+                               -> McResult<cmt<'tcx>> {
+        let mut cmt = try!(self.cat_expr_unadjusted(expr));
         debug!("cat_expr_autoderefd: autoderefs={}, cmt={}",
                autoderefs,
                cmt.repr(self.tcx()));
         for deref in range(1u, autoderefs + 1) {
-            cmt = self.cat_deref(expr, cmt, deref, false);
+            cmt = try!(self.cat_deref(expr, cmt, deref, false));
         }
-        return cmt;
+        return Ok(cmt);
     }
 
-    pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> cmt<'tcx> {
+    pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
         debug!("cat_expr: id={} expr={}", expr.id, expr.repr(self.tcx()));
 
-        let expr_ty = self.expr_ty(expr);
+        let expr_ty = try!(self.expr_ty(expr));
         match expr.node {
           ast::ExprUnary(ast::UnDeref, ref e_base) => {
-            let base_cmt = self.cat_expr(&**e_base);
+            let base_cmt = try!(self.cat_expr(&**e_base));
             self.cat_deref(expr, base_cmt, 0, false)
           }
 
           ast::ExprField(ref base, f_name) => {
-            let base_cmt = self.cat_expr(&**base);
+            let base_cmt = try!(self.cat_expr(&**base));
             debug!("cat_expr(cat_field): id={} expr={} base={}",
                    expr.id,
                    expr.repr(self.tcx()),
                    base_cmt.repr(self.tcx()));
-            self.cat_field(expr, base_cmt, f_name.node.name, expr_ty)
+            Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
           }
 
           ast::ExprTupField(ref base, idx) => {
-            let base_cmt = self.cat_expr(&**base);
-            self.cat_tup_field(expr, base_cmt, idx.node, expr_ty)
+            let base_cmt = try!(self.cat_expr(&**base));
+            Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
           }
 
           ast::ExprIndex(ref base, ref idx) => {
             match idx.node {
                 ast::ExprRange(..) => {
                     // Slicing syntax special case (KILLME).
-                    self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
+                    Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
                 }
                 _ => {
                     let method_call = ty::MethodCall::expr(expr.id());
@@ -517,7 +521,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                                                 ret_ty), 1, true)
                         }
                         None => {
-                            self.cat_index(expr, self.cat_expr(&**base))
+                            self.cat_index(expr, try!(self.cat_expr(&**base)))
                         }
                     }
                 }
@@ -545,7 +549,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
           ast::ExprInlineAsm(..) | ast::ExprBox(..) |
           ast::ExprForLoop(..) => {
-            self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
+            Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
           }
 
           ast::ExprIfLet(..) => {
@@ -562,43 +566,43 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                    span: Span,
                    expr_ty: Ty<'tcx>,
                    def: def::Def)
-                   -> cmt<'tcx> {
+                   -> McResult<cmt<'tcx>> {
         debug!("cat_def: id={} expr={} def={}",
                id, expr_ty.repr(self.tcx()), def);
 
         match def {
           def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) |
           def::DefStaticMethod(..) | def::DefConst(..) => {
-                self.cat_rvalue_node(id, span, expr_ty)
+                Ok(self.cat_rvalue_node(id, span, expr_ty))
           }
           def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
           def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
           def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
           def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
           def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
-              Rc::new(cmt_ {
+              Ok(Rc::new(cmt_ {
                   id:id,
                   span:span,
                   cat:cat_static_item,
                   mutbl: McImmutable,
                   ty:expr_ty,
                   note: NoteNone
-              })
+              }))
           }
 
           def::DefStatic(_, mutbl) => {
-              Rc::new(cmt_ {
+              Ok(Rc::new(cmt_ {
                   id:id,
                   span:span,
                   cat:cat_static_item,
                   mutbl: if mutbl { McDeclared } else { McImmutable},
                   ty:expr_ty,
                   note: NoteNone
-              })
+              }))
           }
 
           def::DefUpvar(var_id, fn_node_id, _) => {
-              let ty = self.node_ty(fn_node_id);
+              let ty = try!(self.node_ty(fn_node_id));
               match ty.sty {
                   ty::ty_closure(ref closure_ty) => {
                       // Translate old closure type info into unboxed
@@ -635,14 +639,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           }
 
           def::DefLocal(vid) => {
-            Rc::new(cmt_ {
+            Ok(Rc::new(cmt_ {
                 id: id,
                 span: span,
                 cat: cat_local(vid),
                 mutbl: MutabilityCategory::from_local(self.tcx(), vid),
                 ty: expr_ty,
                 note: NoteNone
-            })
+            }))
           }
         }
     }
@@ -657,7 +661,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                  kind: ty::UnboxedClosureKind,
                  mode: ast::CaptureClause,
                  is_unboxed: bool)
-                 -> cmt<'tcx> {
+                 -> McResult<cmt<'tcx>> {
         // An upvar can have up to 3 components.  The base is a
         // `cat_upvar`.  Next, we add a deref through the implicit
         // environment pointer with an anonymous free region 'env and
@@ -679,7 +683,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         // FnOnce         | copied               | upvar -> &'up bk
         // old stack      | N/A                  | upvar -> &'env mut -> &'up bk
         // old proc/once  | copied               | N/A
-        let var_ty = self.node_ty(var_id);
+        let var_ty = try!(self.node_ty(var_id));
 
         let upvar_id = ty::UpvarId { var_id: var_id,
                                      closure_expr_id: fn_node_id };
@@ -727,7 +731,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         });
 
         // First, switch by capture mode
-        match mode {
+        Ok(match mode {
             ast::CaptureByValue => {
                 let mut base = cmt_ {
                     id: id,
@@ -809,7 +813,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                     note: NoteUpvarRef(upvar_id)
                 })
             }
-        }
+        })
     }
 
     pub fn cat_rvalue_node(&self,
@@ -882,7 +886,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                              base_cmt: cmt<'tcx>,
                              deref_cnt: uint,
                              implicit: bool)
-                             -> cmt<'tcx> {
+                             -> McResult<cmt<'tcx>> {
         let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
             Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
             _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt),
@@ -896,7 +900,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         let method_ty = self.typer.node_method_ty(method_call);
 
         debug!("cat_deref: method_call={} method_ty={}",
-            method_call, method_ty.map(|ty| ty.repr(self.tcx())));
+               method_call, method_ty.map(|ty| ty.repr(self.tcx())));
 
         let base_cmt = match method_ty {
             Some(method_ty) => {
@@ -922,8 +926,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                     deref_cnt: uint,
                                     deref_ty: Ty<'tcx>,
                                     implicit: bool)
-                                    -> cmt<'tcx> {
-        let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
+                                    -> McResult<cmt<'tcx>>
+    {
+        let (m, cat) = match try!(deref_kind(base_cmt.ty)) {
             deref_ptr(ptr) => {
                 let ptr = if implicit {
                     match ptr {
@@ -943,20 +948,20 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                 (base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
             }
         };
-        Rc::new(cmt_ {
+        Ok(Rc::new(cmt_ {
             id: node.id(),
             span: node.span(),
             cat: cat,
             mutbl: m,
             ty: deref_ty,
             note: NoteNone
-        })
+        }))
     }
 
     pub fn cat_index<N:ast_node>(&self,
                                  elt: &N,
                                  mut base_cmt: cmt<'tcx>)
-                                 -> cmt<'tcx> {
+                                 -> McResult<cmt<'tcx>> {
         //! Creates a cmt for an indexing operation (`[]`).
         //!
         //! One subtle aspect of indexing that may not be
@@ -1021,15 +1026,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     fn deref_vec<N:ast_node>(&self,
                              elt: &N,
                              base_cmt: cmt<'tcx>)
-                             -> cmt<'tcx> {
-        match deref_kind(self.tcx(), base_cmt.ty) {
+                             -> McResult<cmt<'tcx>>
+    {
+        match try!(deref_kind(base_cmt.ty)) {
             deref_ptr(ptr) => {
                 // for unique ptrs, we inherit mutability from the
                 // owning reference.
                 let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
 
                 // the deref is explicit in the resulting cmt
-                Rc::new(cmt_ {
+                Ok(Rc::new(cmt_ {
                     id:elt.id(),
                     span:elt.span(),
                     cat:cat_deref(base_cmt.clone(), 0, ptr),
@@ -1039,11 +1045,11 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                         None => self.tcx().sess.bug("Found non-derefable type")
                     },
                     note: NoteNone
-                })
+                }))
             }
 
             deref_interior(_) => {
-                base_cmt
+                Ok(base_cmt)
             }
         }
     }
@@ -1058,13 +1064,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     pub fn cat_slice_pattern(&self,
                              vec_cmt: cmt<'tcx>,
                              slice_pat: &ast::Pat)
-                             -> (cmt<'tcx>, ast::Mutability, ty::Region) {
-        let slice_ty = self.node_ty(slice_pat.id);
+                             -> McResult<(cmt<'tcx>, ast::Mutability, ty::Region)> {
+        let slice_ty = try!(self.node_ty(slice_pat.id));
         let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(),
                                                     slice_pat,
                                                     slice_ty);
-        let cmt_slice = self.cat_index(slice_pat, self.deref_vec(slice_pat, vec_cmt));
-        return (cmt_slice, slice_mutbl, slice_r);
+        let cmt_slice = try!(self.cat_index(slice_pat, try!(self.deref_vec(slice_pat, vec_cmt))));
+        return Ok((cmt_slice, slice_mutbl, slice_r));
 
         /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
         /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
@@ -1119,15 +1125,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         })
     }
 
-    pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) where
-        F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
+    pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) -> McResult<()>
+        where F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
     {
         self.cat_pattern_(cmt, pat, &mut op)
     }
 
     // FIXME(#19596) This is a workaround, but there should be a better way to do this
-    fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F) where
-        F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
+    fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
+                       -> McResult<()>
+        where F : FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
     {
         // Here, `cmt` is the categorization for the value being
         // matched and pat is the pattern it is being matched against.
@@ -1208,29 +1215,29 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                 Some(&def::DefVariant(..)) => {
                     // variant(x, y, z)
                     for (i, subpat) in subpats.iter().enumerate() {
-                        let subpat_ty = self.pat_ty(&**subpat); // see (*2)
+                        let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
 
                         let subcmt =
                             self.cat_imm_interior(
                                 pat, cmt.clone(), subpat_ty,
                                 InteriorField(PositionalField(i)));
 
-                        self.cat_pattern_(subcmt, &**subpat, op);
+                        try!(self.cat_pattern_(subcmt, &**subpat, op));
                     }
                 }
                 Some(&def::DefStruct(..)) => {
                     for (i, subpat) in subpats.iter().enumerate() {
-                        let subpat_ty = self.pat_ty(&**subpat); // see (*2)
+                        let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
                         let cmt_field =
                             self.cat_imm_interior(
                                 pat, cmt.clone(), subpat_ty,
                                 InteriorField(PositionalField(i)));
-                        self.cat_pattern_(cmt_field, &**subpat, op);
+                        try!(self.cat_pattern_(cmt_field, &**subpat, op));
                     }
                 }
                 Some(&def::DefConst(..)) => {
                     for subpat in subpats.iter() {
-                        self.cat_pattern_(cmt.clone(), &**subpat, op);
+                        try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
                     }
                 }
                 _ => {
@@ -1242,7 +1249,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           }
 
           ast::PatIdent(_, _, Some(ref subpat)) => {
-              self.cat_pattern_(cmt, &**subpat, op);
+              try!(self.cat_pattern_(cmt, &**subpat, op));
           }
 
           ast::PatIdent(_, _, None) => {
@@ -1252,42 +1259,42 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           ast::PatStruct(_, ref field_pats, _) => {
             // {f1: p1, ..., fN: pN}
             for fp in field_pats.iter() {
-                let field_ty = self.pat_ty(&*fp.node.pat); // see (*2)
+                let field_ty = try!(self.pat_ty(&*fp.node.pat)); // see (*2)
                 let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.ident.name, field_ty);
-                self.cat_pattern_(cmt_field, &*fp.node.pat, op);
+                try!(self.cat_pattern_(cmt_field, &*fp.node.pat, op));
             }
           }
 
           ast::PatTup(ref subpats) => {
             // (p1, ..., pN)
             for (i, subpat) in subpats.iter().enumerate() {
-                let subpat_ty = self.pat_ty(&**subpat); // see (*2)
+                let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
                 let subcmt =
                     self.cat_imm_interior(
                         pat, cmt.clone(), subpat_ty,
                         InteriorField(PositionalField(i)));
-                self.cat_pattern_(subcmt, &**subpat, op);
+                try!(self.cat_pattern_(subcmt, &**subpat, op));
             }
           }
 
           ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
             // @p1, ~p1, ref p1
-            let subcmt = self.cat_deref(pat, cmt, 0, false);
-            self.cat_pattern_(subcmt, &**subpat, op);
+            let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
+              try!(self.cat_pattern_(subcmt, &**subpat, op));
           }
 
           ast::PatVec(ref before, ref slice, ref after) => {
-              let elt_cmt = self.cat_index(pat, self.deref_vec(pat, cmt));
+              let elt_cmt = try!(self.cat_index(pat, try!(self.deref_vec(pat, cmt))));
               for before_pat in before.iter() {
-                  self.cat_pattern_(elt_cmt.clone(), &**before_pat, op);
+                  try!(self.cat_pattern_(elt_cmt.clone(), &**before_pat, op));
               }
               for slice_pat in slice.iter() {
-                  let slice_ty = self.pat_ty(&**slice_pat);
+                  let slice_ty = try!(self.pat_ty(&**slice_pat));
                   let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
-                  self.cat_pattern_(slice_cmt, &**slice_pat, op);
+                  try!(self.cat_pattern_(slice_cmt, &**slice_pat, op));
               }
               for after_pat in after.iter() {
-                  self.cat_pattern_(elt_cmt.clone(), &**after_pat, op);
+                  try!(self.cat_pattern_(elt_cmt.clone(), &**after_pat, op));
               }
           }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 999bc23c270..079972eff67 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -5708,7 +5708,10 @@ pub fn unboxed_closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
             freevars.iter()
                     .map(|freevar| {
                         let freevar_def_id = freevar.def.def_id();
-                        let freevar_ty = typer.node_ty(freevar_def_id.node);
+                        let freevar_ty = match typer.node_ty(freevar_def_id.node) {
+                            Ok(t) => { t }
+                            Err(()) => { return None; }
+                        };
                         let freevar_ty = freevar_ty.subst(tcx, substs);
 
                         match capture_mode {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 19ec85dc61e..189798a1390 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -289,12 +289,17 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
         self.ccx.tcx
     }
     fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
+    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
         let ty = self.node_ty(id);
-        self.infcx().resolve_type_vars_if_possible(&ty)
+        self.resolve_type_vars_or_error(&ty)
     }
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
-        let ty = self.expr_ty_adjusted(expr);
-        self.infcx().resolve_type_vars_if_possible(&ty)
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
+        let ty = self.adjust_expr_ty(expr, self.inh.adjustments.borrow().get(&expr.id));
+        self.resolve_type_vars_or_error(&ty)
+    }
+    fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
+        let ty = self.infcx().resolve_type_vars_if_possible(&ty);
+        traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span)
     }
     fn node_method_ty(&self, method_call: ty::MethodCall)
                       -> Option<Ty<'tcx>> {
@@ -1671,6 +1676,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.ccx.tcx.sess.err_count() - self.err_count_on_creation
     }
 
+    /// Resolves all type variables in `t` and then, if any were left
+    /// unresolved, substitutes an error type. This is used after the
+    /// main checking when doing a second pass before writeback. The
+    /// justification is that writeback will produce an error for
+    /// these unconstrained type variables.
+    fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
+        let t = self.infcx().resolve_type_vars_if_possible(t);
+        if ty::type_has_ty_infer(t) || ty::type_is_error(t) { Err(()) } else { Ok(t) }
+    }
+
     pub fn tag(&self) -> String {
         format!("{}", self as *const FnCtxt)
     }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index d01b79068aa..0631b0edb4f 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -140,6 +140,10 @@ use std::collections::hash_map::Entry::{Vacant, Occupied};
 use self::RepeatingScope::Repeating;
 use self::SubjectNode::Subject;
 
+// a variation on try that just returns unit
+macro_rules! ignore_err {
+    ($e:expr) => (match $e { Ok(e) => e, Err(_) => return () })
+}
 
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
@@ -1027,7 +1031,7 @@ fn constrain_callee(rcx: &mut Rcx,
                     // While we're here, link the closure's region with a unique
                     // immutable borrow (gathered later in borrowck)
                     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-                    let expr_cmt = mc.cat_expr(callee_expr);
+                    let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
                     link_region(rcx, callee_expr.span, call_region,
                                 ty::UniqueImmBorrow, expr_cmt);
                     r
@@ -1136,7 +1140,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                 };
                 {
                     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-                    let self_cmt = mc.cat_expr_autoderefd(deref_expr, i);
+                    let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                     link_region(rcx, deref_expr.span, *r,
                                 ty::BorrowKind::from_mutbl(m), self_cmt);
                 }
@@ -1232,7 +1236,7 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
 
     let cmt = {
         let mc = mc::MemCategorizationContext::new(rcx.fcx);
-        mc.cat_expr(base)
+        ignore_err!(mc.cat_expr(base))
     };
     link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
 }
@@ -1247,7 +1251,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
         Some(ref expr) => &**expr,
     };
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-    let discr_cmt = mc.cat_expr(init_expr);
+    let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
     link_pattern(rcx, mc, discr_cmt, &*local.pat);
 }
 
@@ -1257,7 +1261,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
     debug!("regionck::for_match()");
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-    let discr_cmt = mc.cat_expr(discr);
+    let discr_cmt = ignore_err!(mc.cat_expr(discr));
     debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
     for arm in arms.iter() {
         for root_pat in arm.pats.iter() {
@@ -1303,11 +1307,14 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 
                 // `[_, ..slice, _]` pattern
                 ast::PatVec(_, Some(ref slice_pat), _) => {
-                    let (slice_cmt, slice_mutbl, slice_r) =
-                        mc.cat_slice_pattern(sub_cmt, &**slice_pat);
-                    link_region(rcx, sub_pat.span, slice_r,
-                                ty::BorrowKind::from_mutbl(slice_mutbl),
-                                slice_cmt);
+                    match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
+                        Ok((slice_cmt, slice_mutbl, slice_r)) => {
+                            link_region(rcx, sub_pat.span, slice_r,
+                                        ty::BorrowKind::from_mutbl(slice_mutbl),
+                                        slice_cmt);
+                        }
+                        Err(()) => {}
+                    }
                 }
                 _ => {}
             }
@@ -1323,7 +1330,7 @@ fn link_autoref(rcx: &Rcx,
 
     debug!("link_autoref(autoref={})", autoref);
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-    let expr_cmt = mc.cat_expr_autoderefd(expr, autoderefs);
+    let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
     debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
 
     match *autoref {
@@ -1345,7 +1352,7 @@ fn link_by_ref(rcx: &Rcx,
     debug!("link_by_ref(expr={}, callee_scope={})",
            expr.repr(tcx), callee_scope);
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
-    let expr_cmt = mc.cat_expr(expr);
+    let expr_cmt = ignore_err!(mc.cat_expr(expr));
     let borrow_region = ty::ReScope(callee_scope);
     link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
 }