14
14
//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
15
15
//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
16
16
//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
17
- //! * `e` has type `*T` and `U` is `usize` , while `T: Sized`; *ptr-addr-cast*
17
+ //! * `e` has type `*T` and `U` is a numeric type , while `T: Sized`; *ptr-addr-cast*
18
18
//! * `e` has type `usize` and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
19
19
//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
20
20
//! * `e` is a C-like enum and `U` is an integer type or `bool`; *enum-cast*
21
21
//! * `e` has type `bool` and `U` is an integer; *bool-cast*
22
22
//! * `e` has type `u8` and `U` is `char`; *u8-char-cast*
23
23
//! * `e` has type `&.[T; n]` and `U` is `*T`, and `e` is a mutable
24
24
//! reference if `U` is. *array-ptr-cast*
25
+ //! * `e` is a function pointer type and `U` has type `*T`,
26
+ //! while `T: Sized`; *fptr-ptr-cast*
27
+ //! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
28
+ //!
29
+ //! where `&.T` and `*T` are references of either mutability,
30
+ //! and where unsize_kind(`T`) is the kind of the unsize info
31
+ //! in `T` - a vtable or a length (or `()` if `T: Sized`).
32
+ //!
33
+ //! Casting is not transitive, that is, even if `e as U1 as U2` is a valid
34
+ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if
35
+ //! `U1` coerces to `U2`).
25
36
26
37
use super :: coercion;
27
- use super :: demand;
28
38
use super :: FnCtxt ;
29
39
use super :: structurally_resolved_type;
30
40
@@ -33,12 +43,10 @@ use middle::infer;
33
43
use middle:: ty;
34
44
use middle:: ty:: Ty ;
35
45
use syntax:: ast;
36
- use syntax:: ast:: UintTy :: { TyU8 , TyUs } ;
46
+ use syntax:: ast:: UintTy :: { TyU8 } ;
37
47
use syntax:: codemap:: Span ;
38
48
use util:: ppaux:: Repr ;
39
49
40
- use std:: fmt;
41
-
42
50
/// Reifies a cast check to be checked once we have full type information for
43
51
/// a function context.
44
52
pub struct CastCheck < ' tcx > {
@@ -62,6 +70,7 @@ enum ETy<'tcx> {
62
70
Float ,
63
71
Bool ,
64
72
Char ,
73
+ FPtr ,
65
74
Ptr ( & ' tcx ty:: mt < ' tcx > ) ,
66
75
RPtr ( & ' tcx ty:: mt < ' tcx > ) ,
67
76
}
@@ -79,16 +88,41 @@ impl<'tcx> ETy<'tcx> {
79
88
fcx. tcx ( ) , t) => Some ( ETy :: CEnum ) ,
80
89
ty:: ty_ptr( ref mt) => Some ( ETy :: Ptr ( mt) ) ,
81
90
ty:: ty_rptr( _, ref mt) => Some ( ETy :: RPtr ( mt) ) ,
91
+ ty:: ty_bare_fn( ..) => Some ( ETy :: FPtr ) ,
82
92
_ => None ,
83
93
}
84
94
}
85
95
}
86
96
97
+ #[ derive( Copy , PartialEq , Eq ) ]
98
+ enum UnsizeKind {
99
+ Vtable ,
100
+ Length
101
+ }
102
+
103
+ /// Returns the kind of unsize information of t, or None
104
+ /// if t is sized or it is unknown.
105
+ fn unsize_kind < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
106
+ t : Ty < ' tcx > )
107
+ -> Option < UnsizeKind > {
108
+ match t. sty {
109
+ ty:: ty_vec( _, None ) => Some ( UnsizeKind :: Length ) ,
110
+ ty:: ty_trait( _) => Some ( UnsizeKind :: Vtable ) ,
111
+ ty:: ty_struct( did, substs) => {
112
+ match ty:: struct_fields ( fcx. tcx ( ) , did, substs) . pop ( ) {
113
+ None => None ,
114
+ Some ( f) => unsize_kind ( fcx, f. mt . ty )
115
+ }
116
+ }
117
+ _ => None
118
+ }
119
+ }
87
120
88
121
#[ derive( Copy ) ]
89
122
enum CastError {
90
123
CastToBool ,
91
124
CastToChar ,
125
+ DifferingKinds ,
92
126
IllegalCast ,
93
127
NeedViaPtr ,
94
128
NeedViaInt ,
@@ -149,6 +183,13 @@ impl<'tcx> CastCheck<'tcx> {
149
183
fcx. infcx( ) . ty_to_string( self . cast_ty) )
150
184
} , self . expr_ty , None ) ;
151
185
}
186
+ CastError :: DifferingKinds => {
187
+ fcx. type_error_message ( self . span , |actual| {
188
+ format ! ( "illegal cast: `{}` as `{}`; vtable kinds may not match" ,
189
+ actual,
190
+ fcx. infcx( ) . ty_to_string( self . cast_ty) )
191
+ } , self . expr_ty , None ) ;
192
+ }
152
193
CastError :: RefToMutPtr => {
153
194
span_err ! ( fcx. tcx( ) . sess, self . span, E0188 ,
154
195
"cannot cast an immutable reference to a \
@@ -186,7 +227,7 @@ impl<'tcx> CastCheck<'tcx> {
186
227
self . expr_ty = structurally_resolved_type ( fcx, self . span , self . expr_ty ) ;
187
228
self . cast_ty = structurally_resolved_type ( fcx, self . span , self . cast_ty ) ;
188
229
189
- println ! ( "cast: {} -> {}" , self . expr_ty. repr( fcx. tcx( ) ) ,
230
+ debug ! ( "check_cast( {} -> {}) " , self . expr_ty. repr( fcx. tcx( ) ) ,
190
231
self . cast_ty. repr( fcx. tcx( ) ) ) ;
191
232
192
233
if ty:: type_is_error ( self . expr_ty ) || ty:: type_is_error ( self . cast_ty ) {
@@ -217,17 +258,17 @@ impl<'tcx> CastCheck<'tcx> {
217
258
218
259
match ( t_e, t_1) {
219
260
// All non-coercion casts create a true scalar
220
- ( _, RPtr ( _) ) | ( _, CEnum ) => Err ( CastError :: NonScalar ) ,
261
+ ( _, RPtr ( _) ) | ( _, CEnum ) | ( _ , FPtr ) => Err ( CastError :: NonScalar ) ,
221
262
222
263
( Ptr ( m1) , Ptr ( m2) ) => self . check_ptr_ptr_cast ( fcx, m1, m2) , // ptr-ptr-cast
223
-
224
- ( Ptr ( mt) , Int ( U ( ast:: TyUs ) ) ) =>
225
- self . check_ptr_addr_cast ( fcx, mt) , // ptr-addr-cast
226
- ( Ptr ( _) , Int ( _) ) | ( Ptr ( _) , Float ) => Err ( CastError :: NeedViaUsize ) ,
264
+ ( Ptr ( mt) , Int ( _) ) => self . check_ptr_addr_cast ( fcx, mt) , // ptr-addr-cast
265
+ ( Ptr ( _) , Float ) | ( FPtr , Float ) => Err ( CastError :: NeedViaUsize ) ,
266
+ ( FPtr , Int ( _) ) => Ok ( ( ) ) , // fptr-addr-cast
227
267
( RPtr ( _) , Int ( _) ) | ( RPtr ( _) , Float ) => Err ( CastError :: NeedViaPtr ) ,
228
- ( Int ( U ( ast:: TyUs ) ) , Ptr ( mt) ) =>
229
- self . check_addr_ptr_cast ( fcx, mt) , // addr-ptr-cast
230
- ( Int ( _) , Ptr ( _) ) | ( Float , Ptr ( _) ) => Err ( CastError :: NeedViaUsize ) ,
268
+
269
+ ( Int ( _) , Ptr ( mt) ) => self . check_addr_ptr_cast ( fcx, mt) , // addr-ptr-cast
270
+ ( FPtr , Ptr ( mt) ) => self . check_fptr_ptr_cast ( fcx, mt) ,
271
+ ( Float , Ptr ( _) ) => Err ( CastError :: NeedViaUsize ) ,
231
272
232
273
( CEnum , Bool ) | ( CEnum , Int ( _) ) => Ok ( ( ) ) , // enum-cast
233
274
( _, Bool ) => Err ( CastError :: CastToBool ) ,
@@ -247,20 +288,42 @@ impl<'tcx> CastCheck<'tcx> {
247
288
( Bool , Ptr ( _) ) | ( CEnum , Ptr ( _) ) | ( Char , Ptr ( _) )
248
289
=> Err ( CastError :: NeedViaUsize ) ,
249
290
250
-
251
291
( RPtr ( rmt) , Ptr ( mt) ) => self . check_ref_cast ( fcx, rmt, mt) , // array-ptr-cast
252
292
}
253
293
}
254
294
255
295
fn check_ptr_ptr_cast < ' a > ( & self ,
256
- _fcx : & FnCtxt < ' a , ' tcx > ,
257
- _m_e : & ' tcx ty:: mt < ' tcx > ,
258
- _m_1 : & ' tcx ty:: mt < ' tcx > )
296
+ fcx : & FnCtxt < ' a , ' tcx > ,
297
+ m_e : & ' tcx ty:: mt < ' tcx > ,
298
+ m_1 : & ' tcx ty:: mt < ' tcx > )
259
299
-> Result < ( ) , CastError >
260
300
{
261
301
// ptr-ptr cast. vtables must match.
262
- // TODO: implement
263
- Ok ( ( ) )
302
+
303
+ // Cast to sized is OK
304
+ if fcx. type_is_known_to_be_sized ( m_1. ty , self . span ) {
305
+ return Ok ( ( ) ) ;
306
+ }
307
+
308
+ // vtable kinds must match
309
+ match ( unsize_kind ( fcx, m_1. ty ) , unsize_kind ( fcx, m_e. ty ) ) {
310
+ ( Some ( a) , Some ( b) ) if a == b => Ok ( ( ) ) ,
311
+ _ => Err ( CastError :: DifferingKinds )
312
+ }
313
+ }
314
+
315
+ fn check_fptr_ptr_cast < ' a > ( & self ,
316
+ fcx : & FnCtxt < ' a , ' tcx > ,
317
+ m_1 : & ' tcx ty:: mt < ' tcx > )
318
+ -> Result < ( ) , CastError >
319
+ {
320
+ // fptr-ptr cast. must be to sized ptr
321
+
322
+ if fcx. type_is_known_to_be_sized ( m_1. ty , self . span ) {
323
+ Ok ( ( ) )
324
+ } else {
325
+ Err ( CastError :: IllegalCast )
326
+ }
264
327
}
265
328
266
329
fn check_ref_cast < ' a > ( & self ,
@@ -294,7 +357,7 @@ impl<'tcx> CastCheck<'tcx> {
294
357
Err ( CastError :: IllegalCast )
295
358
}
296
359
297
- fn check_ptr_addr_cast < ' a > ( & self ,
360
+ fn check_addr_ptr_cast < ' a > ( & self ,
298
361
fcx : & FnCtxt < ' a , ' tcx > ,
299
362
m_1 : & ' tcx ty:: mt < ' tcx > )
300
363
-> Result < ( ) , CastError >
@@ -307,7 +370,7 @@ impl<'tcx> CastCheck<'tcx> {
307
370
}
308
371
}
309
372
310
- fn check_addr_ptr_cast < ' a > ( & self ,
373
+ fn check_ptr_addr_cast < ' a > ( & self ,
311
374
fcx : & FnCtxt < ' a , ' tcx > ,
312
375
m_e : & ' tcx ty:: mt < ' tcx > )
313
376
-> Result < ( ) , CastError >
0 commit comments