mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 14:31:55 +00:00
Cleanup check_cast. Fixes #21554
This also makes the cast error messages somewhat more uniform.
This commit is contained in:
parent
76fbb35831
commit
e7245252cc
@ -3128,7 +3128,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
|
||||
}
|
||||
}
|
||||
|
@ -993,86 +993,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
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ty::type_is_nil(t_e) {
|
||||
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 from nil: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
} else if ty::type_is_nil(t_1) {
|
||||
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);
|
||||
@ -1081,18 +1060,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) {
|
||||
@ -1104,6 +1074,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 {
|
||||
@ -1145,7 +1125,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
|
||||
@ -1156,15 +1136,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);
|
||||
}
|
||||
|
||||
|
@ -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); }
|
||||
|
@ -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 (); }
|
||||
|
@ -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`
|
||||
}
|
||||
|
15
src/test/compile-fail/issue-21554.rs
Normal file
15
src/test/compile-fail/issue-21554.rs
Normal file
@ -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
|
||||
}
|
@ -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`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user