@@ -990,86 +990,65 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
990
990
}
991
991
}
992
992
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) ;
1042
1016
}
1043
1017
}
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
+ }
1053
1025
}
1026
+ fcx. write_error ( id) ;
1027
+ }
1054
1028
1055
- let t_1 = structurally_resolved_type ( fcx, span, t_1) ;
1056
- let t_e = structurally_resolved_type ( fcx, span, t_e) ;
1057
1029
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 > ) {
1065
1039
fcx. type_error_message ( span, |actual| {
1066
- format ! ( "cast to nil: `{}` as `{}`" ,
1040
+ format ! ( "illegal cast; cast through an \
1041
+ integer first: `{}` as `{}`",
1067
1042
actual,
1068
1043
fcx. infcx( ) . ty_to_string( t_1) )
1069
1044
} , t_e, None ) ;
1070
1045
}
1071
1046
1072
1047
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) ;
1073
1052
1074
1053
let t_1_is_scalar = ty:: type_is_scalar ( t_1) ;
1075
1054
let t_1_is_char = ty:: type_is_char ( t_1) ;
@@ -1078,18 +1057,9 @@ fn check_cast(fcx: &FnCtxt,
1078
1057
1079
1058
// casts to scalars other than `char` and `bare fn` are trivial
1080
1059
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1060
+
1081
1061
if t_e_is_bare_fn_item && t_1_is_bare_fn {
1082
1062
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
1093
1063
} else if t_1_is_char {
1094
1064
let t_e = fcx. infcx ( ) . shallow_resolve ( t_e) ;
1095
1065
if t_e. sty != ty:: ty_uint ( ast:: TyU8 ) {
@@ -1101,6 +1071,16 @@ fn check_cast(fcx: &FnCtxt,
1101
1071
} else if t_1. sty == ty:: ty_bool {
1102
1072
span_err ! ( fcx. tcx( ) . sess, span, E0054 ,
1103
1073
"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
1104
1084
} else if ty:: type_is_region_ptr ( t_e) && ty:: type_is_unsafe_ptr ( t_1) {
1105
1085
fn types_compatible < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > , sp : Span ,
1106
1086
t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> bool {
@@ -1142,7 +1122,7 @@ fn check_cast(fcx: &FnCtxt,
1142
1122
demand:: coerce ( fcx, e. span , t_1, & * e) ;
1143
1123
}
1144
1124
}
1145
- } else if !( ty :: type_is_scalar ( t_e ) && t_1_is_trivial) {
1125
+ } else if !( t_e_is_scalar && t_1_is_trivial) {
1146
1126
/*
1147
1127
If more type combinations should be supported than are
1148
1128
supported here, then file an enhancement issue and
@@ -1153,15 +1133,49 @@ fn check_cast(fcx: &FnCtxt,
1153
1133
actual,
1154
1134
fcx. infcx( ) . ty_to_string( t_1) )
1155
1135
} , 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 ) ;
1163
1136
}
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) ;
1164
1177
1178
+ check_cast_inner ( fcx, span, t_1, t_e, e) ;
1165
1179
fcx. write_ty ( id, t_1) ;
1166
1180
}
1167
1181
0 commit comments