Skip to content

Commit 1f02c75

Browse files
committed
Don't emit useless vptrs for marker traits
1 parent b5d1228 commit 1f02c75

File tree

4 files changed

+25
-13
lines changed

4 files changed

+25
-13
lines changed

compiler/rustc_trait_selection/src/traits/vtable.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,21 @@ fn prepare_vtable_segments_inner<'tcx, T>(
147147
}
148148
}
149149

150-
// Other than the left-most path, vptr should be emitted for each trait.
151-
emit_vptr_on_new_entry = true;
152-
153150
// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
154151
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
155152
segment_visitor(VtblSegment::TraitOwnEntries {
156153
trait_ref: inner_most_trait_ref,
157154
emit_vptr,
158155
})?;
159156

157+
// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,
158+
// we'll need to emit vptrs from now on.
159+
if !emit_vptr_on_new_entry
160+
&& has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id())
161+
{
162+
emit_vptr_on_new_entry = true;
163+
}
164+
160165
if let Some(next_inner_most_trait_ref) =
161166
siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx)))
162167
{
@@ -196,11 +201,23 @@ fn dump_vtable_entries<'tcx>(
196201
});
197202
}
198203

204+
fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
205+
own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some()
206+
}
207+
199208
fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[DefId] {
209+
tcx.arena.alloc_from_iter(own_existential_vtable_entries_iter(tcx, trait_def_id))
210+
}
211+
212+
fn own_existential_vtable_entries_iter(
213+
tcx: TyCtxt<'_>,
214+
trait_def_id: DefId,
215+
) -> impl Iterator<Item = DefId> + '_ {
200216
let trait_methods = tcx
201217
.associated_items(trait_def_id)
202218
.in_definition_order()
203219
.filter(|item| item.kind == ty::AssocKind::Fn);
220+
204221
// Now list each method's DefId (for within its trait).
205222
let own_entries = trait_methods.filter_map(move |&trait_method| {
206223
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
215232
Some(def_id)
216233
});
217234

218-
tcx.arena.alloc_from_iter(own_entries.into_iter())
235+
own_entries
219236
}
220237

221238
/// Given a trait `trait_ref`, iterates the vtable entries

tests/ui/traits/object/print_vtable_sizes.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ trait C {
1010
fn x() {} // not object safe, shouldn't be reported
1111
}
1212

13-
// This ideally should not have any upcasting cost,
14-
// but currently does due to a bug
13+
// This does not have any upcasting cost,
14+
// because both `Send` and `Sync` are traits
15+
// with no methods
1516
trait D: Send + Sync + help::MarkerWithSuper {}
1617

1718
// This can't have no cost without reordering,

tests/ui/traits/object/print_vtable_sizes.stdout

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "D", "entries": "7", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "3", "upcasting_cost_percent": "75" }
21
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "E", "entries": "6", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "2", "upcasting_cost_percent": "50" }
32
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" }
43
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" }
54
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
5+
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
66
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
77
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
88
print-vtable-sizes { "crate_name": "<UNKNOWN_CRATE>", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }

tests/ui/traits/vtable/multiple-markers.stderr

-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ error: vtable entries for `<S as A>`: [
22
MetadataDropInPlace,
33
MetadataSize,
44
MetadataAlign,
5-
TraitVPtr(<S as M1>),
6-
TraitVPtr(<S as M2>),
75
Method(<S as T>::method),
8-
TraitVPtr(<S as T>),
96
]
107
--> $DIR/multiple-markers.rs:21:1
118
|
@@ -16,9 +13,7 @@ error: vtable entries for `<S as B>`: [
1613
MetadataDropInPlace,
1714
MetadataSize,
1815
MetadataAlign,
19-
TraitVPtr(<S as M1>),
2016
Method(<S as T>::method),
21-
TraitVPtr(<S as T>),
2217
TraitVPtr(<S as M2>),
2318
]
2419
--> $DIR/multiple-markers.rs:24:1
@@ -31,7 +26,6 @@ error: vtable entries for `<S as C>`: [
3126
MetadataSize,
3227
MetadataAlign,
3328
Method(<S as T>::method),
34-
TraitVPtr(<S as T>),
3529
TraitVPtr(<S as M1>),
3630
TraitVPtr(<S as M2>),
3731
]

0 commit comments

Comments
 (0)