Skip to content

Commit

Permalink
Normalize vtable entries before walking and deduplicating them
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jan 10, 2025
1 parent ed4c92f commit 04fb1f2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 29 deletions.
53 changes: 29 additions & 24 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,37 +1026,42 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
// Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3.
// However, since we don't know `T`, we can't know if `T: Copy` holds or not,
// thus we lean on the bigger side and say it has 4 entries.
traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| {
match segment {
traits::vtable::VtblSegment::MetadataDSA => {
// If this is the first dsa, it would be included either way,
// otherwise it's needed for upcasting
if std::mem::take(&mut first_dsa) {
entries_ignoring_upcasting += 3;
} else {
entries_for_upcasting += 3;
traits::vtable::prepare_vtable_segments(
tcx,
trait_ref,
ty::TypingEnv::post_analysis(tcx, tr),
|segment| {
match segment {
traits::vtable::VtblSegment::MetadataDSA => {
// If this is the first dsa, it would be included either way,
// otherwise it's needed for upcasting
if std::mem::take(&mut first_dsa) {
entries_ignoring_upcasting += 3;
} else {
entries_for_upcasting += 3;
}
}
}

traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
// Lookup the shape of vtable for the trait.
let own_existential_entries =
tcx.own_existential_vtable_entries(trait_ref.def_id);
traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
// Lookup the shape of vtable for the trait.
let own_existential_entries =
tcx.own_existential_vtable_entries(trait_ref.def_id);

// The original code here ignores the method if its predicates are
// impossible. We can't really do that as, for example, all not trivial
// bounds on generic parameters are impossible (since we don't know the
// parameters...), see the comment above.
entries_ignoring_upcasting += own_existential_entries.len();
// The original code here ignores the method if its predicates are
// impossible. We can't really do that as, for example, all not trivial
// bounds on generic parameters are impossible (since we don't know the
// parameters...), see the comment above.
entries_ignoring_upcasting += own_existential_entries.len();

if emit_vptr {
entries_for_upcasting += 1;
if emit_vptr {
entries_for_upcasting += 1;
}
}
}
}

std::ops::ControlFlow::Continue::<std::convert::Infallible>(())
});
std::ops::ControlFlow::Continue::<std::convert::Infallible>(())
},
);

sess.code_stats.record_vtable_size(tr, &name, VTableSizeInfo {
trait_name: name.clone(),
Expand Down
30 changes: 25 additions & 5 deletions compiler/rustc_trait_selection/src/traits/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ pub enum VtblSegment<'tcx> {
pub fn prepare_vtable_segments<'tcx, T>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
) -> Option<T> {
prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value()
prepare_vtable_segments_inner(tcx, trait_ref, typing_env, segment_visitor).break_value()
}

/// Helper for [`prepare_vtable_segments`] that returns `ControlFlow`,
/// such that we can use `?` in the body.
fn prepare_vtable_segments_inner<'tcx, T>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
) -> ControlFlow<T> {
// The following constraints holds for the final arrangement.
Expand Down Expand Up @@ -129,7 +131,8 @@ fn prepare_vtable_segments_inner<'tcx, T>(
.iter_identity_copied()
.filter_map(move |(pred, _)| {
Some(
tcx.instantiate_bound_regions_with_erased(
tcx.normalize_erasing_late_bound_regions(
typing_env,
pred.instantiate_supertrait(
tcx,
ty::Binder::dummy(inner_most_trait_ref),
Expand Down Expand Up @@ -306,7 +309,12 @@ fn vtable_entries<'tcx>(
ControlFlow::Continue(())
};

let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
let _ = prepare_vtable_segments(
tcx,
trait_ref,
ty::TypingEnv::fully_monomorphized(),
vtable_segment_callback,
);

if tcx.has_attr(trait_ref.def_id, sym::rustc_dump_vtable) {
let sp = tcx.def_span(trait_ref.def_id);
Expand Down Expand Up @@ -358,7 +366,13 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
}
};

prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
prepare_vtable_segments(
tcx,
source_principal,
ty::TypingEnv::fully_monomorphized(),
vtable_segment_callback,
)
.unwrap()
}

/// Given a `dyn Subtrait` and `dyn Supertrait` trait object, find the slot of
Expand Down Expand Up @@ -420,7 +434,13 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
}
};

prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
prepare_vtable_segments(
tcx,
source_principal,
ty::TypingEnv::fully_monomorphized(),
vtable_segment_callback,
)
.unwrap()
}

fn trait_refs_are_compatible<'tcx>(
Expand Down

0 comments on commit 04fb1f2

Please sign in to comment.