@@ -32,10 +32,10 @@ use super::FnCtxt;
32
32
33
33
use crate :: errors;
34
34
use crate :: type_error_struct;
35
- use hir:: ExprKind ;
35
+ use hir:: { ExprKind , LangItem } ;
36
36
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
37
37
use rustc_hir as hir;
38
- use rustc_macros :: { TypeFoldable , TypeVisitable } ;
38
+ use rustc_infer :: traits :: Obligation ;
39
39
use rustc_middle:: mir:: Mutability ;
40
40
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
41
41
use rustc_middle:: ty:: cast:: { CastKind , CastTy } ;
@@ -45,7 +45,8 @@ use rustc_session::lint;
45
45
use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
46
46
use rustc_span:: symbol:: sym;
47
47
use 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 _;
49
50
50
51
/// Reifies a cast check to be checked once we have full type information for
51
52
/// a function context.
@@ -67,7 +68,7 @@ pub struct CastCheck<'tcx> {
67
68
/// The kind of pointer and associated metadata (thin, length or vtable) - we
68
69
/// only allow casts between fat pointers if their metadata have the same
69
70
/// kind.
70
- #[ derive( Debug , Copy , Clone , PartialEq , Eq , TypeVisitable , TypeFoldable ) ]
71
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
71
72
enum PointerKind < ' tcx > {
72
73
/// No metadata attached, ie pointer to sized type or foreign type
73
74
Thin ,
@@ -787,33 +788,40 @@ impl<'a, 'tcx> CastCheck<'tcx> {
787
788
) -> Result < ( ) , CastError > {
788
789
debug ! ( ?expr, ?cast, "check_ptr_ptr_cast" ) ;
789
790
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) ;
792
796
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
+ ) ;
797
803
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 ) {
800
806
return Ok ( ( ) ) ;
801
807
}
802
808
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 ( ) ?;
812
811
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 )
816
823
} else {
824
+ // metadata kinds must match
817
825
Err ( CastError :: DifferingKinds )
818
826
}
819
827
}
0 commit comments