1414//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
1515//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
1616//! 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*
1818//! * `e` has type `usize` and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
1919//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
2020//! * `e` is a C-like enum and `U` is an integer type or `bool`; *enum-cast*
2121//! * `e` has type `bool` and `U` is an integer; *bool-cast*
2222//! * `e` has type `u8` and `U` is `char`; *u8-char-cast*
2323//! * `e` has type `&.[T; n]` and `U` is `*T`, and `e` is a mutable
2424//! 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`).
2536
2637use super :: coercion;
27- use super :: demand;
2838use super :: FnCtxt ;
2939use super :: structurally_resolved_type;
3040
@@ -33,12 +43,10 @@ use middle::infer;
3343use middle:: ty;
3444use middle:: ty:: Ty ;
3545use syntax:: ast;
36- use syntax:: ast:: UintTy :: { TyU8 , TyUs } ;
46+ use syntax:: ast:: UintTy :: { TyU8 } ;
3747use syntax:: codemap:: Span ;
3848use util:: ppaux:: Repr ;
3949
40- use std:: fmt;
41-
4250/// Reifies a cast check to be checked once we have full type information for
4351/// a function context.
4452pub struct CastCheck < ' tcx > {
@@ -62,6 +70,7 @@ enum ETy<'tcx> {
6270 Float ,
6371 Bool ,
6472 Char ,
73+ FPtr ,
6574 Ptr ( & ' tcx ty:: mt < ' tcx > ) ,
6675 RPtr ( & ' tcx ty:: mt < ' tcx > ) ,
6776}
@@ -79,16 +88,41 @@ impl<'tcx> ETy<'tcx> {
7988 fcx. tcx ( ) , t) => Some ( ETy :: CEnum ) ,
8089 ty:: ty_ptr( ref mt) => Some ( ETy :: Ptr ( mt) ) ,
8190 ty:: ty_rptr( _, ref mt) => Some ( ETy :: RPtr ( mt) ) ,
91+ ty:: ty_bare_fn( ..) => Some ( ETy :: FPtr ) ,
8292 _ => None ,
8393 }
8494 }
8595}
8696
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+ }
87120
88121#[ derive( Copy ) ]
89122enum CastError {
90123 CastToBool ,
91124 CastToChar ,
125+ DifferingKinds ,
92126 IllegalCast ,
93127 NeedViaPtr ,
94128 NeedViaInt ,
@@ -149,6 +183,13 @@ impl<'tcx> CastCheck<'tcx> {
149183 fcx. infcx( ) . ty_to_string( self . cast_ty) )
150184 } , self . expr_ty , None ) ;
151185 }
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+ }
152193 CastError :: RefToMutPtr => {
153194 span_err ! ( fcx. tcx( ) . sess, self . span, E0188 ,
154195 "cannot cast an immutable reference to a \
@@ -186,7 +227,7 @@ impl<'tcx> CastCheck<'tcx> {
186227 self . expr_ty = structurally_resolved_type ( fcx, self . span , self . expr_ty ) ;
187228 self . cast_ty = structurally_resolved_type ( fcx, self . span , self . cast_ty ) ;
188229
189- println ! ( "cast: {} -> {}" , self . expr_ty. repr( fcx. tcx( ) ) ,
230+ debug ! ( "check_cast( {} -> {}) " , self . expr_ty. repr( fcx. tcx( ) ) ,
190231 self . cast_ty. repr( fcx. tcx( ) ) ) ;
191232
192233 if ty:: type_is_error ( self . expr_ty ) || ty:: type_is_error ( self . cast_ty ) {
@@ -217,17 +258,17 @@ impl<'tcx> CastCheck<'tcx> {
217258
218259 match ( t_e, t_1) {
219260 // All non-coercion casts create a true scalar
220- ( _, RPtr ( _) ) | ( _, CEnum ) => Err ( CastError :: NonScalar ) ,
261+ ( _, RPtr ( _) ) | ( _, CEnum ) | ( _ , FPtr ) => Err ( CastError :: NonScalar ) ,
221262
222263 ( 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
227267 ( 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 ) ,
231272
232273 ( CEnum , Bool ) | ( CEnum , Int ( _) ) => Ok ( ( ) ) , // enum-cast
233274 ( _, Bool ) => Err ( CastError :: CastToBool ) ,
@@ -247,20 +288,42 @@ impl<'tcx> CastCheck<'tcx> {
247288 ( Bool , Ptr ( _) ) | ( CEnum , Ptr ( _) ) | ( Char , Ptr ( _) )
248289 => Err ( CastError :: NeedViaUsize ) ,
249290
250-
251291 ( RPtr ( rmt) , Ptr ( mt) ) => self . check_ref_cast ( fcx, rmt, mt) , // array-ptr-cast
252292 }
253293 }
254294
255295 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 > )
259299 -> Result < ( ) , CastError >
260300 {
261301 // 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+ }
264327 }
265328
266329 fn check_ref_cast < ' a > ( & self ,
@@ -294,7 +357,7 @@ impl<'tcx> CastCheck<'tcx> {
294357 Err ( CastError :: IllegalCast )
295358 }
296359
297- fn check_ptr_addr_cast < ' a > ( & self ,
360+ fn check_addr_ptr_cast < ' a > ( & self ,
298361 fcx : & FnCtxt < ' a , ' tcx > ,
299362 m_1 : & ' tcx ty:: mt < ' tcx > )
300363 -> Result < ( ) , CastError >
@@ -307,7 +370,7 @@ impl<'tcx> CastCheck<'tcx> {
307370 }
308371 }
309372
310- fn check_addr_ptr_cast < ' a > ( & self ,
373+ fn check_ptr_addr_cast < ' a > ( & self ,
311374 fcx : & FnCtxt < ' a , ' tcx > ,
312375 m_e : & ' tcx ty:: mt < ' tcx > )
313376 -> Result < ( ) , CastError >
0 commit comments