Skip to content

Commit a637365

Browse files
committed
Auto merge of #21606 - arielb1:clean-cast, r=huonw
This also makes the cast error messages somewhat more uniform.
2 parents 8ec3a83 + e724525 commit a637365

File tree

7 files changed

+119
-91
lines changed

7 files changed

+119
-91
lines changed

src/librustc/middle/ty.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3126,7 +3126,6 @@ pub fn type_is_scalar(ty: Ty) -> bool {
31263126
ty_bool | ty_char | ty_int(_) | ty_float(_) | ty_uint(_) |
31273127
ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) |
31283128
ty_bare_fn(..) | ty_ptr(_) => true,
3129-
ty_tup(ref tys) if tys.is_empty() => true,
31303129
_ => false
31313130
}
31323131
}

src/librustc_typeck/check/mod.rs

Lines changed: 100 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -990,86 +990,65 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
990990
}
991991
}
992992

993-
fn check_cast(fcx: &FnCtxt,
994-
cast_expr: &ast::Expr,
995-
e: &ast::Expr,
996-
t: &ast::Ty) {
997-
let id = cast_expr.id;
998-
let span = cast_expr.span;
999-
1000-
// Find the type of `e`. Supply hints based on the type we are casting to,
1001-
// if appropriate.
1002-
let t_1 = fcx.to_ty(t);
1003-
let t_1 = structurally_resolved_type(fcx, span, t_1);
1004-
1005-
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
1006-
1007-
let t_e = fcx.expr_ty(e);
1008-
1009-
debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
1010-
debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
1011-
1012-
if ty::type_is_error(t_e) {
1013-
fcx.write_error(id);
1014-
return
1015-
}
1016-
1017-
if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
1018-
let tstr = fcx.infcx().ty_to_string(t_1);
1019-
fcx.type_error_message(span, |actual| {
1020-
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
1021-
}, t_e, None);
1022-
match t_e.sty {
1023-
ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
1024-
let mtstr = match mt {
1025-
ast::MutMutable => "mut ",
1026-
ast::MutImmutable => ""
1027-
};
1028-
if ty::type_is_trait(t_1) {
1029-
span_help!(fcx.tcx().sess, t.span, "did you mean `&{}{}`?", mtstr, tstr);
1030-
} else {
1031-
span_help!(fcx.tcx().sess, span,
1032-
"consider using an implicit coercion to `&{}{}` instead",
1033-
mtstr, tstr);
1034-
}
1035-
}
1036-
ty::ty_uniq(..) => {
1037-
span_help!(fcx.tcx().sess, t.span, "did you mean `Box<{}>`?", tstr);
1038-
}
1039-
_ => {
1040-
span_help!(fcx.tcx().sess, e.span,
1041-
"consider using a box or reference as appropriate");
993+
fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
994+
span: Span,
995+
t_span: Span,
996+
e_span: Span,
997+
t_1: Ty<'tcx>,
998+
t_e: Ty<'tcx>,
999+
id: ast::NodeId) {
1000+
let tstr = fcx.infcx().ty_to_string(t_1);
1001+
fcx.type_error_message(span, |actual| {
1002+
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
1003+
}, t_e, None);
1004+
match t_e.sty {
1005+
ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
1006+
let mtstr = match mt {
1007+
ast::MutMutable => "mut ",
1008+
ast::MutImmutable => ""
1009+
};
1010+
if ty::type_is_trait(t_1) {
1011+
span_help!(fcx.tcx().sess, t_span, "did you mean `&{}{}`?", mtstr, tstr);
1012+
} else {
1013+
span_help!(fcx.tcx().sess, span,
1014+
"consider using an implicit coercion to `&{}{}` instead",
1015+
mtstr, tstr);
10421016
}
10431017
}
1044-
fcx.write_error(id);
1045-
return
1046-
}
1047-
1048-
if ty::type_is_trait(t_1) {
1049-
// This will be looked up later on.
1050-
vtable::check_object_cast(fcx, cast_expr, e, t_1);
1051-
fcx.write_ty(id, t_1);
1052-
return
1018+
ty::ty_uniq(..) => {
1019+
span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr);
1020+
}
1021+
_ => {
1022+
span_help!(fcx.tcx().sess, e_span,
1023+
"consider using a box or reference as appropriate");
1024+
}
10531025
}
1026+
fcx.write_error(id);
1027+
}
10541028

1055-
let t_1 = structurally_resolved_type(fcx, span, t_1);
1056-
let t_e = structurally_resolved_type(fcx, span, t_e);
10571029

1058-
if ty::type_is_nil(t_e) {
1059-
fcx.type_error_message(span, |actual| {
1060-
format!("cast from nil: `{}` as `{}`",
1061-
actual,
1062-
fcx.infcx().ty_to_string(t_1))
1063-
}, t_e, None);
1064-
} else if ty::type_is_nil(t_1) {
1030+
fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
1031+
span: Span,
1032+
t_1: Ty<'tcx>,
1033+
t_e: Ty<'tcx>,
1034+
e: &ast::Expr) {
1035+
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
1036+
span: Span,
1037+
t_1: Ty<'tcx>,
1038+
t_e: Ty<'tcx>) {
10651039
fcx.type_error_message(span, |actual| {
1066-
format!("cast to nil: `{}` as `{}`",
1040+
format!("illegal cast; cast through an \
1041+
integer first: `{}` as `{}`",
10671042
actual,
10681043
fcx.infcx().ty_to_string(t_1))
10691044
}, t_e, None);
10701045
}
10711046

10721047
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
1048+
let t_e_is_scalar = ty::type_is_scalar(t_e);
1049+
let t_e_is_integral = ty::type_is_integral(t_e);
1050+
let t_e_is_float = ty::type_is_floating_point(t_e);
1051+
let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
10731052

10741053
let t_1_is_scalar = ty::type_is_scalar(t_1);
10751054
let t_1_is_char = ty::type_is_char(t_1);
@@ -1078,18 +1057,9 @@ fn check_cast(fcx: &FnCtxt,
10781057

10791058
// casts to scalars other than `char` and `bare fn` are trivial
10801059
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1060+
10811061
if t_e_is_bare_fn_item && t_1_is_bare_fn {
10821062
demand::coerce(fcx, e.span, t_1, &*e);
1083-
} else if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial {
1084-
if t_1_is_float || ty::type_is_unsafe_ptr(t_1) {
1085-
fcx.type_error_message(span, |actual| {
1086-
format!("illegal cast; cast through an \
1087-
integer first: `{}` as `{}`",
1088-
actual,
1089-
fcx.infcx().ty_to_string(t_1))
1090-
}, t_e, None);
1091-
}
1092-
// casts from C-like enums are allowed
10931063
} else if t_1_is_char {
10941064
let t_e = fcx.infcx().shallow_resolve(t_e);
10951065
if t_e.sty != ty::ty_uint(ast::TyU8) {
@@ -1101,6 +1071,16 @@ fn check_cast(fcx: &FnCtxt,
11011071
} else if t_1.sty == ty::ty_bool {
11021072
span_err!(fcx.tcx().sess, span, E0054,
11031073
"cannot cast as `bool`, compare with zero instead");
1074+
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
1075+
t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
1076+
// Casts to float must go through an integer or boolean
1077+
cast_through_integer_err(fcx, span, t_1, t_e)
1078+
} else if t_e_is_c_enum && t_1_is_trivial {
1079+
if ty::type_is_unsafe_ptr(t_1) {
1080+
// ... and likewise with C enum -> *T
1081+
cast_through_integer_err(fcx, span, t_1, t_e)
1082+
}
1083+
// casts from C-like enums are allowed
11041084
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
11051085
fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
11061086
t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
@@ -1142,7 +1122,7 @@ fn check_cast(fcx: &FnCtxt,
11421122
demand::coerce(fcx, e.span, t_1, &*e);
11431123
}
11441124
}
1145-
} else if !(ty::type_is_scalar(t_e) && t_1_is_trivial) {
1125+
} else if !(t_e_is_scalar && t_1_is_trivial) {
11461126
/*
11471127
If more type combinations should be supported than are
11481128
supported here, then file an enhancement issue and
@@ -1153,15 +1133,49 @@ fn check_cast(fcx: &FnCtxt,
11531133
actual,
11541134
fcx.infcx().ty_to_string(t_1))
11551135
}, t_e, None);
1156-
} else if ty::type_is_unsafe_ptr(t_e) && t_1_is_float {
1157-
fcx.type_error_message(span, |actual| {
1158-
format!("cannot cast from pointer to float directly: `{}` as `{}`; cast through an \
1159-
integer first",
1160-
actual,
1161-
fcx.infcx().ty_to_string(t_1))
1162-
}, t_e, None);
11631136
}
1137+
}
1138+
1139+
fn check_cast(fcx: &FnCtxt,
1140+
cast_expr: &ast::Expr,
1141+
e: &ast::Expr,
1142+
t: &ast::Ty) {
1143+
let id = cast_expr.id;
1144+
let span = cast_expr.span;
1145+
1146+
// Find the type of `e`. Supply hints based on the type we are casting to,
1147+
// if appropriate.
1148+
let t_1 = fcx.to_ty(t);
1149+
let t_1 = structurally_resolved_type(fcx, span, t_1);
1150+
1151+
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
1152+
1153+
let t_e = fcx.expr_ty(e);
1154+
1155+
debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
1156+
debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
1157+
1158+
if ty::type_is_error(t_e) {
1159+
fcx.write_error(id);
1160+
return
1161+
}
1162+
1163+
if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
1164+
report_cast_to_unsized_type(fcx, span, t.span, e.span, t_1, t_e, id);
1165+
return
1166+
}
1167+
1168+
if ty::type_is_trait(t_1) {
1169+
// This will be looked up later on.
1170+
vtable::check_object_cast(fcx, cast_expr, e, t_1);
1171+
fcx.write_ty(id, t_1);
1172+
return
1173+
}
1174+
1175+
let t_1 = structurally_resolved_type(fcx, span, t_1);
1176+
let t_e = structurally_resolved_type(fcx, span, t_e);
11641177

1178+
check_cast_inner(fcx, span, t_1, t_e, e);
11651179
fcx.write_ty(id, t_1);
11661180
}
11671181

src/test/compile-fail/cast-from-nil.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern: cast from nil: `()` as `u32`
11+
// error-pattern: non-scalar cast: `()` as `u32`
1212
fn main() { let u = (assert!(true) as u32); }

src/test/compile-fail/cast-to-nil.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern: cast to nil: `u32` as `()`
11+
// error-pattern: non-scalar cast: `u32` as `()`
1212
fn main() { let u = 0u32 as (); }

src/test/compile-fail/issue-10991.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010

1111
fn main() {
1212
let nil = ();
13-
let _t = nil as usize; //~ ERROR: cast from nil: `()` as `usize`
13+
let _t = nil as usize; //~ ERROR: non-scalar cast: `()` as `usize`
1414
}

src/test/compile-fail/issue-21554.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Inches(i32);
12+
13+
fn main() {
14+
Inches as f32; //~ ERROR illegal cast; cast through an integer first
15+
}

src/test/compile-fail/typeck-cast-pointer-to-float.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
fn main() {
1212
let x : i16 = 22;
1313
((&x) as *const i16) as f32;
14-
//~^ ERROR: cannot cast from pointer to float directly: `*const i16` as `f32`
14+
//~^ ERROR illegal cast; cast through an integer first: `*const i16` as `f32`
1515
}

0 commit comments

Comments
 (0)