@@ -993,86 +993,65 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
993993 }
994994}
995995
996- fn check_cast ( fcx : & FnCtxt ,
997- cast_expr : & ast:: Expr ,
998- e : & ast:: Expr ,
999- t : & ast:: Ty ) {
1000- let id = cast_expr. id ;
1001- let span = cast_expr. span ;
1002-
1003- // Find the type of `e`. Supply hints based on the type we are casting to,
1004- // if appropriate.
1005- let t_1 = fcx. to_ty ( t) ;
1006- let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1007-
1008- check_expr_with_expectation ( fcx, e, ExpectCastableToType ( t_1) ) ;
1009-
1010- let t_e = fcx. expr_ty ( e) ;
1011-
1012- debug ! ( "t_1={}" , fcx. infcx( ) . ty_to_string( t_1) ) ;
1013- debug ! ( "t_e={}" , fcx. infcx( ) . ty_to_string( t_e) ) ;
1014-
1015- if ty:: type_is_error ( t_e) {
1016- fcx. write_error ( id) ;
1017- return
1018- }
1019-
1020- if !fcx. type_is_known_to_be_sized ( t_1, cast_expr. span ) {
1021- let tstr = fcx. infcx ( ) . ty_to_string ( t_1) ;
1022- fcx. type_error_message ( span, |actual| {
1023- format ! ( "cast to unsized type: `{}` as `{}`" , actual, tstr)
1024- } , t_e, None ) ;
1025- match t_e. sty {
1026- ty:: ty_rptr( _, ty:: mt { mutbl : mt, .. } ) => {
1027- let mtstr = match mt {
1028- ast:: MutMutable => "mut " ,
1029- ast:: MutImmutable => ""
1030- } ;
1031- if ty:: type_is_trait ( t_1) {
1032- span_help ! ( fcx. tcx( ) . sess, t. span, "did you mean `&{}{}`?" , mtstr, tstr) ;
1033- } else {
1034- span_help ! ( fcx. tcx( ) . sess, span,
1035- "consider using an implicit coercion to `&{}{}` instead" ,
1036- mtstr, tstr) ;
1037- }
1038- }
1039- ty:: ty_uniq( ..) => {
1040- span_help ! ( fcx. tcx( ) . sess, t. span, "did you mean `Box<{}>`?" , tstr) ;
1041- }
1042- _ => {
1043- span_help ! ( fcx. tcx( ) . sess, e. span,
1044- "consider using a box or reference as appropriate" ) ;
996+ fn report_cast_to_unsized_type < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
997+ span : Span ,
998+ t_span : Span ,
999+ e_span : Span ,
1000+ t_1 : Ty < ' tcx > ,
1001+ t_e : Ty < ' tcx > ,
1002+ id : ast:: NodeId ) {
1003+ let tstr = fcx. infcx ( ) . ty_to_string ( t_1) ;
1004+ fcx. type_error_message ( span, |actual| {
1005+ format ! ( "cast to unsized type: `{}` as `{}`" , actual, tstr)
1006+ } , t_e, None ) ;
1007+ match t_e. sty {
1008+ ty:: ty_rptr( _, ty:: mt { mutbl : mt, .. } ) => {
1009+ let mtstr = match mt {
1010+ ast:: MutMutable => "mut " ,
1011+ ast:: MutImmutable => ""
1012+ } ;
1013+ if ty:: type_is_trait ( t_1) {
1014+ span_help ! ( fcx. tcx( ) . sess, t_span, "did you mean `&{}{}`?" , mtstr, tstr) ;
1015+ } else {
1016+ span_help ! ( fcx. tcx( ) . sess, span,
1017+ "consider using an implicit coercion to `&{}{}` instead" ,
1018+ mtstr, tstr) ;
10451019 }
10461020 }
1047- fcx. write_error ( id) ;
1048- return
1049- }
1050-
1051- if ty:: type_is_trait ( t_1) {
1052- // This will be looked up later on.
1053- vtable:: check_object_cast ( fcx, cast_expr, e, t_1) ;
1054- fcx. write_ty ( id, t_1) ;
1055- return
1021+ ty:: ty_uniq( ..) => {
1022+ span_help ! ( fcx. tcx( ) . sess, t_span, "did you mean `Box<{}>`?" , tstr) ;
1023+ }
1024+ _ => {
1025+ span_help ! ( fcx. tcx( ) . sess, e_span,
1026+ "consider using a box or reference as appropriate" ) ;
1027+ }
10561028 }
1029+ fcx. write_error ( id) ;
1030+ }
10571031
1058- let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1059- let t_e = structurally_resolved_type ( fcx, span, t_e) ;
10601032
1061- if ty:: type_is_nil ( t_e) {
1062- fcx. type_error_message ( span, |actual| {
1063- format ! ( "cast from nil: `{}` as `{}`" ,
1064- actual,
1065- fcx. infcx( ) . ty_to_string( t_1) )
1066- } , t_e, None ) ;
1067- } else if ty:: type_is_nil ( t_1) {
1033+ fn check_cast_inner < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
1034+ span : Span ,
1035+ t_1 : Ty < ' tcx > ,
1036+ t_e : Ty < ' tcx > ,
1037+ e : & ast:: Expr ) {
1038+ fn cast_through_integer_err < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
1039+ span : Span ,
1040+ t_1 : Ty < ' tcx > ,
1041+ t_e : Ty < ' tcx > ) {
10681042 fcx. type_error_message ( span, |actual| {
1069- format ! ( "cast to nil: `{}` as `{}`" ,
1043+ format ! ( "illegal cast; cast through an \
1044+ integer first: `{}` as `{}`",
10701045 actual,
10711046 fcx. infcx( ) . ty_to_string( t_1) )
10721047 } , t_e, None ) ;
10731048 }
10741049
10751050 let t_e_is_bare_fn_item = ty:: type_is_bare_fn_item ( t_e) ;
1051+ let t_e_is_scalar = ty:: type_is_scalar ( t_e) ;
1052+ let t_e_is_integral = ty:: type_is_integral ( t_e) ;
1053+ let t_e_is_float = ty:: type_is_floating_point ( t_e) ;
1054+ let t_e_is_c_enum = ty:: type_is_c_like_enum ( fcx. tcx ( ) , t_e) ;
10761055
10771056 let t_1_is_scalar = ty:: type_is_scalar ( t_1) ;
10781057 let t_1_is_char = ty:: type_is_char ( t_1) ;
@@ -1081,18 +1060,9 @@ fn check_cast(fcx: &FnCtxt,
10811060
10821061 // casts to scalars other than `char` and `bare fn` are trivial
10831062 let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1063+
10841064 if t_e_is_bare_fn_item && t_1_is_bare_fn {
10851065 demand:: coerce ( fcx, e. span , t_1, & * e) ;
1086- } else if ty:: type_is_c_like_enum ( fcx. tcx ( ) , t_e) && t_1_is_trivial {
1087- if t_1_is_float || ty:: type_is_unsafe_ptr ( t_1) {
1088- fcx. type_error_message ( span, |actual| {
1089- format ! ( "illegal cast; cast through an \
1090- integer first: `{}` as `{}`",
1091- actual,
1092- fcx. infcx( ) . ty_to_string( t_1) )
1093- } , t_e, None ) ;
1094- }
1095- // casts from C-like enums are allowed
10961066 } else if t_1_is_char {
10971067 let t_e = fcx. infcx ( ) . shallow_resolve ( t_e) ;
10981068 if t_e. sty != ty:: ty_uint ( ast:: TyU8 ) {
@@ -1104,6 +1074,16 @@ fn check_cast(fcx: &FnCtxt,
11041074 } else if t_1. sty == ty:: ty_bool {
11051075 span_err ! ( fcx. tcx( ) . sess, span, E0054 ,
11061076 "cannot cast as `bool`, compare with zero instead" ) ;
1077+ } else if t_1_is_float && ( t_e_is_scalar || t_e_is_c_enum) && !(
1078+ t_e_is_integral || t_e_is_float || t_e. sty == ty:: ty_bool) {
1079+ // Casts to float must go through an integer or boolean
1080+ cast_through_integer_err ( fcx, span, t_1, t_e)
1081+ } else if t_e_is_c_enum && t_1_is_trivial {
1082+ if ty:: type_is_unsafe_ptr ( t_1) {
1083+ // ... and likewise with C enum -> *T
1084+ cast_through_integer_err ( fcx, span, t_1, t_e)
1085+ }
1086+ // casts from C-like enums are allowed
11071087 } else if ty:: type_is_region_ptr ( t_e) && ty:: type_is_unsafe_ptr ( t_1) {
11081088 fn types_compatible < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > , sp : Span ,
11091089 t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> bool {
@@ -1145,7 +1125,7 @@ fn check_cast(fcx: &FnCtxt,
11451125 demand:: coerce ( fcx, e. span , t_1, & * e) ;
11461126 }
11471127 }
1148- } else if !( ty :: type_is_scalar ( t_e ) && t_1_is_trivial) {
1128+ } else if !( t_e_is_scalar && t_1_is_trivial) {
11491129 /*
11501130 If more type combinations should be supported than are
11511131 supported here, then file an enhancement issue and
@@ -1156,15 +1136,49 @@ fn check_cast(fcx: &FnCtxt,
11561136 actual,
11571137 fcx. infcx( ) . ty_to_string( t_1) )
11581138 } , t_e, None ) ;
1159- } else if ty:: type_is_unsafe_ptr ( t_e) && t_1_is_float {
1160- fcx. type_error_message ( span, |actual| {
1161- format ! ( "cannot cast from pointer to float directly: `{}` as `{}`; cast through an \
1162- integer first",
1163- actual,
1164- fcx. infcx( ) . ty_to_string( t_1) )
1165- } , t_e, None ) ;
11661139 }
1140+ }
1141+
1142+ fn check_cast ( fcx : & FnCtxt ,
1143+ cast_expr : & ast:: Expr ,
1144+ e : & ast:: Expr ,
1145+ t : & ast:: Ty ) {
1146+ let id = cast_expr. id ;
1147+ let span = cast_expr. span ;
1148+
1149+ // Find the type of `e`. Supply hints based on the type we are casting to,
1150+ // if appropriate.
1151+ let t_1 = fcx. to_ty ( t) ;
1152+ let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1153+
1154+ check_expr_with_expectation ( fcx, e, ExpectCastableToType ( t_1) ) ;
1155+
1156+ let t_e = fcx. expr_ty ( e) ;
1157+
1158+ debug ! ( "t_1={}" , fcx. infcx( ) . ty_to_string( t_1) ) ;
1159+ debug ! ( "t_e={}" , fcx. infcx( ) . ty_to_string( t_e) ) ;
1160+
1161+ if ty:: type_is_error ( t_e) {
1162+ fcx. write_error ( id) ;
1163+ return
1164+ }
1165+
1166+ if !fcx. type_is_known_to_be_sized ( t_1, cast_expr. span ) {
1167+ report_cast_to_unsized_type ( fcx, span, t. span , e. span , t_1, t_e, id) ;
1168+ return
1169+ }
1170+
1171+ if ty:: type_is_trait ( t_1) {
1172+ // This will be looked up later on.
1173+ vtable:: check_object_cast ( fcx, cast_expr, e, t_1) ;
1174+ fcx. write_ty ( id, t_1) ;
1175+ return
1176+ }
1177+
1178+ let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1179+ let t_e = structurally_resolved_type ( fcx, span, t_e) ;
11671180
1181+ check_cast_inner ( fcx, span, t_1, t_e, e) ;
11681182 fcx. write_ty ( id, t_1) ;
11691183}
11701184
0 commit comments