Skip to content

Commit 10257fd

Browse files
More assertions, tests, and miri coverage
1 parent 6427e49 commit 10257fd

12 files changed

+146
-68
lines changed

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
693693
trace!("Virtual call dispatches to {fn_inst:#?}");
694694
// We can also do the lookup based on `def_id` and `dyn_ty`, and check that that
695695
// produces the same result.
696-
if cfg!(debug_assertions) {
696+
{
697697
let tcx = *self.tcx;
698698

699699
let trait_def_id = tcx.trait_of_item(def_id).unwrap();

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -414,35 +414,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
414414

415415
// Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces
416416
// our destination trait.
417-
if cfg!(debug_assertions) {
418-
let vptr_entry_idx =
419-
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
420-
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
421-
if let Some(entry_idx) = vptr_entry_idx {
422-
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
423-
vtable_entries.get(entry_idx)
424-
else {
425-
span_bug!(
426-
self.cur_span(),
427-
"invalid vtable entry index in {} -> {} upcast",
428-
src_pointee_ty,
429-
dest_pointee_ty
430-
);
431-
};
432-
let erased_trait_ref =
433-
ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
434-
assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env(
435-
erased_trait_ref,
436-
self.tcx.instantiate_bound_regions_with_erased(b)
437-
)));
438-
} else {
439-
// In this case codegen would keep using the old vtable. We don't want to do
440-
// that as it has the wrong trait. The reason codegen can do this is that
441-
// one vtable is a prefix of the other, so we double-check that.
442-
let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
443-
assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
417+
let vptr_entry_idx =
418+
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
419+
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
420+
if let Some(entry_idx) = vptr_entry_idx {
421+
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
422+
vtable_entries.get(entry_idx)
423+
else {
424+
span_bug!(
425+
self.cur_span(),
426+
"invalid vtable entry index in {} -> {} upcast",
427+
src_pointee_ty,
428+
dest_pointee_ty
429+
);
444430
};
445-
}
431+
let erased_trait_ref =
432+
ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
433+
assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env(
434+
erased_trait_ref,
435+
self.tcx.instantiate_bound_regions_with_erased(b)
436+
)));
437+
} else {
438+
// In this case codegen would keep using the old vtable. We don't want to do
439+
// that as it has the wrong trait. The reason codegen can do this is that
440+
// one vtable is a prefix of the other, so we double-check that.
441+
let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
442+
assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
443+
};
446444

447445
// Get the destination trait vtable and return that.
448446
let new_vptr = self.get_vtable_ptr(ty, data_b)?;

compiler/rustc_trait_selection/src/traits/vtable.rs

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::fmt::Debug;
22
use std::ops::ControlFlow;
33

44
use rustc_hir::def_id::DefId;
5-
use rustc_infer::infer::TyCtxtInferExt;
6-
use rustc_infer::traits::ObligationCause;
75
use rustc_infer::traits::util::PredicateSet;
86
use rustc_middle::bug;
97
use rustc_middle::query::Providers;
@@ -14,7 +12,7 @@ use rustc_span::DUMMY_SP;
1412
use smallvec::{SmallVec, smallvec};
1513
use tracing::debug;
1614

17-
use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
15+
use crate::traits::{impossible_predicates, is_vtable_safe_method};
1816

1917
#[derive(Clone, Debug)]
2018
pub enum VtblSegment<'tcx> {
@@ -230,6 +228,11 @@ fn vtable_entries<'tcx>(
230228
trait_ref: ty::TraitRef<'tcx>,
231229
) -> &'tcx [VtblEntry<'tcx>] {
232230
debug_assert!(!trait_ref.has_non_region_infer() && !trait_ref.has_non_region_param());
231+
debug_assert_eq!(
232+
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref),
233+
trait_ref,
234+
"vtable trait ref should be normalized"
235+
);
233236

234237
debug!("vtable_entries({:?})", trait_ref);
235238

@@ -307,6 +310,11 @@ fn vtable_entries<'tcx>(
307310
// for `Supertrait`'s methods in the vtable of `Subtrait`.
308311
pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize {
309312
debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
313+
debug_assert_eq!(
314+
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key),
315+
key,
316+
"vtable trait ref should be normalized"
317+
);
310318

311319
let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
312320
bug!();
@@ -325,11 +333,9 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
325333
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
326334
}
327335
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
328-
if trait_refs_are_compatible(
329-
tcx,
330-
ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal),
331-
target_principal,
332-
) {
336+
if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal)
337+
== target_principal
338+
{
333339
return ControlFlow::Break(vptr_offset);
334340
}
335341

@@ -360,6 +366,12 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
360366
),
361367
) -> Option<usize> {
362368
debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
369+
debug_assert_eq!(
370+
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key),
371+
key,
372+
"upcasting trait refs should be normalized"
373+
);
374+
363375
let (source, target) = key;
364376

365377
// If the target principal is `None`, we can just return `None`.
@@ -386,11 +398,9 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
386398
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
387399
vptr_offset +=
388400
tcx.own_existential_vtable_entries(vtable_principal.def_id).len();
389-
if trait_refs_are_compatible(
390-
tcx,
391-
ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal),
392-
target_principal,
393-
) {
401+
if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal)
402+
== target_principal
403+
{
394404
if emit_vptr {
395405
return ControlFlow::Break(Some(vptr_offset));
396406
} else {
@@ -410,27 +420,6 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
410420
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
411421
}
412422

413-
fn trait_refs_are_compatible<'tcx>(
414-
tcx: TyCtxt<'tcx>,
415-
vtable_principal: ty::ExistentialTraitRef<'tcx>,
416-
target_principal: ty::ExistentialTraitRef<'tcx>,
417-
) -> bool {
418-
if vtable_principal.def_id != target_principal.def_id {
419-
return false;
420-
}
421-
422-
let (infcx, param_env) =
423-
tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
424-
let ocx = ObligationCtxt::new(&infcx);
425-
let source_principal = ocx.normalize(&ObligationCause::dummy(), param_env, vtable_principal);
426-
let target_principal = ocx.normalize(&ObligationCause::dummy(), param_env, target_principal);
427-
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target_principal, source_principal)
428-
else {
429-
return false;
430-
};
431-
ocx.select_all_or_error().is_empty()
432-
}
433-
434423
pub(super) fn provide(providers: &mut Providers) {
435424
*providers = Providers {
436425
own_existential_vtable_entries,

src/tools/miri/tests/pass/dyn-upcast.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ fn main() {
1010
replace_vptr();
1111
vtable_nop_cast();
1212
drop_principal();
13+
modulo_binder();
14+
modulo_assoc();
1315
}
1416

1517
fn vtable_nop_cast() {
@@ -482,3 +484,53 @@ fn drop_principal() {
482484
println!("before");
483485
drop(y);
484486
}
487+
488+
// Test for <https://github.com/rust-lang/rust/issues/135316>.
489+
fn modulo_binder() {
490+
trait Supertrait<T> {
491+
fn _print_numbers(&self, mem: &[usize; 100]) {
492+
println!("{mem:?}");
493+
}
494+
}
495+
impl<T> Supertrait<T> for () {}
496+
497+
trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
498+
fn say_hello(&self, _: &usize) {
499+
println!("Hello!");
500+
}
501+
}
502+
impl<T, U> Trait<T, U> for () {}
503+
504+
(&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
505+
as &'static dyn Trait<&'static (), &'static ()>)
506+
.say_hello(&0);
507+
}
508+
509+
// Test for <https://github.com/rust-lang/rust/issues/135315>.
510+
fn modulo_assoc() {
511+
trait Supertrait<T> {
512+
fn _print_numbers(&self, mem: &[usize; 100]) {
513+
println!("{mem:?}");
514+
}
515+
}
516+
impl<T> Supertrait<T> for () {}
517+
518+
trait Identity {
519+
type Selff;
520+
}
521+
impl<Selff> Identity for Selff {
522+
type Selff = Selff;
523+
}
524+
525+
trait Middle<T>: Supertrait<()> + Supertrait<T> {
526+
fn say_hello(&self, _: &usize) {
527+
println!("Hello!");
528+
}
529+
}
530+
impl<T> Middle<T> for () {}
531+
532+
trait Trait: Middle<<() as Identity>::Selff> {}
533+
impl Trait for () {}
534+
535+
(&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
536+
}

src/tools/miri/tests/pass/dyn-upcast.stdout

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ before
22
goodbye
33
before
44
goodbye
5+
Hello!
6+
Hello!

tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#![feature(rustc_attrs)]
22

3+
// Test for <https://github.com/rust-lang/rust/issues/135316>.
4+
35
trait Supertrait<T> {
46
fn _print_numbers(&self, mem: &[usize; 100]) {
57
}

tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ error: vtable entries: [
55
Method(<dyn for<'a> Trait<&(), &'a ()> as Supertrait<&()>>::_print_numbers - shim(reify)),
66
Method(<dyn for<'a> Trait<&(), &'a ()> as Trait<&(), &()>>::say_hello - shim(reify)),
77
]
8-
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:18:1
8+
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:20:1
99
|
1010
LL | type First = dyn for<'a> Trait<&'static (), &'a ()>;
1111
| ^^^^^^^^^^
@@ -17,7 +17,7 @@ error: vtable entries: [
1717
Method(<dyn Trait<&(), &()> as Supertrait<&()>>::_print_numbers - shim(reify)),
1818
Method(<dyn Trait<&(), &()> as Trait<&(), &()>>::say_hello - shim(reify)),
1919
]
20-
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:22:1
20+
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:24:1
2121
|
2222
LL | type Second = dyn Trait<&'static (), &'static ()>;
2323
| ^^^^^^^^^^^

tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//@ run-pass
22
//@ check-run-results
33

4+
// Test for <https://github.com/rust-lang/rust/issues/135316>.
5+
46
#![feature(trait_upcasting)]
57

68
trait Supertrait<T> {

tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#![feature(rustc_attrs)]
2-
32
#![feature(trait_upcasting)]
43

4+
// Test for <https://github.com/rust-lang/rust/issues/135315>.
5+
56
trait Supertrait<T> {
67
fn _print_numbers(&self, mem: &[usize; 100]) {
78
println!("{mem:?}");

tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ error: vtable entries: [
55
Method(<() as Supertrait<()>>::_print_numbers),
66
Method(<() as Middle<()>>::say_hello),
77
]
8-
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:29:1
8+
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:30:1
99
|
1010
LL | impl Trait for () {}
1111
| ^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ error: vtable entries: [
1717
Method(<dyn Middle<()> as Supertrait<()>>::_print_numbers - shim(reify)),
1818
Method(<dyn Middle<()> as Middle<()>>::say_hello - shim(reify)),
1919
]
20-
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:33:1
20+
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:34:1
2121
|
2222
LL | type Virtual = dyn Middle<()>;
2323
| ^^^^^^^^^^^^

0 commit comments

Comments
 (0)