From eabd306265911c30641dbf8b263e0191a7e07f9a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 09:44:40 +0000 Subject: [PATCH 1/9] Document `PredicateSet::insert` I always forget what the `bool` means :/ --- compiler/rustc_infer/src/traits/util.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 074ff7ec97f84..87ba6b3ec5089 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -25,6 +25,13 @@ impl<'tcx> PredicateSet<'tcx> { Self { tcx, set: Default::default() } } + /// Adds a predicate to the set. + /// + /// Returns whether the predicate was newly inserted. That is: + /// - If the set did not previously contain this predicate, `true` is returned. + /// - If the set already contained this predicate, `false` is returned, + /// and the set is not modified: original predicate is not replaced, + /// and the predicate passed as argument is dropped. pub fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool { // We have to be careful here because we want // From 348f26e40957c2a2469f0ea2b41c403803de8075 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 09:45:26 +0000 Subject: [PATCH 2/9] Use `?` in `prepare_vtable_segments` --- .../src/traits/vtable.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 78816fed01739..0a3f423d3c1ac 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -24,8 +24,18 @@ pub enum VtblSegment<'tcx> { pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, - mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, + segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, ) -> Option { + prepare_vtable_segments_inner(tcx, trait_ref, 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::PolyTraitRef<'tcx>, + mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, +) -> ControlFlow { // The following constraints holds for the final arrangement. // 1. The whole virtual table of the first direct super trait is included as the // the prefix. If this trait doesn't have any super traits, then this step @@ -71,9 +81,7 @@ pub fn prepare_vtable_segments<'tcx, T>( // N, N-vptr, O // emit dsa segment first. - if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) { - return Some(v); - } + segment_visitor(VtblSegment::MetadataDSA)?; let mut emit_vptr_on_new_entry = false; let mut visited = PredicateSet::new(tcx); @@ -146,12 +154,10 @@ pub fn prepare_vtable_segments<'tcx, T>( // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. 'exiting_out: loop { if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() { - if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries { + segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: *inner_most_trait_ref, emit_vptr: *emit_vptr, - }) { - return Some(v); - } + })?; 'exiting_out_skip_visited_traits: loop { if let Some(siblings) = siblings_opt { @@ -174,7 +180,7 @@ pub fn prepare_vtable_segments<'tcx, T>( } } // all done - return None; + return ControlFlow::Continue(()); } } } From f8f5d7aab28b9c310b4312b5d38c80fe4dc6df02 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 09:49:13 +0000 Subject: [PATCH 3/9] Replace `if let` with `unwrap` in `prepare_vtable_segments` Reasoning: if the stack is empty, the loop will be infinite, so the assumption is that the stack can't be non empty. Unwrap makes the assumption more clear (and removes an indentation level) --- .../src/traits/vtable.rs | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 0a3f423d3c1ac..ac9fb51e3919e 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -116,34 +116,33 @@ fn prepare_vtable_segments_inner<'tcx, T>( loop { // dive deeper into the stack, recording the path 'diving_in: loop { - if let Some((inner_most_trait_ref, _, _)) = stack.last() { - let inner_most_trait_ref = *inner_most_trait_ref; - let mut direct_super_traits_iter = tcx - .super_predicates_of(inner_most_trait_ref.def_id()) - .predicates - .into_iter() - .filter_map(move |(pred, _)| { - pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() - }); + let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); + + let mut direct_super_traits_iter = tcx + .super_predicates_of(inner_most_trait_ref.def_id()) + .predicates + .into_iter() + .filter_map(move |(pred, _)| { + pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + }); - 'diving_in_skip_visited_traits: loop { - if let Some(next_super_trait) = direct_super_traits_iter.next() { - if visited.insert(next_super_trait.to_predicate(tcx)) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); - stack.push(( - next_super_trait, - emit_vptr_on_new_entry, - Some(direct_super_traits_iter), - )); - break 'diving_in_skip_visited_traits; - } else { - continue 'diving_in_skip_visited_traits; - } + 'diving_in_skip_visited_traits: loop { + if let Some(next_super_trait) = direct_super_traits_iter.next() { + if visited.insert(next_super_trait.to_predicate(tcx)) { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); + stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + Some(direct_super_traits_iter), + )); + break 'diving_in_skip_visited_traits; } else { - break 'diving_in; + continue 'diving_in_skip_visited_traits; } + } else { + break 'diving_in; } } } From 364fc444a5f4e8f348d5abeb9978894ed250823a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 10:01:48 +0000 Subject: [PATCH 4/9] Refactor 'diving_in loop internals in `prepare_vtable_segments` Less explicit loops -- easier to read. --- .../src/traits/vtable.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index ac9fb51e3919e..89b5272083ec9 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -126,24 +126,24 @@ fn prepare_vtable_segments_inner<'tcx, T>( pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() }); - 'diving_in_skip_visited_traits: loop { - if let Some(next_super_trait) = direct_super_traits_iter.next() { - if visited.insert(next_super_trait.to_predicate(tcx)) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); - stack.push(( - next_super_trait, - emit_vptr_on_new_entry, - Some(direct_super_traits_iter), - )); - break 'diving_in_skip_visited_traits; - } else { - continue 'diving_in_skip_visited_traits; - } - } else { - break 'diving_in; + // Find an unvisited supertrait + match direct_super_traits_iter + .find(|&super_trait| visited.insert(super_trait.to_predicate(tcx))) + { + // Push it to the stack for the next iteration of 'diving_in to pick up + Some(unvisited_super_trait) => { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref); + stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + Some(direct_super_traits_iter), + )) } + + // There are no more unvisited direct super traits, dive-in finished + None => break 'diving_in, } } From d567f0fc688411a8805c0187957b8bdcc84ef1d8 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 10:19:12 +0000 Subject: [PATCH 5/9] Slightly refactor 'exiting_out loop in `prepare_vtable_segments` 1. Hide the option as an iterator, so it's nicer to work with 2. Replace a loop with `find` --- .../src/traits/vtable.rs | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 89b5272083ec9..c00161d158ff9 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -87,7 +87,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let mut visited = PredicateSet::new(tcx); let predicate = trait_ref.without_const().to_predicate(tcx); let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> = - smallvec![(trait_ref, emit_vptr_on_new_entry, None)]; + smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))]; visited.insert(predicate); // the main traversal loop: @@ -138,7 +138,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( stack.push(( next_super_trait, emit_vptr_on_new_entry, - Some(direct_super_traits_iter), + maybe_iter(Some(direct_super_traits_iter)), )) } @@ -152,30 +152,26 @@ fn prepare_vtable_segments_inner<'tcx, T>( // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. 'exiting_out: loop { - if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() { + if let Some((inner_most_trait_ref, emit_vptr, siblings)) = stack.last_mut() { segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: *inner_most_trait_ref, emit_vptr: *emit_vptr, })?; - 'exiting_out_skip_visited_traits: loop { - if let Some(siblings) = siblings_opt { - if let Some(next_inner_most_trait_ref) = siblings.next() { - if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_inner_most_trait_ref = - next_inner_most_trait_ref.map_bound(|t| t.trait_ref); - *inner_most_trait_ref = next_inner_most_trait_ref; - *emit_vptr = emit_vptr_on_new_entry; - break 'exiting_out; - } else { - continue 'exiting_out_skip_visited_traits; - } - } + match siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx))) { + Some(next_inner_most_trait_ref) => { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_inner_most_trait_ref = + next_inner_most_trait_ref.map_bound(|t| t.trait_ref); + *inner_most_trait_ref = next_inner_most_trait_ref; + *emit_vptr = emit_vptr_on_new_entry; + break 'exiting_out; + } + None => { + stack.pop(); + continue 'exiting_out; } - stack.pop(); - continue 'exiting_out; } } // all done @@ -184,6 +180,12 @@ fn prepare_vtable_segments_inner<'tcx, T>( } } +/// Turns option of iterator into an iterator (this is just flatten) +fn maybe_iter(i: Option) -> impl Iterator { + // Flatten is bad perf-vise, we could probably implement a special case here that is better + i.into_iter().flatten() +} + fn dump_vtable_entries<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, From d87db8eb3f470d5cc8901dd74f6a25685511161a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 10:34:35 +0000 Subject: [PATCH 6/9] Simplify last `prepare_vtable_segments` loop even more --- .../src/traits/vtable.rs | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index c00161d158ff9..3a647b784ccfa 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -113,7 +113,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node. // Loop run #1: Stack after exiting out is []. Now the function exits. - loop { + 'outer: loop { // dive deeper into the stack, recording the path 'diving_in: loop { let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); @@ -151,32 +151,29 @@ fn prepare_vtable_segments_inner<'tcx, T>( emit_vptr_on_new_entry = true; // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. - 'exiting_out: loop { - if let Some((inner_most_trait_ref, emit_vptr, siblings)) = stack.last_mut() { - segment_visitor(VtblSegment::TraitOwnEntries { - trait_ref: *inner_most_trait_ref, - emit_vptr: *emit_vptr, - })?; - - match siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx))) { - Some(next_inner_most_trait_ref) => { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_inner_most_trait_ref = - next_inner_most_trait_ref.map_bound(|t| t.trait_ref); - *inner_most_trait_ref = next_inner_most_trait_ref; - *emit_vptr = emit_vptr_on_new_entry; - break 'exiting_out; - } - None => { - stack.pop(); - continue 'exiting_out; - } - } + while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { + segment_visitor(VtblSegment::TraitOwnEntries { + trait_ref: inner_most_trait_ref, + emit_vptr, + })?; + + if let Some(next_inner_most_trait_ref) = + siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx))) + { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_inner_most_trait_ref = + next_inner_most_trait_ref.map_bound(|t| t.trait_ref); + + stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings)); + + // just pushed a new trait onto the stack, so we need to go through its super traits + continue 'outer; } - // all done - return ControlFlow::Continue(()); } + + // the stack is empty, all done + return ControlFlow::Continue(()); } } From f33936c567829d024a829f25c40b1e6dca9c75c6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 11:40:51 +0000 Subject: [PATCH 7/9] Fix comment --- compiler/rustc_trait_selection/src/traits/vtable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 3a647b784ccfa..13ece4ccebb21 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -92,7 +92,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( // the main traversal loop: // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes - // that each node is emitted after all its descendents have been emitted. + // such that each node is emitted after all its descendants have been emitted. // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set. // this is done on the fly. // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it From b5d122850821f80f9496abc09840102561ec4267 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 11:45:04 +0000 Subject: [PATCH 8/9] Add a (failing test) for issue `113840` --- tests/ui/traits/vtable/multiple-markers.rs | 47 +++++++++++++++ .../ui/traits/vtable/multiple-markers.stderr | 58 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tests/ui/traits/vtable/multiple-markers.rs create mode 100644 tests/ui/traits/vtable/multiple-markers.stderr diff --git a/tests/ui/traits/vtable/multiple-markers.rs b/tests/ui/traits/vtable/multiple-markers.rs new file mode 100644 index 0000000000000..1e6e308702762 --- /dev/null +++ b/tests/ui/traits/vtable/multiple-markers.rs @@ -0,0 +1,47 @@ +// Regression test for +// +// This test makes sure that multiple marker (method-less) traits can reuse the +// same pointer for upcasting. +// +// build-fail +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +// Markers +trait M0 {} +trait M1 {} +trait M2 {} + +// Just a trait with a method +trait T { + fn method(&self) {} +} + +#[rustc_dump_vtable] +trait A: M0 + M1 + M2 + T {} //~ error: vtable entries for ``: + +#[rustc_dump_vtable] +trait B: M0 + M1 + T + M2 {} //~ error: vtable entries for ``: + +#[rustc_dump_vtable] +trait C: M0 + T + M1 + M2 {} //~ error: vtable entries for ``: + +#[rustc_dump_vtable] +trait D: T + M0 + M1 + M2 {} //~ error: vtable entries for ``: + +struct S; + +impl M0 for S {} +impl M1 for S {} +impl M2 for S {} +impl T for S {} +impl A for S {} +impl B for S {} +impl C for S {} +impl D for S {} + +pub fn require_vtables() { + fn require_vtables(_: &dyn A, _: &dyn B, _: &dyn C, _: &dyn D) {} + + require_vtables(&S, &S, &S, &S) +} diff --git a/tests/ui/traits/vtable/multiple-markers.stderr b/tests/ui/traits/vtable/multiple-markers.stderr new file mode 100644 index 0000000000000..766be12487b9e --- /dev/null +++ b/tests/ui/traits/vtable/multiple-markers.stderr @@ -0,0 +1,58 @@ +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + TraitVPtr(), + TraitVPtr(), + Method(::method), + TraitVPtr(), + ] + --> $DIR/multiple-markers.rs:21:1 + | +LL | trait A: M0 + M1 + M2 + T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + TraitVPtr(), + Method(::method), + TraitVPtr(), + TraitVPtr(), + ] + --> $DIR/multiple-markers.rs:24:1 + | +LL | trait B: M0 + M1 + T + M2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + TraitVPtr(), + TraitVPtr(), + TraitVPtr(), + ] + --> $DIR/multiple-markers.rs:27:1 + | +LL | trait C: M0 + T + M1 + M2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: vtable entries for ``: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + TraitVPtr(), + TraitVPtr(), + TraitVPtr(), + ] + --> $DIR/multiple-markers.rs:30:1 + | +LL | trait D: T + M0 + M1 + M2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From 1f02c75718706d6180f9b25f55aa50f1b4ce75e1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 19 Jul 2023 11:50:40 +0000 Subject: [PATCH 9/9] 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(), ]