@@ -32,10 +32,10 @@ use super::FnCtxt;
3232
3333use crate :: errors;
3434use crate :: type_error_struct;
35- use hir:: ExprKind ;
35+ use hir:: { ExprKind , LangItem } ;
3636use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
3737use rustc_hir as hir;
38- use rustc_macros :: { TypeFoldable , TypeVisitable } ;
38+ use rustc_infer :: traits :: Obligation ;
3939use rustc_middle:: mir:: Mutability ;
4040use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
4141use rustc_middle:: ty:: cast:: { CastKind , CastTy } ;
@@ -45,7 +45,8 @@ use rustc_session::lint;
4545use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
4646use rustc_span:: symbol:: sym;
4747use rustc_span:: Span ;
48- use rustc_trait_selection:: infer:: InferCtxtExt ;
48+ use rustc_trait_selection:: infer:: InferCtxtExt as _;
49+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
4950
5051/// Reifies a cast check to be checked once we have full type information for
5152/// a function context.
@@ -67,7 +68,7 @@ pub struct CastCheck<'tcx> {
6768/// The kind of pointer and associated metadata (thin, length or vtable) - we
6869/// only allow casts between fat pointers if their metadata have the same
6970/// kind.
70- #[ derive( Debug , Copy , Clone , PartialEq , Eq , TypeVisitable , TypeFoldable ) ]
71+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
7172enum PointerKind < ' tcx > {
7273 /// No metadata attached, ie pointer to sized type or foreign type
7374 Thin ,
@@ -787,33 +788,40 @@ impl<'a, 'tcx> CastCheck<'tcx> {
787788 ) -> Result < ( ) , CastError > {
788789 debug ! ( ?expr, ?cast, "check_ptr_ptr_cast" ) ;
789790
790- let expr_kind = fcx. pointer_kind ( expr, self . span ) ?;
791- let cast_kind = fcx. pointer_kind ( cast, self . span ) ?;
791+ let meta_did = fcx. tcx . require_lang_item ( LangItem :: Metadata , Some ( self . span ) ) ;
792+ let expr_meta = Ty :: new_projection ( fcx. tcx , meta_did, [ expr] ) ;
793+ let cast_meta = Ty :: new_projection ( fcx. tcx , meta_did, [ cast] ) ;
794+ let expr_meta = fcx. normalize ( self . span , expr_meta) ;
795+ let cast_meta = fcx. normalize ( self . span , cast_meta) ;
792796
793- let Some ( cast_kind) = cast_kind else {
794- // We can't cast if target pointer kind is unknown
795- return Err ( CastError :: UnknownCastPtrKind ) ;
796- } ;
797+ let pred = ty:: TraitRef :: from_lang_item (
798+ fcx. tcx ,
799+ LangItem :: MetadataCast ,
800+ self . span ,
801+ [ expr_meta, cast_meta] ,
802+ ) ;
797803
798- // Cast to thin pointer is OK
799- if cast_kind == PointerKind :: Thin {
804+ let obligation = Obligation :: new ( fcx . tcx , fcx . misc ( self . span ) , fcx . param_env , pred ) ;
805+ if fcx . predicate_must_hold_modulo_regions ( & obligation ) {
800806 return Ok ( ( ) ) ;
801807 }
802808
803- let Some ( expr_kind) = expr_kind else {
804- // We can't cast to fat pointer if source pointer kind is unknown
805- return Err ( CastError :: UnknownExprPtrKind ) ;
806- } ;
807-
808- // thin -> fat? report invalid cast (don't complain about vtable kinds)
809- if expr_kind == PointerKind :: Thin {
810- return Err ( CastError :: SizedUnsizedCast ) ;
811- }
809+ expr_meta. error_reported ( ) ?;
810+ cast_meta. error_reported ( ) ?;
812811
813- // vtable kinds must match
814- if fcx. tcx . erase_regions ( cast_kind) == fcx. tcx . erase_regions ( expr_kind) {
815- Ok ( ( ) )
812+ if cast_meta == fcx. tcx . types . unit {
813+ span_bug ! ( self . span, "cast to thin pointer, but predicate didn't hold: {pred}" ) ;
814+ } else if cast_meta. has_infer_types ( ) {
815+ // We can't cast if target pointer kind is unknown
816+ Err ( CastError :: UnknownCastPtrKind )
817+ } else if expr_meta. has_infer_types ( ) {
818+ // We can't cast to fat pointer if source pointer kind is unknown
819+ Err ( CastError :: UnknownExprPtrKind )
820+ } else if expr_meta == fcx. tcx . types . unit {
821+ // thin -> fat? report invalid cast (don't complain about metadata kinds)
822+ Err ( CastError :: SizedUnsizedCast )
816823 } else {
824+ // metadata kinds must match
817825 Err ( CastError :: DifferingKinds )
818826 }
819827 }
0 commit comments