@@ -27,6 +27,9 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
27
27
use rustc_span:: symbol:: sym;
28
28
use rustc_span:: { DUMMY_SP , Symbol } ;
29
29
use 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 } ;
30
33
use tracing:: { debug, info} ;
31
34
32
35
use crate :: assert_module_sources:: CguReuse ;
@@ -101,6 +104,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
101
104
bx. sext ( cmp, ret_ty)
102
105
}
103
106
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
+
104
155
/// Retrieves the information we are losing (making dynamic) in an unsizing
105
156
/// adjustment.
106
157
///
@@ -133,12 +184,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
133
184
// between the same trait with different args. If we, for
134
185
// some reason, were to relax the `Unsize` trait, it could become
135
186
// 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) ,
142
189
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
143
190
) ;
144
191
0 commit comments