@@ -32,6 +32,7 @@ use rustc_data_structures::fx::FxHashSet;
3232use rustc_errors:: codes:: * ;
3333use rustc_errors:: { Applicability , Diag , ErrorGuaranteed } ;
3434use rustc_hir:: { self as hir, ExprKind } ;
35+ use rustc_infer:: infer:: DefineOpaqueTypes ;
3536use rustc_macros:: { TypeFoldable , TypeVisitable } ;
3637use rustc_middle:: mir:: Mutability ;
3738use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
@@ -152,12 +153,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
152153}
153154
154155#[ derive( Copy , Clone , Debug ) ]
155- pub enum CastError {
156+ enum CastError < ' tcx > {
156157 ErrorGuaranteed ( ErrorGuaranteed ) ,
157158
158159 CastToBool ,
159160 CastToChar ,
160- DifferingKinds ,
161+ DifferingKinds {
162+ src_kind : PointerKind < ' tcx > ,
163+ dst_kind : PointerKind < ' tcx > ,
164+ } ,
161165 /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
162166 SizedUnsizedCast ,
163167 IllegalCast ,
@@ -177,7 +181,7 @@ pub enum CastError {
177181 ForeignNonExhaustiveAdt ,
178182}
179183
180- impl From < ErrorGuaranteed > for CastError {
184+ impl From < ErrorGuaranteed > for CastError < ' _ > {
181185 fn from ( err : ErrorGuaranteed ) -> Self {
182186 CastError :: ErrorGuaranteed ( err)
183187 }
@@ -251,7 +255,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
251255 }
252256 }
253257
254- fn report_cast_error ( & self , fcx : & FnCtxt < ' a , ' tcx > , e : CastError ) {
258+ fn report_cast_error ( & self , fcx : & FnCtxt < ' a , ' tcx > , e : CastError < ' tcx > ) {
255259 match e {
256260 CastError :: ErrorGuaranteed ( _) => {
257261 // an error has already been reported
@@ -306,10 +310,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
306310 CastError :: IllegalCast => {
307311 make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx) . emit ( ) ;
308312 }
309- CastError :: DifferingKinds => {
310- make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx)
311- . with_note ( "vtable kinds may not match" )
312- . emit ( ) ;
313+ CastError :: DifferingKinds { src_kind, dst_kind } => {
314+ let mut err =
315+ make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx) ;
316+
317+ match ( src_kind, dst_kind) {
318+ ( PointerKind :: VTable ( _) , PointerKind :: VTable ( _) ) => {
319+ err. note ( "the trait objects may have different vtables" ) ;
320+ }
321+ (
322+ PointerKind :: OfParam ( _) | PointerKind :: OfAlias ( _) ,
323+ PointerKind :: OfParam ( _)
324+ | PointerKind :: OfAlias ( _)
325+ | PointerKind :: VTable ( _)
326+ | PointerKind :: Length ,
327+ )
328+ | (
329+ PointerKind :: VTable ( _) | PointerKind :: Length ,
330+ PointerKind :: OfParam ( _) | PointerKind :: OfAlias ( _) ,
331+ ) => {
332+ err. note ( "the pointers may have different metadata" ) ;
333+ }
334+ ( PointerKind :: VTable ( _) , PointerKind :: Length )
335+ | ( PointerKind :: Length , PointerKind :: VTable ( _) ) => {
336+ err. note ( "the pointers have different metadata" ) ;
337+ }
338+ (
339+ PointerKind :: Thin ,
340+ PointerKind :: Thin
341+ | PointerKind :: VTable ( _)
342+ | PointerKind :: Length
343+ | PointerKind :: OfParam ( _)
344+ | PointerKind :: OfAlias ( _) ,
345+ )
346+ | (
347+ PointerKind :: VTable ( _)
348+ | PointerKind :: Length
349+ | PointerKind :: OfParam ( _)
350+ | PointerKind :: OfAlias ( _) ,
351+ PointerKind :: Thin ,
352+ )
353+ | ( PointerKind :: Length , PointerKind :: Length ) => {
354+ span_bug ! ( self . span, "unexpected cast error: {e:?}" )
355+ }
356+ }
357+
358+ err. emit ( ) ;
313359 }
314360 CastError :: CastToBool => {
315361 let expr_ty = fcx. resolve_vars_if_possible ( self . expr_ty ) ;
@@ -674,7 +720,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
674720 /// Checks a cast, and report an error if one exists. In some cases, this
675721 /// can return Ok and create type errors in the fcx rather than returning
676722 /// directly. coercion-cast is handled in check instead of here.
677- fn do_check ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Result < CastKind , CastError > {
723+ fn do_check ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Result < CastKind , CastError < ' tcx > > {
678724 use rustc_middle:: ty:: cast:: CastTy :: * ;
679725 use rustc_middle:: ty:: cast:: IntTy :: * ;
680726
@@ -802,27 +848,34 @@ impl<'a, 'tcx> CastCheck<'tcx> {
802848 fcx : & FnCtxt < ' a , ' tcx > ,
803849 m_src : ty:: TypeAndMut < ' tcx > ,
804850 m_dst : ty:: TypeAndMut < ' tcx > ,
805- ) -> Result < CastKind , CastError > {
851+ ) -> Result < CastKind , CastError < ' tcx > > {
806852 debug ! ( "check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}" ) ;
807- // ptr-ptr cast. vtables must match.
853+ // ptr-ptr cast. metadata must match.
808854
809855 let src_kind = fcx. tcx . erase_regions ( fcx. pointer_kind ( m_src. ty , self . span ) ?) ;
810856 let dst_kind = fcx. tcx . erase_regions ( fcx. pointer_kind ( m_dst. ty , self . span ) ?) ;
811857
812- match ( src_kind, dst_kind) {
813- // We can't cast if target pointer kind is unknown
814- ( _, None ) => Err ( CastError :: UnknownCastPtrKind ) ,
815- // Cast to thin pointer is OK
816- ( _, Some ( PointerKind :: Thin ) ) => Ok ( CastKind :: PtrPtrCast ) ,
858+ // We can't cast if target pointer kind is unknown
859+ let Some ( dst_kind) = dst_kind else {
860+ return Err ( CastError :: UnknownCastPtrKind ) ;
861+ } ;
862+
863+ // Cast to thin pointer is OK
864+ if dst_kind == PointerKind :: Thin {
865+ return Ok ( CastKind :: PtrPtrCast ) ;
866+ }
817867
818- // We can't cast to fat pointer if source pointer kind is unknown
819- ( None , _) => Err ( CastError :: UnknownExprPtrKind ) ,
868+ // We can't cast to fat pointer if source pointer kind is unknown
869+ let Some ( src_kind) = src_kind else {
870+ return Err ( CastError :: UnknownCastPtrKind ) ;
871+ } ;
820872
873+ match ( src_kind, dst_kind) {
821874 // thin -> fat? report invalid cast (don't complain about vtable kinds)
822- ( Some ( PointerKind :: Thin ) , _) => Err ( CastError :: SizedUnsizedCast ) ,
875+ ( PointerKind :: Thin , _) => Err ( CastError :: SizedUnsizedCast ) ,
823876
824877 // trait object -> trait object? need to do additional checks
825- ( Some ( PointerKind :: VTable ( src_tty) ) , Some ( PointerKind :: VTable ( dst_tty) ) ) => {
878+ ( PointerKind :: VTable ( src_tty) , PointerKind :: VTable ( dst_tty) ) => {
826879 match ( src_tty. principal ( ) , dst_tty. principal ( ) ) {
827880 // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
828881 // - `Src` and `Dst` traits are the same
@@ -838,7 +891,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
838891 // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
839892 // and is unaffected by this check.
840893 if src_principal. def_id ( ) != dst_principal. def_id ( ) {
841- return Err ( CastError :: DifferingKinds ) ;
894+ return Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ;
842895 }
843896
844897 // We need to reconstruct trait object types.
@@ -864,7 +917,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
864917 ) ) ;
865918
866919 // `dyn Src = dyn Dst`, this checks for matching traits/generics
867- fcx. demand_eqtype ( self . span , src_obj, dst_obj) ;
920+ // This is `demand_eqtype`, but inlined to give a better error.
921+ let cause = fcx. misc ( self . span ) ;
922+ if fcx
923+ . at ( & cause, fcx. param_env )
924+ . eq ( DefineOpaqueTypes :: Yes , src_obj, dst_obj)
925+ . map ( |infer_ok| fcx. register_infer_ok_obligations ( infer_ok) )
926+ . is_err ( )
927+ {
928+ return Err ( CastError :: DifferingKinds { src_kind, dst_kind } ) ;
929+ }
868930
869931 // Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
870932 // Emit an FCW otherwise.
@@ -909,25 +971,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
909971
910972 // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
911973 // FIXME: allow this
912- ( Some ( _) , None ) => Err ( CastError :: DifferingKinds ) ,
974+ ( Some ( _) , None ) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
913975
914976 // dyn Auto -> dyn Trait? not ok.
915- ( None , Some ( _) ) => Err ( CastError :: DifferingKinds ) ,
977+ ( None , Some ( _) ) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
916978 }
917979 }
918980
919981 // fat -> fat? metadata kinds must match
920- ( Some ( src_kind) , Some ( dst_kind) ) if src_kind == dst_kind => Ok ( CastKind :: PtrPtrCast ) ,
982+ ( src_kind, dst_kind) if src_kind == dst_kind => Ok ( CastKind :: PtrPtrCast ) ,
921983
922- ( _, _) => Err ( CastError :: DifferingKinds ) ,
984+ ( _, _) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
923985 }
924986 }
925987
926988 fn check_fptr_ptr_cast (
927989 & self ,
928990 fcx : & FnCtxt < ' a , ' tcx > ,
929991 m_cast : ty:: TypeAndMut < ' tcx > ,
930- ) -> Result < CastKind , CastError > {
992+ ) -> Result < CastKind , CastError < ' tcx > > {
931993 // fptr-ptr cast. must be to thin ptr
932994
933995 match fcx. pointer_kind ( m_cast. ty , self . span ) ? {
@@ -941,7 +1003,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
9411003 & self ,
9421004 fcx : & FnCtxt < ' a , ' tcx > ,
9431005 m_expr : ty:: TypeAndMut < ' tcx > ,
944- ) -> Result < CastKind , CastError > {
1006+ ) -> Result < CastKind , CastError < ' tcx > > {
9451007 // ptr-addr cast. must be from thin ptr
9461008
9471009 match fcx. pointer_kind ( m_expr. ty , self . span ) ? {
@@ -956,7 +1018,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
9561018 fcx : & FnCtxt < ' a , ' tcx > ,
9571019 m_expr : ty:: TypeAndMut < ' tcx > ,
9581020 m_cast : ty:: TypeAndMut < ' tcx > ,
959- ) -> Result < CastKind , CastError > {
1021+ ) -> Result < CastKind , CastError < ' tcx > > {
9601022 // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
9611023 if m_expr. mutbl >= m_cast. mutbl {
9621024 if let ty:: Array ( ety, _) = m_expr. ty . kind ( ) {
@@ -991,7 +1053,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
9911053 & self ,
9921054 fcx : & FnCtxt < ' a , ' tcx > ,
9931055 m_cast : TypeAndMut < ' tcx > ,
994- ) -> Result < CastKind , CastError > {
1056+ ) -> Result < CastKind , CastError < ' tcx > > {
9951057 // ptr-addr cast. pointer must be thin.
9961058 match fcx. pointer_kind ( m_cast. ty , self . span ) ? {
9971059 None => Err ( CastError :: UnknownCastPtrKind ) ,
0 commit comments