about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2023-07-19 11:50:40 +0000
committerMaybe Waffle <waffle.lapkin@gmail.com>2023-07-19 12:06:31 +0000
commit1f02c75718706d6180f9b25f55aa50f1b4ce75e1 (patch)
tree26274a01c60443fb7007c55c309dd89e38a92b2c
parentb5d122850821f80f9496abc09840102561ec4267 (diff)
downloadrust-1f02c75718706d6180f9b25f55aa50f1b4ce75e1.tar.gz
rust-1f02c75718706d6180f9b25f55aa50f1b4ce75e1.zip
Don't emit useless vptrs for marker traits
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs25
-rw-r--r--tests/ui/traits/object/print_vtable_sizes.rs5
-rw-r--r--tests/ui/traits/object/print_vtable_sizes.stdout2
-rw-r--r--tests/ui/traits/vtable/multiple-markers.stderr6
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 13ece4ccebb..b4f614e3e22 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<Item = DefId> + '_ {
     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 5656094990b..f510608537a 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 3ba650bc360..ce90c76217b 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": "<UNKNOWN_CRATE>", "trait_name": "D", "entries": "7", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "3", "upcasting_cost_percent": "75" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "E", "entries": "6", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "2", "upcasting_cost_percent": "50" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "G", "entries": "14", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "3", "upcasting_cost_percent": "27.27272727272727" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
+print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
 print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "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 766be12487b..4497c703ae8 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 `<S as A>`: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           TraitVPtr(<S as M1>),
-           TraitVPtr(<S as M2>),
            Method(<S as T>::method),
-           TraitVPtr(<S as T>),
        ]
   --> $DIR/multiple-markers.rs:21:1
    |
@@ -16,9 +13,7 @@ error: vtable entries for `<S as B>`: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           TraitVPtr(<S as M1>),
            Method(<S as T>::method),
-           TraitVPtr(<S as T>),
            TraitVPtr(<S as M2>),
        ]
   --> $DIR/multiple-markers.rs:24:1
@@ -31,7 +26,6 @@ error: vtable entries for `<S as C>`: [
            MetadataSize,
            MetadataAlign,
            Method(<S as T>::method),
-           TraitVPtr(<S as T>),
            TraitVPtr(<S as M1>),
            TraitVPtr(<S as M2>),
        ]