@@ -41,8 +41,8 @@ use rustc_abi::ExternAbi;
4141use rustc_attr_parsing:: InlineAttr ;
4242use rustc_errors:: codes:: * ;
4343use rustc_errors:: { Applicability , Diag , struct_span_code_err} ;
44- use rustc_hir as hir;
4544use rustc_hir:: def_id:: { DefId , LocalDefId } ;
45+ use rustc_hir:: { self as hir, LangItem } ;
4646use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
4747use rustc_infer:: infer:: relate:: RelateResult ;
4848use rustc_infer:: infer:: { Coercion , DefineOpaqueTypes , InferOk , InferResult } ;
@@ -58,7 +58,7 @@ use rustc_middle::ty::adjustment::{
5858} ;
5959use rustc_middle:: ty:: error:: TypeError ;
6060use rustc_middle:: ty:: visit:: TypeVisitableExt ;
61- use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
61+ use rustc_middle:: ty:: { self , AliasTy , GenericArgsRef , Ty , TyCtxt } ;
6262use rustc_session:: parse:: feature_err;
6363use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Span , sym} ;
6464use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -590,6 +590,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
590590
591591 // Create an obligation for `Source: CoerceUnsized<Target>`.
592592 let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
593+ let root_obligation = Obligation :: new (
594+ self . tcx ,
595+ cause. clone ( ) ,
596+ self . fcx . param_env ,
597+ ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ,
598+ ) ;
599+
600+ // If the root `Source: CoerceUnsized<Target>` obligation can't possibly hold,
601+ // we don't have to assume that this is unsizing coercion (it will always lead to an error)
602+ //
603+ // However, we don't want to bail early all the time, since the unholdable obligations
604+ // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id<This = U>`),
605+ // so we only bail if there (likely) is another way to convert the types.
606+ if !self . infcx . predicate_may_hold ( & root_obligation) {
607+ if let Some ( dyn_metadata_adt_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: DynMetadata )
608+ && let Some ( metadata_type_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: Metadata )
609+ {
610+ self . probe ( |_| {
611+ let ocx = ObligationCtxt :: new ( & self . infcx ) ;
612+
613+ // returns `true` if `<ty as Pointee>::Metadata` is `DynMetadata<_>`
614+ let has_dyn_trait_metadata = |ty| {
615+ let metadata_ty: Result < _ , _ > = ocx. structurally_normalize_ty (
616+ & ObligationCause :: dummy ( ) ,
617+ self . fcx . param_env ,
618+ Ty :: new_alias (
619+ self . tcx ,
620+ ty:: AliasTyKind :: Projection ,
621+ AliasTy :: new ( self . tcx , metadata_type_def_id, [ ty] ) ,
622+ ) ,
623+ ) ;
624+
625+ metadata_ty. is_ok_and ( |metadata_ty| {
626+ metadata_ty
627+ . ty_adt_def ( )
628+ . is_some_and ( |d| d. did ( ) == dyn_metadata_adt_def_id)
629+ } )
630+ } ;
631+
632+ // If both types are raw pointers to a (wrapper over a) trait object,
633+ // this might be a cast like `*const W<dyn Trait> -> *const dyn Trait`.
634+ // So it's better to bail and try that. (even if the cast is not possible, for
635+ // example due to vtables not matching, cast diagnostic will likely still be better)
636+ //
637+ // N.B. use `target`, not `coerce_target` (the latter is a var)
638+ if let & ty:: RawPtr ( source_pointee, _) = coerce_source. kind ( )
639+ && let & ty:: RawPtr ( target_pointee, _) = target. kind ( )
640+ && has_dyn_trait_metadata ( source_pointee)
641+ && has_dyn_trait_metadata ( target_pointee)
642+ {
643+ return Err ( TypeError :: Mismatch ) ;
644+ }
645+
646+ Ok ( ( ) )
647+ } ) ?;
648+ }
649+ }
593650
594651 // Use a FIFO queue for this custom fulfillment procedure.
595652 //
@@ -598,12 +655,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
598655 // and almost never more than 3. By using a SmallVec we avoid an
599656 // allocation, at the (very small) cost of (occasionally) having to
600657 // shift subsequent elements down when removing the front element.
601- let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ Obligation :: new(
602- self . tcx,
603- cause,
604- self . fcx. param_env,
605- ty:: TraitRef :: new( self . tcx, coerce_unsized_did, [ coerce_source, coerce_target] )
606- ) ] ;
658+ let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ root_obligation] ;
607659
608660 let mut has_unsized_tuple_coercion = false ;
609661 let mut has_trait_upcasting_coercion = None ;
0 commit comments