about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-02 04:01:30 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-03 07:01:21 -0500
commit83ef3042de889db07b819fc6b2802cd0ace7e21c (patch)
tree646cc51892b652481984e7989823cd6fd6fd7f3f /src
parent429d9cce1b4b1f94672981986f049b52b341c9f7 (diff)
downloadrust-83ef3042de889db07b819fc6b2802cd0ace7e21c.tar.gz
rust-83ef3042de889db07b819fc6b2802cd0ace7e21c.zip
Modify `type_known_to_meet_builtin_bound` so that it doesn't suppress overflow,
which should always result in an error.

NB. Some of the hunks in this commit rely on a later commit which adds
`tcx` into `param_env` and modifies `ParameterEnvironment` to
implement `Typer`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/lint/builtin.rs10
-rw-r--r--src/librustc/middle/check_match.rs4
-rw-r--r--src/librustc/middle/check_rvalues.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs25
-rw-r--r--src/librustc/middle/intrinsicck.rs12
-rw-r--r--src/librustc/middle/traits/error_reporting.rs8
-rw-r--r--src/librustc/middle/traits/mod.rs91
-rw-r--r--src/librustc/middle/ty.rs50
-rw-r--r--src/librustc_trans/trans/_match.rs5
-rw-r--r--src/librustc_trans/trans/common.rs4
-rw-r--r--src/librustc_trans/trans/datum.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
13 files changed, 149 insertions, 77 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index c314fba91d5..53249c72462 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1612,15 +1612,11 @@ impl LintPass for MissingCopyImplementations {
             }
             _ => return,
         };
-        let parameter_environment = ty::empty_parameter_environment();
-        if !ty::type_moves_by_default(cx.tcx,
-                                      ty,
-                                      &parameter_environment) {
+        let parameter_environment = ty::empty_parameter_environment(cx.tcx);
+        if !ty::type_moves_by_default(&parameter_environment, item.span, ty) {
             return
         }
-        if ty::can_type_implement_copy(cx.tcx,
-                                       ty,
-                                       &parameter_environment).is_ok() {
+        if ty::can_type_implement_copy(&parameter_environment, item.span, ty).is_ok() {
             cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
                          item.span,
                          "type could implement `Copy`; consider adding `impl \
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index d16224ec5b8..7952c99dd79 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -1032,9 +1032,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                 match p.node {
                     ast::PatIdent(ast::BindByValue(_), _, ref sub) => {
                         let pat_ty = ty::node_id_to_type(tcx, p.id);
-                        if ty::type_moves_by_default(tcx,
-                                                      pat_ty,
-                                                      &cx.param_env) {
+                        if ty::type_moves_by_default(&cx.param_env, pat.span, pat_ty) {
                             check_move(p, sub.as_ref().map(|p| &**p));
                         }
                     }
diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs
index 3b4ea5234f4..1a7a642f82a 100644
--- a/src/librustc/middle/check_rvalues.rs
+++ b/src/librustc/middle/check_rvalues.rs
@@ -60,7 +60,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
                cmt: mc::cmt<'tcx>,
                _: euv::ConsumeMode) {
         debug!("consume; cmt: {}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
-        if !ty::type_is_sized(self.tcx, cmt.ty, self.param_env) {
+        if !ty::type_is_sized(self.param_env, span, cmt.ty) {
             span_err!(self.tcx.sess, span, E0161,
                 "cannot move a value of type {0}: the size of {0} cannot be statically determined",
                 ty_to_string(self.tcx, cmt.ty));
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 7dbf797e739..b2d866cf586 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -367,10 +367,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         consume_id: ast::NodeId,
                         consume_span: Span,
                         cmt: mc::cmt<'tcx>) {
-        let mode = copy_or_move(self.tcx(),
-                                cmt.ty,
-                                self.param_env,
-                                DirectRefMove);
+        let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
         self.delegate.consume(consume_id, consume_span, cmt, mode);
     }
 
@@ -1020,10 +1017,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     ast::PatIdent(ast::BindByRef(_), _, _) =>
                         mode.lub(BorrowingMatch),
                     ast::PatIdent(ast::BindByValue(_), _, _) => {
-                        match copy_or_move(tcx,
-                                           cmt_pat.ty,
-                                           self.param_env,
-                                           PatBindingMove) {
+                        match copy_or_move(self.typer, &cmt_pat, PatBindingMove) {
                             Copy => mode.lub(CopyingMatch),
                             Move(_) => mode.lub(MovingMatch),
                         }
@@ -1085,10 +1079,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                                              r, bk, RefBinding);
                     }
                     ast::PatIdent(ast::BindByValue(_), _, _) => {
-                        let mode = copy_or_move(typer.tcx(),
-                                                cmt_pat.ty,
-                                                param_env,
-                                                PatBindingMove);
+                        let mode = copy_or_move(typer, &cmt_pat, PatBindingMove);
                         debug!("walk_pat binding consuming pat");
                         delegate.consume_pat(pat, cmt_pat, mode);
                     }
@@ -1303,12 +1294,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     }
 }
 
-fn copy_or_move<'tcx>(tcx: &ty::ctxt<'tcx>,
-                      ty: Ty<'tcx>,
-                      param_env: &ParameterEnvironment<'tcx>,
+fn copy_or_move<'tcx>(typer: &mc::Typer<'tcx>,
+                      cmt: &mc::cmt<'tcx>,
                       move_reason: MoveReason)
-                      -> ConsumeMode {
-    if ty::type_moves_by_default(tcx, ty, param_env) {
+                      -> ConsumeMode
+{
+    if typer.type_moves_by_default(cmt.span, cmt.ty) {
         Move(move_reason)
     } else {
         Copy
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index df06b3b7789..89ffcbf37a9 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -170,6 +170,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
 
         let mut substs = param_env.free_substs.clone();
         self.with_each_combination(
+            span,
             param_env,
             param_env.free_substs.types.iter_enumerated(),
             &mut substs,
@@ -187,7 +188,8 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
     }
 
     fn with_each_combination(&self,
-                             param_env: &ty::ParameterEnvironment<'tcx>,
+                             span: Span,
+                             param_env: &ty::ParameterEnvironment<'a,'tcx>,
                              mut types_in_scope: EnumeratedItems<Ty<'tcx>>,
                              substs: &mut Substs<'tcx>,
                              callback: &mut FnMut(&Substs<'tcx>))
@@ -210,15 +212,17 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
                 debug!("with_each_combination: space={}, index={}, param_ty={}",
                        space, index, param_ty.repr(self.tcx));
 
-                if !ty::type_is_sized(self.tcx, param_ty, param_env) {
+                if !ty::type_is_sized(param_env, span, param_ty) {
                     debug!("with_each_combination: param_ty is not known to be sized");
 
                     substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
-                    self.with_each_combination(param_env, types_in_scope.clone(), substs, callback);
+                    self.with_each_combination(span, param_env, types_in_scope.clone(),
+                                               substs, callback);
                 }
 
                 substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
-                self.with_each_combination(param_env, types_in_scope, substs, callback);
+                self.with_each_combination(span, param_env, types_in_scope,
+                                           substs, callback);
             }
         }
     }
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index a0413701abc..05ea2f9a7d2 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -77,7 +77,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                     "overflow evaluating the requirement `{}`",
                     predicate.user_string(infcx.tcx)).as_slice());
 
-            suggest_new_overflow_limit(infcx, obligation.cause.span);
+            suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
 
             note_obligation_cause(infcx, obligation);
         }
@@ -332,10 +332,10 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     }
 }
 
-pub fn suggest_new_overflow_limit(infcx: &InferCtxt, span: Span) {
-    let current_limit = infcx.tcx.sess.recursion_limit.get();
+pub fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) {
+    let current_limit = tcx.sess.recursion_limit.get();
     let suggested_limit = current_limit * 2;
-    infcx.tcx.sess.span_note(
+    tcx.sess.span_note(
         span,
         format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index c83898bcd8a..1a1d52a047c 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*;
 pub use self::Vtable::*;
 pub use self::ObligationCauseCode::*;
 
+use middle::mem_categorization::Typer;
 use middle::subst;
 use middle::ty::{mod, Ty};
 use middle::infer::InferCtxt;
@@ -22,9 +23,10 @@ use std::slice::Iter;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
 
 pub use self::error_reporting::report_fulfillment_errors;
+pub use self::error_reporting::suggest_new_overflow_limit;
 pub use self::coherence::orphan_check;
 pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, RegionObligation};
@@ -288,11 +290,12 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
 /// `bound` or is not known to meet bound (note that this is
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
-pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                                 param_env: &ty::ParameterEnvironment<'tcx>,
-                                                 ty: Ty<'tcx>,
-                                                 bound: ty::BuiltinBound)
-                                                 -> bool
+pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+                                       typer: &ty::UnboxedClosureTyper<'tcx>,
+                                       ty: Ty<'tcx>,
+                                       bound: ty::BuiltinBound,
+                                       span: Span)
+                                       -> SelectionResult<'tcx, ()>
 {
     debug!("type_known_to_meet_builtin_bound(ty={}, bound={})",
            ty.repr(infcx.tcx),
@@ -300,17 +303,49 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
 
     let mut fulfill_cx = FulfillmentContext::new();
 
-    // We can use dummy values here because we won't report any errors
-    // that result nor will we pay any mind to region obligations that arise
-    // (there shouldn't really be any anyhow).
-    let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
+    // We can use a dummy node-id here because we won't pay any mind
+    // to region obligations that arise (there shouldn't really be any
+    // anyhow).
+    let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
 
     fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
 
     // Note: we only assume something is `Copy` if we can
     // *definitively* show that it implements `Copy`. Otherwise,
     // assume it is move; linear is always ok.
-    let result = fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx).is_ok();
+    let result = match fulfill_cx.select_all_or_error(infcx, typer) {
+        Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
+        Err(errors) => {
+            // Check if overflow occurred anywhere and propagate that.
+            if errors.iter().any(
+                |err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
+            {
+                return Err(Overflow);
+            }
+
+            // Otherwise, if there were any hard errors, propagate an
+            // arbitrary one of those. If no hard errors at all,
+            // report ambiguity.
+            let sel_error =
+                errors.iter()
+                      .filter_map(|err| {
+                          match err.code {
+                              CodeAmbiguity => None,
+                              CodeSelectionError(ref e) => Some(e.clone()),
+                              CodeProjectionError(_) => {
+                                  infcx.tcx.sess.span_bug(
+                                      span,
+                                      "projection error while selecting?")
+                              }
+                          }
+                      })
+                      .next();
+            match sel_error {
+                None => { Ok(None) }
+                Some(e) => { Err(e) }
+            }
+        }
+    };
 
     debug!("type_known_to_meet_builtin_bound: ty={} bound={} result={}",
            ty.repr(infcx.tcx),
@@ -320,6 +355,40 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     result
 }
 
+pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+                                                 typer: &ty::UnboxedClosureTyper<'tcx>,
+                                                 ty: Ty<'tcx>,
+                                                 bound: ty::BuiltinBound,
+                                                 span: Span)
+                                                 -> bool
+{
+    match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
+        Ok(Some(())) => {
+            // definitely impl'd
+            true
+        }
+        Ok(None) => {
+            // ambiguous: if coherence check was successful, shouldn't
+            // happen, but we might have reported an error and been
+            // soldering on, so just treat this like not implemented
+            false
+        }
+        Err(Overflow) => {
+            infcx.tcx.sess.span_err(
+                span,
+                format!("overflow evaluating whether `{}` is `{}`",
+                        ty.user_string(infcx.tcx),
+                        bound.user_string(infcx.tcx))[]);
+            suggest_new_overflow_limit(infcx.tcx, span);
+            false
+        }
+        Err(_) => {
+            // other errors: not implemented.
+            false
+        }
+    }
+}
+
 impl<'tcx,O> Obligation<'tcx,O> {
     pub fn new(cause: ObligationCause<'tcx>,
                trait_ref: O)
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 079972eff67..fd32e798689 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3548,11 +3548,12 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
         }
     }
 
-    let infcx = infer::new_infer_ctxt(cx);
-    let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound);
+    let infcx = infer::new_infer_ctxt(param_env.tcx);
+
+    let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
 
     debug!("type_impls_bound({}, {}) = {}",
-           ty_to_string(cx, ty),
+           ty.repr(param_env.tcx),
            bound,
            is_impld);
 
@@ -3564,20 +3565,22 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
     is_impld
 }
 
-pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
-                                   ty: Ty<'tcx>,
-                                   param_env: &ParameterEnvironment<'tcx>)
-                                   -> bool
+pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
+                                      span: Span,
+                                      ty: Ty<'tcx>)
+                                      -> bool
 {
-    !type_impls_bound(cx, &cx.type_impls_copy_cache, param_env, ty, ty::BoundCopy)
+    let tcx = param_env.tcx;
+    !type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
 }
 
-pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>,
-                           ty: Ty<'tcx>,
-                           param_env: &ParameterEnvironment<'tcx>)
-                           -> bool
+pub fn type_is_sized<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
+                              span: Span,
+                              ty: Ty<'tcx>)
+                              -> bool
 {
-    type_impls_bound(cx, &cx.type_impls_sized_cache, param_env, ty, ty::BoundSized)
+    let tcx = param_env.tcx;
+    type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
 }
 
 pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -6562,6 +6565,10 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> {
                     -> ast::CaptureClause {
         self.capture_modes.borrow()[closure_expr_id].clone()
     }
+
+    fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
+        type_moves_by_default(self, span, ty)
+    }
 }
 
 impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
@@ -6944,15 +6951,18 @@ pub enum CopyImplementationError {
     TypeIsStructural,
 }
 
-pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>,
-                                     self_type: Ty<'tcx>,
-                                     param_env: &ParameterEnvironment<'tcx>)
-                                     -> Result<(),CopyImplementationError> {
+pub fn can_type_implement_copy<'a,'tcx>(param_env: &ParameterEnvironment<'a, 'tcx>,
+                                        span: Span,
+                                        self_type: Ty<'tcx>)
+                                        -> Result<(),CopyImplementationError>
+{
+    let tcx = param_env.tcx;
+
     match self_type.sty {
         ty::ty_struct(struct_did, substs) => {
             let fields = ty::struct_fields(tcx, struct_did, substs);
             for field in fields.iter() {
-                if type_moves_by_default(tcx, field.mt.ty, param_env) {
+                if type_moves_by_default(param_env, span, field.mt.ty) {
                     return Err(FieldDoesNotImplementCopy(field.name))
                 }
             }
@@ -6963,9 +6973,7 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>,
                 for variant_arg_type in variant.args.iter() {
                     let substd_arg_type =
                         variant_arg_type.subst(tcx, substs);
-                    if type_moves_by_default(tcx,
-                                             substd_arg_type,
-                                             param_env) {
+                    if type_moves_by_default(param_env, span, substd_arg_type) {
                         return Err(VariantDoesNotImplementCopy(variant.name))
                     }
                 }
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index fc68d1d3258..0b1dfcb378b 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -1327,9 +1327,8 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat,
         let trmode;
         match bm {
             ast::BindByValue(_)
-                if !ty::type_moves_by_default(tcx,
-                                              variable_ty,
-                                              &param_env) || reassigned => {
+                if !ty::type_moves_by_default(&param_env, span, variable_ty) || reassigned =>
+            {
                 llmatch = alloca_no_lifetime(bcx,
                                  llvariable_ty.ptr_to(),
                                  "__llmatch");
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index aa882240880..660b7aeeb00 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -625,6 +625,10 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
                     -> ast::CaptureClause {
         self.tcx().capture_modes.borrow()[closure_expr_id].clone()
     }
+
+    fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
+        self.param_env().type_moves_by_default(span, ty)
+    }
 }
 
 impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> {
diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs
index 83bf06383a8..0afe3a8ef8d 100644
--- a/src/librustc_trans/trans/datum.rs
+++ b/src/librustc_trans/trans/datum.rs
@@ -543,8 +543,9 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
          * affine values (since they must never be duplicated).
          */
 
-        let param_env = ty::empty_parameter_environment();
-        assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty, &param_env));
+        assert!(!ty::type_moves_by_default(&ty::empty_parameter_environment(bcx.tcx()),
+                                           DUMMY_SP,
+                                           self.ty));
         self.shallow_copy_raw(bcx, dst)
     }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 189798a1390..37ec24ae23b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1462,7 +1462,7 @@ fn check_cast(fcx: &FnCtxt,
         return
     }
 
-    if !fcx.type_is_known_to_be_sized(t_1) {
+    if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
         let tstr = fcx.infcx().ty_to_string(t_1);
         fcx.type_error_message(span, |actual| {
             format!("cast to unsized type: `{}` as `{}`", actual, tstr)
@@ -1981,13 +1981,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn type_is_known_to_be_sized(&self,
-                                     ty: Ty<'tcx>)
+                                     ty: Ty<'tcx>,
+                                     span: Span)
                                      -> bool
     {
         traits::type_known_to_meet_builtin_bound(self.infcx(),
                                                  self.param_env(),
                                                  ty,
-                                                 ty::BoundSized)
+                                                 ty::BoundSized,
+                                                 span)
     }
 
     pub fn register_builtin_bound(&self,
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 79e1efa618f..bb308198330 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -482,7 +482,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("check_implementations_of_copy: self_type={} (free)",
                    self_type.repr(tcx));
 
-            match ty::can_type_implement_copy(tcx, self_type, &param_env) {
+            match ty::can_type_implement_copy(&param_env, span, self_type) {
                 Ok(()) => {}
                 Err(ty::FieldDoesNotImplementCopy(name)) => {
                     tcx.sess