11use rustc_middle:: mir:: interpret:: { InterpResult , Pointer } ;
22use rustc_middle:: ty:: layout:: LayoutOf ;
3- use rustc_middle:: ty:: { self , Ty , TyCtxt , VtblEntry } ;
3+ use rustc_middle:: ty:: { self , ExistentialPredicateStableCmpExt , Ty , TyCtxt , VtblEntry } ;
44use rustc_target:: abi:: { Align , Size } ;
55use tracing:: trace;
66
@@ -18,19 +18,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1818 pub fn get_vtable_ptr (
1919 & self ,
2020 ty : Ty < ' tcx > ,
21- poly_trait_ref : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
21+ vtable : & ' tcx ty :: List < ty:: PolyExistentialPredicate < ' tcx > > ,
2222 ) -> InterpResult < ' tcx , Pointer < Option < M :: Provenance > > > {
23- trace ! ( "get_vtable(trait_ref={ :?})" , poly_trait_ref ) ;
23+ trace ! ( "get_vtable(ty={ty :?}, vtable={vtable:?})" ) ;
2424
25- let ( ty, poly_trait_ref ) = self . tcx . erase_regions ( ( ty, poly_trait_ref ) ) ;
25+ let ( ty, vtable ) = self . tcx . erase_regions ( ( ty, vtable ) ) ;
2626
2727 // All vtables must be monomorphic, bail out otherwise.
2828 ensure_monomorphic_enough ( * self . tcx , ty) ?;
29- ensure_monomorphic_enough ( * self . tcx , poly_trait_ref ) ?;
29+ ensure_monomorphic_enough ( * self . tcx , vtable ) ?;
3030
3131 let salt = M :: get_global_alloc_salt ( self , None ) ;
32- let vtable_symbolic_allocation =
33- self . tcx . reserve_and_set_vtable_alloc ( ty, poly_trait_ref, salt) ;
32+ let vtable_symbolic_allocation = self . tcx . reserve_and_set_vtable_alloc ( ty, vtable, salt) ;
3433 let vtable_ptr = self . global_root_pointer ( Pointer :: from ( vtable_symbolic_allocation) ) ?;
3534 Ok ( vtable_ptr. into ( ) )
3635 }
@@ -64,17 +63,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6463 /// expected trait type.
6564 pub ( super ) fn check_vtable_for_type (
6665 & self ,
67- vtable_trait : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
68- expected_trait : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
66+ allocated_vtable : & ' tcx ty :: List < ty:: PolyExistentialPredicate < ' tcx > > ,
67+ expected_vtable : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
6968 ) -> InterpResult < ' tcx > {
70- let eq = match ( expected_trait. principal ( ) , vtable_trait) {
71- ( Some ( a) , Some ( b) ) => self . eq_in_param_env ( a, b) ,
72- ( None , None ) => true ,
73- _ => false ,
74- } ;
75- if !eq {
76- throw_ub ! ( InvalidVTableTrait { expected_trait, vtable_trait } ) ;
69+ let mut sorted_allocated_v: Vec < _ > = allocated_vtable. without_auto_traits ( ) . collect ( ) ;
70+ let mut sorted_expected_v: Vec < _ > = expected_vtable. without_auto_traits ( ) . collect ( ) ;
71+ // `skip_binder` here is okay because `stable_cmp` doesn't look at binders
72+ sorted_allocated_v. sort_by ( |a, b| a. skip_binder ( ) . stable_cmp ( * self . tcx , & b. skip_binder ( ) ) ) ;
73+ sorted_allocated_v. dedup ( ) ;
74+ sorted_expected_v. sort_by ( |a, b| a. skip_binder ( ) . stable_cmp ( * self . tcx , & b. skip_binder ( ) ) ) ;
75+ sorted_expected_v. dedup ( ) ;
76+
77+ if sorted_allocated_v. len ( ) != sorted_expected_v. len ( ) {
78+ throw_ub ! ( InvalidVTableTrait { allocated_vtable, expected_vtable } ) ;
79+ }
80+
81+ for ( a_pred, b_pred) in std:: iter:: zip ( sorted_allocated_v, sorted_expected_v) {
82+ let is_eq = match ( a_pred. skip_binder ( ) , b_pred. skip_binder ( ) ) {
83+ (
84+ ty:: ExistentialPredicate :: Trait ( a_data) ,
85+ ty:: ExistentialPredicate :: Trait ( b_data) ,
86+ ) => self . eq_in_param_env ( a_pred. rebind ( a_data) , b_pred. rebind ( b_data) ) ,
87+
88+ (
89+ ty:: ExistentialPredicate :: Projection ( a_data) ,
90+ ty:: ExistentialPredicate :: Projection ( b_data) ,
91+ ) => self . eq_in_param_env ( a_pred. rebind ( a_data) , b_pred. rebind ( b_data) ) ,
92+
93+ _ => false ,
94+ } ;
95+ if !is_eq {
96+ throw_ub ! ( InvalidVTableTrait { allocated_vtable, expected_vtable } ) ;
97+ }
7798 }
99+
100+ // FIXME: Should we validate auto traits here?
101+
78102 Ok ( ( ) )
79103 }
80104
0 commit comments