@@ -993,86 +993,65 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
993
993
}
994
994
}
995
995
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) ;
1045
1019
}
1046
1020
}
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
+ }
1056
1028
}
1029
+ fcx. write_error ( id) ;
1030
+ }
1057
1031
1058
- let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1059
- let t_e = structurally_resolved_type ( fcx, span, t_e) ;
1060
1032
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 > ) {
1068
1042
fcx. type_error_message ( span, |actual| {
1069
- format ! ( "cast to nil: `{}` as `{}`" ,
1043
+ format ! ( "illegal cast; cast through an \
1044
+ integer first: `{}` as `{}`",
1070
1045
actual,
1071
1046
fcx. infcx( ) . ty_to_string( t_1) )
1072
1047
} , t_e, None ) ;
1073
1048
}
1074
1049
1075
1050
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) ;
1076
1055
1077
1056
let t_1_is_scalar = ty:: type_is_scalar ( t_1) ;
1078
1057
let t_1_is_char = ty:: type_is_char ( t_1) ;
@@ -1081,18 +1060,9 @@ fn check_cast(fcx: &FnCtxt,
1081
1060
1082
1061
// casts to scalars other than `char` and `bare fn` are trivial
1083
1062
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1063
+
1084
1064
if t_e_is_bare_fn_item && t_1_is_bare_fn {
1085
1065
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
1096
1066
} else if t_1_is_char {
1097
1067
let t_e = fcx. infcx ( ) . shallow_resolve ( t_e) ;
1098
1068
if t_e. sty != ty:: ty_uint ( ast:: TyU8 ) {
@@ -1104,6 +1074,16 @@ fn check_cast(fcx: &FnCtxt,
1104
1074
} else if t_1. sty == ty:: ty_bool {
1105
1075
span_err ! ( fcx. tcx( ) . sess, span, E0054 ,
1106
1076
"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
1107
1087
} else if ty:: type_is_region_ptr ( t_e) && ty:: type_is_unsafe_ptr ( t_1) {
1108
1088
fn types_compatible < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > , sp : Span ,
1109
1089
t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> bool {
@@ -1145,7 +1125,7 @@ fn check_cast(fcx: &FnCtxt,
1145
1125
demand:: coerce ( fcx, e. span , t_1, & * e) ;
1146
1126
}
1147
1127
}
1148
- } else if !( ty :: type_is_scalar ( t_e ) && t_1_is_trivial) {
1128
+ } else if !( t_e_is_scalar && t_1_is_trivial) {
1149
1129
/*
1150
1130
If more type combinations should be supported than are
1151
1131
supported here, then file an enhancement issue and
@@ -1156,15 +1136,49 @@ fn check_cast(fcx: &FnCtxt,
1156
1136
actual,
1157
1137
fcx. infcx( ) . ty_to_string( t_1) )
1158
1138
} , 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 ) ;
1166
1139
}
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) ;
1167
1180
1181
+ check_cast_inner ( fcx, span, t_1, t_e, e) ;
1168
1182
fcx. write_ty ( id, t_1) ;
1169
1183
}
1170
1184
0 commit comments