@@ -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
@@ -303,10 +307,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
303307 CastError :: IllegalCast => {
304308 make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx) . emit ( ) ;
305309 }
306- CastError :: DifferingKinds => {
307- make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx)
308- . with_note ( "vtable kinds may not match" )
309- . emit ( ) ;
310+ CastError :: DifferingKinds { src_kind, dst_kind } => {
311+ let mut err =
312+ make_invalid_casting_error ( self . span , self . expr_ty , self . cast_ty , fcx) ;
313+
314+ match ( src_kind, dst_kind) {
315+ ( PointerKind :: VTable ( _) , PointerKind :: VTable ( _) ) => {
316+ err. note ( "the trait objects may have different vtables" ) ;
317+ }
318+ (
319+ PointerKind :: OfParam ( _) | PointerKind :: OfAlias ( _) ,
320+ PointerKind :: OfParam ( _)
321+ | PointerKind :: OfAlias ( _)
322+ | PointerKind :: VTable ( _)
323+ | PointerKind :: Length ,
324+ )
325+ | (
326+ PointerKind :: VTable ( _) | PointerKind :: Length ,
327+ PointerKind :: OfParam ( _) | PointerKind :: OfAlias ( _) ,
328+ ) => {
329+ err. note ( "the pointers may have different metadata" ) ;
330+ }
331+ ( PointerKind :: VTable ( _) , PointerKind :: Length )
332+ | ( PointerKind :: Length , PointerKind :: VTable ( _) ) => {
333+ err. note ( "the pointers have different metadata" ) ;
334+ }
335+ (
336+ PointerKind :: Thin ,
337+ PointerKind :: Thin
338+ | PointerKind :: VTable ( _)
339+ | PointerKind :: Length
340+ | PointerKind :: OfParam ( _)
341+ | PointerKind :: OfAlias ( _) ,
342+ )
343+ | (
344+ PointerKind :: VTable ( _)
345+ | PointerKind :: Length
346+ | PointerKind :: OfParam ( _)
347+ | PointerKind :: OfAlias ( _) ,
348+ PointerKind :: Thin ,
349+ )
350+ | ( PointerKind :: Length , PointerKind :: Length ) => {
351+ span_bug ! ( self . span, "unexpected cast error: {e:?}" )
352+ }
353+ }
354+
355+ err. emit ( ) ;
310356 }
311357 CastError :: CastToBool => {
312358 let expr_ty = fcx. resolve_vars_if_possible ( self . expr_ty ) ;
@@ -670,7 +716,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
670716 /// Checks a cast, and report an error if one exists. In some cases, this
671717 /// can return Ok and create type errors in the fcx rather than returning
672718 /// directly. coercion-cast is handled in check instead of here.
673- fn do_check ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Result < CastKind , CastError > {
719+ fn do_check ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Result < CastKind , CastError < ' tcx > > {
674720 use rustc_middle:: ty:: cast:: CastTy :: * ;
675721 use rustc_middle:: ty:: cast:: IntTy :: * ;
676722
@@ -798,27 +844,34 @@ impl<'a, 'tcx> CastCheck<'tcx> {
798844 fcx : & FnCtxt < ' a , ' tcx > ,
799845 m_src : ty:: TypeAndMut < ' tcx > ,
800846 m_dst : ty:: TypeAndMut < ' tcx > ,
801- ) -> Result < CastKind , CastError > {
847+ ) -> Result < CastKind , CastError < ' tcx > > {
802848 debug ! ( "check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}" ) ;
803- // ptr-ptr cast. vtables must match.
849+ // ptr-ptr cast. metadata must match.
804850
805851 let src_kind = fcx. tcx . erase_regions ( fcx. pointer_kind ( m_src. ty , self . span ) ?) ;
806852 let dst_kind = fcx. tcx . erase_regions ( fcx. pointer_kind ( m_dst. ty , self . span ) ?) ;
807853
808- match ( src_kind, dst_kind) {
809- // We can't cast if target pointer kind is unknown
810- ( _, None ) => Err ( CastError :: UnknownCastPtrKind ) ,
811- // Cast to thin pointer is OK
812- ( _, Some ( PointerKind :: Thin ) ) => Ok ( CastKind :: PtrPtrCast ) ,
854+ // We can't cast if target pointer kind is unknown
855+ let Some ( dst_kind) = dst_kind else {
856+ return Err ( CastError :: UnknownCastPtrKind ) ;
857+ } ;
858+
859+ // Cast to thin pointer is OK
860+ if dst_kind == PointerKind :: Thin {
861+ return Ok ( CastKind :: PtrPtrCast ) ;
862+ }
813863
814- // We can't cast to fat pointer if source pointer kind is unknown
815- ( None , _) => Err ( CastError :: UnknownExprPtrKind ) ,
864+ // We can't cast to fat pointer if source pointer kind is unknown
865+ let Some ( src_kind) = src_kind else {
866+ return Err ( CastError :: UnknownCastPtrKind ) ;
867+ } ;
816868
869+ match ( src_kind, dst_kind) {
817870 // thin -> fat? report invalid cast (don't complain about vtable kinds)
818- ( Some ( PointerKind :: Thin ) , _) => Err ( CastError :: SizedUnsizedCast ) ,
871+ ( PointerKind :: Thin , _) => Err ( CastError :: SizedUnsizedCast ) ,
819872
820873 // trait object -> trait object? need to do additional checks
821- ( Some ( PointerKind :: VTable ( src_tty) ) , Some ( PointerKind :: VTable ( dst_tty) ) ) => {
874+ ( PointerKind :: VTable ( src_tty) , PointerKind :: VTable ( dst_tty) ) => {
822875 match ( src_tty. principal ( ) , dst_tty. principal ( ) ) {
823876 // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
824877 // - `Src` and `Dst` traits are the same
@@ -834,7 +887,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
834887 // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
835888 // and is unaffected by this check.
836889 if src_principal. def_id ( ) != dst_principal. def_id ( ) {
837- return Err ( CastError :: DifferingKinds ) ;
890+ return Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ;
838891 }
839892
840893 // We need to reconstruct trait object types.
@@ -860,7 +913,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
860913 ) ) ;
861914
862915 // `dyn Src = dyn Dst`, this checks for matching traits/generics
863- fcx. demand_eqtype ( self . span , src_obj, dst_obj) ;
916+ // This is `demand_eqtype`, but inlined to give a better error.
917+ let cause = fcx. misc ( self . span ) ;
918+ if fcx
919+ . at ( & cause, fcx. param_env )
920+ . eq ( DefineOpaqueTypes :: Yes , src_obj, dst_obj)
921+ . map ( |infer_ok| fcx. register_infer_ok_obligations ( infer_ok) )
922+ . is_err ( )
923+ {
924+ return Err ( CastError :: DifferingKinds { src_kind, dst_kind } ) ;
925+ }
864926
865927 // Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
866928 // Emit an FCW otherwise.
@@ -905,25 +967,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
905967
906968 // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
907969 // FIXME: allow this
908- ( Some ( _) , None ) => Err ( CastError :: DifferingKinds ) ,
970+ ( Some ( _) , None ) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
909971
910972 // dyn Auto -> dyn Trait? not ok.
911- ( None , Some ( _) ) => Err ( CastError :: DifferingKinds ) ,
973+ ( None , Some ( _) ) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
912974 }
913975 }
914976
915977 // fat -> fat? metadata kinds must match
916- ( Some ( src_kind) , Some ( dst_kind) ) if src_kind == dst_kind => Ok ( CastKind :: PtrPtrCast ) ,
978+ ( src_kind, dst_kind) if src_kind == dst_kind => Ok ( CastKind :: PtrPtrCast ) ,
917979
918- ( _, _) => Err ( CastError :: DifferingKinds ) ,
980+ ( _, _) => Err ( CastError :: DifferingKinds { src_kind , dst_kind } ) ,
919981 }
920982 }
921983
922984 fn check_fptr_ptr_cast (
923985 & self ,
924986 fcx : & FnCtxt < ' a , ' tcx > ,
925987 m_cast : ty:: TypeAndMut < ' tcx > ,
926- ) -> Result < CastKind , CastError > {
988+ ) -> Result < CastKind , CastError < ' tcx > > {
927989 // fptr-ptr cast. must be to thin ptr
928990
929991 match fcx. pointer_kind ( m_cast. ty , self . span ) ? {
@@ -937,7 +999,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
937999 & self ,
9381000 fcx : & FnCtxt < ' a , ' tcx > ,
9391001 m_expr : ty:: TypeAndMut < ' tcx > ,
940- ) -> Result < CastKind , CastError > {
1002+ ) -> Result < CastKind , CastError < ' tcx > > {
9411003 // ptr-addr cast. must be from thin ptr
9421004
9431005 match fcx. pointer_kind ( m_expr. ty , self . span ) ? {
@@ -952,7 +1014,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
9521014 fcx : & FnCtxt < ' a , ' tcx > ,
9531015 m_expr : ty:: TypeAndMut < ' tcx > ,
9541016 m_cast : ty:: TypeAndMut < ' tcx > ,
955- ) -> Result < CastKind , CastError > {
1017+ ) -> Result < CastKind , CastError < ' tcx > > {
9561018 // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
9571019 if m_expr. mutbl >= m_cast. mutbl {
9581020 if let ty:: Array ( ety, _) = m_expr. ty . kind ( ) {
@@ -987,7 +1049,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
9871049 & self ,
9881050 fcx : & FnCtxt < ' a , ' tcx > ,
9891051 m_cast : TypeAndMut < ' tcx > ,
990- ) -> Result < CastKind , CastError > {
1052+ ) -> Result < CastKind , CastError < ' tcx > > {
9911053 // ptr-addr cast. pointer must be thin.
9921054 match fcx. pointer_kind ( m_cast. ty , self . span ) ? {
9931055 None => Err ( CastError :: UnknownCastPtrKind ) ,
0 commit comments