From 1f02c75718706d6180f9b25f55aa50f1b4ce75e1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 11:50:40 +0000 Subject: [PATCH] Don't emit useless vptrs for marker traits --- .../src/traits/vtable.rs | 25 ++++++++++++++++--- tests/ui/traits/object/print_vtable_sizes.rs | 5 ++-- .../traits/object/print_vtable_sizes.stdout | 2 +- .../ui/traits/vtable/multiple-markers.stderr | 6 ----- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 13ece4ccebb21..b4f614e3e2202 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -147,9 +147,6 @@ fn prepare_vtable_segments_inner<'tcx, T>( } } - // Other than the left-most path, vptr should be emitted for each trait. - emit_vptr_on_new_entry = true; - // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { segment_visitor(VtblSegment::TraitOwnEntries { @@ -157,6 +154,14 @@ fn prepare_vtable_segments_inner<'tcx, T>( emit_vptr, })?; + // If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable, + // we'll need to emit vptrs from now on. + if !emit_vptr_on_new_entry + && has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id()) + { + emit_vptr_on_new_entry = true; + } + if let Some(next_inner_most_trait_ref) = siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx))) { @@ -196,11 +201,23 @@ fn dump_vtable_entries<'tcx>( }); } +fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some() +} + fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[DefId] { + tcx.arena.alloc_from_iter(own_existential_vtable_entries_iter(tcx, trait_def_id)) +} + +fn own_existential_vtable_entries_iter( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> impl Iterator + '_ { let trait_methods = tcx .associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Fn); + // Now list each method's DefId (for within its trait). let own_entries = trait_methods.filter_map(move |&trait_method| { debug!("own_existential_vtable_entry: trait_method={:?}", trait_method); @@ -215,7 +232,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def Some(def_id) }); - tcx.arena.alloc_from_iter(own_entries.into_iter()) + own_entries } /// Given a trait `trait_ref`, iterates the vtable entries diff --git a/tests/ui/traits/object/print_vtable_sizes.rs b/tests/ui/traits/object/print_vtable_sizes.rs index 5656094990be6..f510608537abb 100644 --- a/tests/ui/traits/object/print_vtable_sizes.rs +++ b/tests/ui/traits/object/print_vtable_sizes.rs @@ -10,8 +10,9 @@ trait C { fn x() {} // not object safe, shouldn't be reported } -// This ideally should not have any upcasting cost, -// but currently does due to a bug +// This does not have any upcasting cost, +// because both `Send` and `Sync` are traits +// with no methods trait D: Send + Sync + help::MarkerWithSuper {} // This can't have no cost without reordering, diff --git a/tests/ui/traits/object/print_vtable_sizes.stdout b/tests/ui/traits/object/print_vtable_sizes.stdout index 3ba650bc36045..ce90c76217b95 100644 --- a/tests/ui/traits/object/print_vtable_sizes.stdout +++ b/tests/ui/traits/object/print_vtable_sizes.stdout @@ -1,8 +1,8 @@ -print-vtable-sizes { "crate_name": "", "trait_name": "D", "entries": "7", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "3", "upcasting_cost_percent": "75" } print-vtable-sizes { "crate_name": "", "trait_name": "E", "entries": "6", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "2", "upcasting_cost_percent": "50" } print-vtable-sizes { "crate_name": "", "trait_name": "G", "entries": "14", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "3", "upcasting_cost_percent": "27.27272727272727" } print-vtable-sizes { "crate_name": "", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" } print-vtable-sizes { "crate_name": "", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } +print-vtable-sizes { "crate_name": "", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } print-vtable-sizes { "crate_name": "", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } print-vtable-sizes { "crate_name": "", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } print-vtable-sizes { "crate_name": "", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } diff --git a/tests/ui/traits/vtable/multiple-markers.stderr b/tests/ui/traits/vtable/multiple-markers.stderr index 766be12487b9e..4497c703ae8a1 100644 --- a/tests/ui/traits/vtable/multiple-markers.stderr +++ b/tests/ui/traits/vtable/multiple-markers.stderr @@ -2,10 +2,7 @@ error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - TraitVPtr(), - TraitVPtr(), Method(::method), - TraitVPtr(), ] --> $DIR/multiple-markers.rs:21:1 | @@ -16,9 +13,7 @@ error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - TraitVPtr(), Method(::method), - TraitVPtr(), TraitVPtr(), ] --> $DIR/multiple-markers.rs:24:1 @@ -31,7 +26,6 @@ error: vtable entries for ``: [ MetadataSize, MetadataAlign, Method(::method), - TraitVPtr(), TraitVPtr(), TraitVPtr(), ]