about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/ty.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs186
-rw-r--r--src/test/compile-fail/cast-from-nil.rs2
-rw-r--r--src/test/compile-fail/cast-to-nil.rs2
-rw-r--r--src/test/compile-fail/issue-10991.rs2
-rw-r--r--src/test/compile-fail/issue-21554.rs15
-rw-r--r--src/test/compile-fail/typeck-cast-pointer-to-float.rs2
7 files changed, 119 insertions, 91 deletions
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 0ee26ce1cd3..86cf030c828 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3126,7 +3126,6 @@ pub fn type_is_scalar(ty: Ty) -> bool {
       ty_bool | ty_char | ty_int(_) | ty_float(_) | ty_uint(_) |
       ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) |
       ty_bare_fn(..) | ty_ptr(_) => true,
-      ty_tup(ref tys) if tys.is_empty() => true,
       _ => false
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5b172598ebb..8de1ffd37e0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -990,86 +990,65 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn check_cast(fcx: &FnCtxt,
-              cast_expr: &ast::Expr,
-              e: &ast::Expr,
-              t: &ast::Ty) {
-    let id = cast_expr.id;
-    let span = cast_expr.span;
-
-    // Find the type of `e`. Supply hints based on the type we are casting to,
-    // if appropriate.
-    let t_1 = fcx.to_ty(t);
-    let t_1 = structurally_resolved_type(fcx, span, t_1);
-
-    check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
-
-    let t_e = fcx.expr_ty(e);
-
-    debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
-    debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
-
-    if ty::type_is_error(t_e) {
-        fcx.write_error(id);
-        return
-    }
-
-    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)
-        }, t_e, None);
-        match t_e.sty {
-            ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
-                let mtstr = match mt {
-                    ast::MutMutable => "mut ",
-                    ast::MutImmutable => ""
-                };
-                if ty::type_is_trait(t_1) {
-                    span_help!(fcx.tcx().sess, t.span, "did you mean `&{}{}`?", mtstr, tstr);
-                } else {
-                    span_help!(fcx.tcx().sess, span,
-                               "consider using an implicit coercion to `&{}{}` instead",
-                               mtstr, tstr);
-                }
-            }
-            ty::ty_uniq(..) => {
-                span_help!(fcx.tcx().sess, t.span, "did you mean `Box<{}>`?", tstr);
-            }
-            _ => {
-                span_help!(fcx.tcx().sess, e.span,
-                           "consider using a box or reference as appropriate");
+fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                         span: Span,
+                                         t_span: Span,
+                                         e_span: Span,
+                                         t_1: Ty<'tcx>,
+                                         t_e: Ty<'tcx>,
+                                         id: ast::NodeId) {
+    let tstr = fcx.infcx().ty_to_string(t_1);
+    fcx.type_error_message(span, |actual| {
+        format!("cast to unsized type: `{}` as `{}`", actual, tstr)
+    }, t_e, None);
+    match t_e.sty {
+        ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
+            let mtstr = match mt {
+                ast::MutMutable => "mut ",
+                ast::MutImmutable => ""
+            };
+            if ty::type_is_trait(t_1) {
+                span_help!(fcx.tcx().sess, t_span, "did you mean `&{}{}`?", mtstr, tstr);
+            } else {
+                span_help!(fcx.tcx().sess, span,
+                           "consider using an implicit coercion to `&{}{}` instead",
+                           mtstr, tstr);
             }
         }
-        fcx.write_error(id);
-        return
-    }
-
-    if ty::type_is_trait(t_1) {
-        // This will be looked up later on.
-        vtable::check_object_cast(fcx, cast_expr, e, t_1);
-        fcx.write_ty(id, t_1);
-        return
+        ty::ty_uniq(..) => {
+            span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr);
+        }
+        _ => {
+            span_help!(fcx.tcx().sess, e_span,
+                       "consider using a box or reference as appropriate");
+        }
     }
+    fcx.write_error(id);
+}
 
-    let t_1 = structurally_resolved_type(fcx, span, t_1);
-    let t_e = structurally_resolved_type(fcx, span, t_e);
 
-    if ty::type_is_nil(t_e) {
-        fcx.type_error_message(span, |actual| {
-            format!("cast from nil: `{}` as `{}`",
-                    actual,
-                    fcx.infcx().ty_to_string(t_1))
-        }, t_e, None);
-    } else if ty::type_is_nil(t_1) {
+fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                              span: Span,
+                              t_1: Ty<'tcx>,
+                              t_e: Ty<'tcx>,
+                              e: &ast::Expr) {
+    fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                          span: Span,
+                                          t_1: Ty<'tcx>,
+                                          t_e: Ty<'tcx>) {
         fcx.type_error_message(span, |actual| {
-            format!("cast to nil: `{}` as `{}`",
+            format!("illegal cast; cast through an \
+                    integer first: `{}` as `{}`",
                     actual,
                     fcx.infcx().ty_to_string(t_1))
         }, t_e, None);
     }
 
     let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
+    let t_e_is_scalar = ty::type_is_scalar(t_e);
+    let t_e_is_integral = ty::type_is_integral(t_e);
+    let t_e_is_float = ty::type_is_floating_point(t_e);
+    let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
 
     let t_1_is_scalar = ty::type_is_scalar(t_1);
     let t_1_is_char = ty::type_is_char(t_1);
@@ -1078,18 +1057,9 @@ fn check_cast(fcx: &FnCtxt,
 
     // casts to scalars other than `char` and `bare fn` are trivial
     let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
+
     if t_e_is_bare_fn_item && t_1_is_bare_fn {
         demand::coerce(fcx, e.span, t_1, &*e);
-    } else if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial {
-        if t_1_is_float || ty::type_is_unsafe_ptr(t_1) {
-            fcx.type_error_message(span, |actual| {
-                format!("illegal cast; cast through an \
-                         integer first: `{}` as `{}`",
-                        actual,
-                        fcx.infcx().ty_to_string(t_1))
-            }, t_e, None);
-        }
-        // casts from C-like enums are allowed
     } else if t_1_is_char {
         let t_e = fcx.infcx().shallow_resolve(t_e);
         if t_e.sty != ty::ty_uint(ast::TyU8) {
@@ -1101,6 +1071,16 @@ fn check_cast(fcx: &FnCtxt,
     } else if t_1.sty == ty::ty_bool {
         span_err!(fcx.tcx().sess, span, E0054,
             "cannot cast as `bool`, compare with zero instead");
+    } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
+        t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
+        // Casts to float must go through an integer or boolean
+        cast_through_integer_err(fcx, span, t_1, t_e)
+    } else if t_e_is_c_enum && t_1_is_trivial {
+        if ty::type_is_unsafe_ptr(t_1) {
+            // ... and likewise with C enum -> *T
+            cast_through_integer_err(fcx, span, t_1, t_e)
+        }
+        // casts from C-like enums are allowed
     } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
         fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
                                       t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
@@ -1142,7 +1122,7 @@ fn check_cast(fcx: &FnCtxt,
                 demand::coerce(fcx, e.span, t_1, &*e);
             }
         }
-    } else if !(ty::type_is_scalar(t_e) && t_1_is_trivial) {
+    } else if !(t_e_is_scalar && t_1_is_trivial) {
         /*
         If more type combinations should be supported than are
         supported here, then file an enhancement issue and
@@ -1153,15 +1133,49 @@ fn check_cast(fcx: &FnCtxt,
                     actual,
                     fcx.infcx().ty_to_string(t_1))
         }, t_e, None);
-    } else if ty::type_is_unsafe_ptr(t_e) && t_1_is_float {
-        fcx.type_error_message(span, |actual| {
-            format!("cannot cast from pointer to float directly: `{}` as `{}`; cast through an \
-                     integer first",
-                    actual,
-                    fcx.infcx().ty_to_string(t_1))
-        }, t_e, None);
     }
+}
+
+fn check_cast(fcx: &FnCtxt,
+              cast_expr: &ast::Expr,
+              e: &ast::Expr,
+              t: &ast::Ty) {
+    let id = cast_expr.id;
+    let span = cast_expr.span;
+
+    // Find the type of `e`. Supply hints based on the type we are casting to,
+    // if appropriate.
+    let t_1 = fcx.to_ty(t);
+    let t_1 = structurally_resolved_type(fcx, span, t_1);
+
+    check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
+
+    let t_e = fcx.expr_ty(e);
+
+    debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
+    debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
+
+    if ty::type_is_error(t_e) {
+        fcx.write_error(id);
+        return
+    }
+
+    if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
+        report_cast_to_unsized_type(fcx, span, t.span, e.span, t_1, t_e, id);
+        return
+    }
+
+    if ty::type_is_trait(t_1) {
+        // This will be looked up later on.
+        vtable::check_object_cast(fcx, cast_expr, e, t_1);
+        fcx.write_ty(id, t_1);
+        return
+    }
+
+    let t_1 = structurally_resolved_type(fcx, span, t_1);
+    let t_e = structurally_resolved_type(fcx, span, t_e);
 
+    check_cast_inner(fcx, span, t_1, t_e, e);
     fcx.write_ty(id, t_1);
 }
 
diff --git a/src/test/compile-fail/cast-from-nil.rs b/src/test/compile-fail/cast-from-nil.rs
index 558a5478718..4c6dcaccc9a 100644
--- a/src/test/compile-fail/cast-from-nil.rs
+++ b/src/test/compile-fail/cast-from-nil.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: cast from nil: `()` as `u32`
+// error-pattern: non-scalar cast: `()` as `u32`
 fn main() { let u = (assert!(true) as u32); }
diff --git a/src/test/compile-fail/cast-to-nil.rs b/src/test/compile-fail/cast-to-nil.rs
index 1a5c0744f70..e5fd5bb33eb 100644
--- a/src/test/compile-fail/cast-to-nil.rs
+++ b/src/test/compile-fail/cast-to-nil.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: cast to nil: `u32` as `()`
+// error-pattern: non-scalar cast: `u32` as `()`
 fn main() { let u = 0u32 as (); }
diff --git a/src/test/compile-fail/issue-10991.rs b/src/test/compile-fail/issue-10991.rs
index 2913ddf395f..25060b94dcf 100644
--- a/src/test/compile-fail/issue-10991.rs
+++ b/src/test/compile-fail/issue-10991.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     let nil = ();
-    let _t = nil as usize; //~ ERROR: cast from nil: `()` as `usize`
+    let _t = nil as usize; //~ ERROR: non-scalar cast: `()` as `usize`
 }
diff --git a/src/test/compile-fail/issue-21554.rs b/src/test/compile-fail/issue-21554.rs
new file mode 100644
index 00000000000..a2cac55033c
--- /dev/null
+++ b/src/test/compile-fail/issue-21554.rs
@@ -0,0 +1,15 @@
+// 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.
+
+struct Inches(i32);
+
+fn main() {
+    Inches as f32; //~ ERROR illegal cast; cast through an integer first
+}
diff --git a/src/test/compile-fail/typeck-cast-pointer-to-float.rs b/src/test/compile-fail/typeck-cast-pointer-to-float.rs
index 22a0978ef7c..285a5dbee05 100644
--- a/src/test/compile-fail/typeck-cast-pointer-to-float.rs
+++ b/src/test/compile-fail/typeck-cast-pointer-to-float.rs
@@ -11,5 +11,5 @@
 fn main() {
     let x : i16 = 22;
     ((&x) as *const i16) as f32;
-    //~^ ERROR: cannot cast from pointer to float directly: `*const i16` as `f32`
+    //~^ ERROR illegal cast; cast through an integer first: `*const i16` as `f32`
 }