@@ -27,6 +27,9 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
2727use rustc_span:: symbol:: sym;
2828use rustc_span:: { DUMMY_SP , Symbol } ;
2929use rustc_target:: abi:: FIRST_VARIANT ;
30+ use rustc_trait_selection:: infer:: at:: ToTrace ;
31+ use rustc_trait_selection:: infer:: { BoundRegionConversionTime , TyCtxtInferExt } ;
32+ use rustc_trait_selection:: traits:: { ObligationCause , ObligationCtxt } ;
3033use tracing:: { debug, info} ;
3134
3235use crate :: assert_module_sources:: CguReuse ;
@@ -101,6 +104,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
101104 bx. sext ( cmp, ret_ty)
102105}
103106
107+ /// Codegen takes advantage of the additional assumption, where if the
108+ /// principal trait def id of what's being casted doesn't change,
109+ /// then we don't need to adjust the vtable at all. This
110+ /// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
111+ /// requires that `A = B`; we don't allow *upcasting* objects
112+ /// between the same trait with different args. If we, for
113+ /// some reason, were to relax the `Unsize` trait, it could become
114+ /// unsound, so let's validate here that the trait refs are subtypes.
115+ pub fn validate_trivial_unsize < ' tcx > (
116+ tcx : TyCtxt < ' tcx > ,
117+ source_data : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
118+ target_data : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
119+ ) -> bool {
120+ match ( source_data. principal ( ) , target_data. principal ( ) ) {
121+ ( Some ( hr_source_principal) , Some ( hr_target_principal) ) => {
122+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
123+ let universe = infcx. universe ( ) ;
124+ let ocx = ObligationCtxt :: new ( & infcx) ;
125+ infcx. enter_forall ( hr_target_principal, |target_principal| {
126+ let source_principal = infcx. instantiate_binder_with_fresh_vars (
127+ DUMMY_SP ,
128+ BoundRegionConversionTime :: HigherRankedType ,
129+ hr_source_principal,
130+ ) ;
131+ let Ok ( ( ) ) = ocx. eq_trace (
132+ & ObligationCause :: dummy ( ) ,
133+ ty:: ParamEnv :: reveal_all ( ) ,
134+ ToTrace :: to_trace (
135+ & ObligationCause :: dummy ( ) ,
136+ hr_target_principal,
137+ hr_source_principal,
138+ ) ,
139+ target_principal,
140+ source_principal,
141+ ) else {
142+ return false ;
143+ } ;
144+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
145+ return false ;
146+ }
147+ infcx. leak_check ( universe, None ) . is_ok ( )
148+ } )
149+ }
150+ ( None , None ) => true ,
151+ _ => false ,
152+ }
153+ }
154+
104155/// Retrieves the information we are losing (making dynamic) in an unsizing
105156/// adjustment.
106157///
@@ -133,12 +184,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
133184 // between the same trait with different args. If we, for
134185 // some reason, were to relax the `Unsize` trait, it could become
135186 // unsound, so let's assert here that the trait refs are *equal*.
136- //
137- // We can use `assert_eq` because the binders should have been anonymized,
138- // and because higher-ranked equality now requires the binders are equal.
139- debug_assert_eq ! (
140- data_a. principal( ) ,
141- data_b. principal( ) ,
187+ debug_assert ! (
188+ validate_trivial_unsize( cx. tcx( ) , data_a, data_b) ,
142189 "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
143190 ) ;
144191
0 commit comments