Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/rustc_trait_selection/src/traits/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ fn prepare_vtable_segments_inner<'tcx, T>(

// 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() {
let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id);
Copy link
Member

@compiler-errors compiler-errors Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you would like to look at if any of the supertraits (including the trait itself) has entries, you can do something like:

let has_entries = elaborate::supertrait_def_ids(tcx, inner_most_trait_ref.def_id).any(|def_id| has_own_existential_vtable_entries(tcx, def_id));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! This is a much better solution

// We don't need to emit a vptr for "truly-empty" supertraits, but we *do* need to emit a
// vptr for supertraits that have no methods, but that themselves have supertraits
// with methods, so we check if any transitive supertrait has entries here (this includes
// the trait itself).
let has_entries = ty::elaborate::supertrait_def_ids(tcx, inner_most_trait_ref.def_id)
.any(|def_id| has_own_existential_vtable_entries(tcx, def_id));

segment_visitor(VtblSegment::TraitOwnEntries {
trait_ref: inner_most_trait_ref,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: vtable entries: [
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Method(<dyn OneTwo as One>::one - shim(reify)),
Method(<dyn OneTwo as Two>::two - shim(reify)),
TraitVPtr(<dyn OneTwo as Two>),
TraitVPtr(<dyn OneTwo as TwoAgain>),
]
--> $DIR/empty-supertrait-with-nonempty-supersupertrait.rs:40:1
|
LL | type T = dyn OneTwo;
| ^^^^^^

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//@ revisions: run dump
//@[run] run-pass
//@[dump] check-fail
//! Regression test for #145752
//! Ensure that `OneTwo` contains a vptr for `TwoAgain`
#![allow(unused)]
#![cfg_attr(dump, feature(rustc_attrs))]

trait One {
fn one(&self) {
panic!("don't call this");
}
}
impl One for () {}

trait Two {
fn two(&self) {
println!("good");
}
}
impl Two for () {}

trait TwoAgain: Two {}
impl<T: Two> TwoAgain for T {}

trait OneTwo: One + TwoAgain {}
impl<T: One + Two> OneTwo for T {}

fn main() {
(&()).two();
(&() as &dyn OneTwo).two();
(&() as &dyn OneTwo as &dyn Two).two();

// these two used to panic because they called `one` due to #145752
(&() as &dyn OneTwo as &dyn TwoAgain).two();
(&() as &dyn OneTwo as &dyn TwoAgain as &dyn Two).two();
}

#[cfg_attr(dump, rustc_dump_vtable)]
type T = dyn OneTwo;
//[dump]~^ ERROR vtable entries: [
//[dump]~| ERROR MetadataDropInPlace,
//[dump]~| ERROR MetadataSize,
//[dump]~| ERROR MetadataAlign,
//[dump]~| ERROR Method(<dyn OneTwo as One>::one - shim(reify)),
//[dump]~| ERROR Method(<dyn OneTwo as Two>::two - shim(reify)),
//[dump]~| ERROR TraitVPtr(<dyn OneTwo as Two>),
//[dump]~| ERROR TraitVPtr(<dyn OneTwo as TwoAgain>),
//[dump]~| ERROR ]
50 changes: 50 additions & 0 deletions tests/ui/traits/vtable/multiple-auto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Related to <https://github.com/rust-lang/rust/issues/113840>
//
// This test makes sure that multiple auto traits can reuse the
// same pointer for upcasting (e.g. `Send`/`Sync`)

#![crate_type = "lib"]
#![feature(rustc_attrs, auto_traits)]

// Markers
auto trait M0 {}
auto trait M1 {}
auto trait M2 {}

// Just a trait with a method
trait T {
fn method(&self) {}
}

trait A: M0 + M1 + M2 + T {}

trait B: M0 + M1 + T + M2 {}

trait C: M0 + T + M1 + M2 {}

trait D: T + M0 + M1 + M2 {}

struct S;

impl M0 for S {}
impl M1 for S {}
impl M2 for S {}
impl T for S {}

#[rustc_dump_vtable]
impl A for S {}
//~^ ERROR vtable entries

#[rustc_dump_vtable]
impl B for S {}
//~^ ERROR vtable entries

#[rustc_dump_vtable]
impl C for S {}
//~^ ERROR vtable entries

#[rustc_dump_vtable]
impl D for S {}
//~^ ERROR vtable entries

fn main() {}
46 changes: 46 additions & 0 deletions tests/ui/traits/vtable/multiple-auto.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
error: vtable entries: [
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
]
--> $DIR/multiple-auto.rs:35:1
|
LL | impl A for S {}
| ^^^^^^^^^^^^

error: vtable entries: [
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
]
--> $DIR/multiple-auto.rs:39:1
|
LL | impl B for S {}
| ^^^^^^^^^^^^

error: vtable entries: [
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
]
--> $DIR/multiple-auto.rs:43:1
|
LL | impl C for S {}
| ^^^^^^^^^^^^

error: vtable entries: [
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Method(<S as T>::method),
]
--> $DIR/multiple-auto.rs:47:1
|
LL | impl D for S {}
| ^^^^^^^^^^^^

error: aborting due to 4 previous errors

Loading