@@ -42,7 +42,7 @@ use rustc_middle::ty::cast::{CastKind, CastTy};
4242use rustc_middle:: ty:: error:: TypeError ;
4343use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeVisitableExt , VariantDef } ;
4444use rustc_session:: lint;
45- use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
45+ use rustc_span:: def_id:: LOCAL_CRATE ;
4646use rustc_span:: symbol:: sym;
4747use rustc_span:: Span ;
4848use rustc_trait_selection:: infer:: InferCtxtExt ;
@@ -72,7 +72,7 @@ enum PointerKind<'tcx> {
7272 /// No metadata attached, ie pointer to sized type or foreign type
7373 Thin ,
7474 /// A trait object
75- VTable ( Option < DefId > ) ,
75+ VTable ( Option < ty :: Binder < ' tcx , ty :: ExistentialTraitRef < ' tcx > > > ) ,
7676 /// Slice
7777 Length ,
7878 /// The unsize info of this projection or opaque type
@@ -100,7 +100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
100100
101101 Ok ( match * t. kind ( ) {
102102 ty:: Slice ( _) | ty:: Str => Some ( PointerKind :: Length ) ,
103- ty:: Dynamic ( tty, _, ty:: Dyn ) => Some ( PointerKind :: VTable ( tty. principal_def_id ( ) ) ) ,
103+ ty:: Dynamic ( tty, _, ty:: Dyn ) => Some ( PointerKind :: VTable ( tty. principal ( ) ) ) ,
104104 ty:: Adt ( def, args) if def. is_struct ( ) => match def. non_enum_variant ( ) . tail_opt ( ) {
105105 None => Some ( PointerKind :: Thin ) ,
106106 Some ( f) => {
@@ -611,14 +611,39 @@ impl<'a, 'tcx> CastCheck<'tcx> {
611611 } else {
612612 match self . try_coercion_cast ( fcx) {
613613 Ok ( ( ) ) => {
614- if self . expr_ty . is_unsafe_ptr ( ) && self . cast_ty . is_unsafe_ptr ( ) {
615- // When casting a raw pointer to another raw pointer, we cannot convert the cast into
616- // a coercion because the pointee types might only differ in regions, which HIR typeck
617- // cannot distinguish. This would cause us to erroneously discard a cast which will
618- // lead to a borrowck error like #113257.
619- // We still did a coercion above to unify inference variables for `ptr as _` casts.
620- // This does cause us to miss some trivial casts in the trival cast lint.
621- debug ! ( " -> PointerCast" ) ;
614+ if let ty:: RawPtr ( src_pointee) = self . expr_ty . kind ( )
615+ && let ty:: RawPtr ( tgt_pointee) = self . cast_ty . kind ( )
616+ {
617+ if let Ok ( Some ( src_kind) ) = fcx. pointer_kind ( src_pointee. ty , self . expr_span )
618+ && let Ok ( Some ( tgt_kind) ) =
619+ fcx. pointer_kind ( tgt_pointee. ty , self . cast_span )
620+ {
621+ match ( src_kind, tgt_kind) {
622+ // When casting a raw pointer to another raw pointer, we cannot convert the cast into
623+ // a coercion because the pointee types might only differ in regions, which HIR typeck
624+ // cannot distinguish. This would cause us to erroneously discard a cast which will
625+ // lead to a borrowck error like #113257.
626+ // We still did a coercion above to unify inference variables for `ptr as _` casts.
627+ // This does cause us to miss some trivial casts in the trivial cast lint.
628+ ( PointerKind :: Thin , PointerKind :: Thin )
629+ | ( PointerKind :: Length , PointerKind :: Length ) => {
630+ debug ! ( " -> PointerCast" ) ;
631+ }
632+
633+ // If we are not casting pointers to sized types or slice-ish DSTs
634+ // (handled above), we need to make a coercion cast. This prevents
635+ // casts like `*const dyn Trait<'a> -> *const dyn Trait<'b>` which
636+ // are unsound.
637+ //
638+ // See <https://github.com/rust-lang/rust/issues/120217>
639+ ( _, _) => {
640+ debug ! ( " -> CoercionCast" ) ;
641+ fcx. typeck_results
642+ . borrow_mut ( )
643+ . set_coercion_cast ( self . expr . hir_id . local_id ) ;
644+ }
645+ }
646+ }
622647 } else {
623648 self . trivial_cast_lint ( fcx) ;
624649 debug ! ( " -> CoercionCast" ) ;
0 commit comments