diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 3565c11249ad1..7e8a41457d411 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -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); + // 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, diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr new file mode 100644 index 0000000000000..d90a786498e16 --- /dev/null +++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr @@ -0,0 +1,16 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::one - shim(reify)), + Method(::two - shim(reify)), + TraitVPtr(), + TraitVPtr(), + ] + --> $DIR/empty-supertrait-with-nonempty-supersupertrait.rs:40:1 + | +LL | type T = dyn OneTwo; + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs new file mode 100644 index 0000000000000..507cda63868cd --- /dev/null +++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs @@ -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 TwoAgain for T {} + +trait OneTwo: One + TwoAgain {} +impl 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(::one - shim(reify)), +//[dump]~| ERROR Method(::two - shim(reify)), +//[dump]~| ERROR TraitVPtr(), +//[dump]~| ERROR TraitVPtr(), +//[dump]~| ERROR ] diff --git a/tests/ui/traits/vtable/multiple-auto.rs b/tests/ui/traits/vtable/multiple-auto.rs new file mode 100644 index 0000000000000..87ee865868bb7 --- /dev/null +++ b/tests/ui/traits/vtable/multiple-auto.rs @@ -0,0 +1,50 @@ +// Related to +// +// 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() {} diff --git a/tests/ui/traits/vtable/multiple-auto.stderr b/tests/ui/traits/vtable/multiple-auto.stderr new file mode 100644 index 0000000000000..0a7c3ebd36da2 --- /dev/null +++ b/tests/ui/traits/vtable/multiple-auto.stderr @@ -0,0 +1,46 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:35:1 + | +LL | impl A for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:39:1 + | +LL | impl B for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:43:1 + | +LL | impl C for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(::method), + ] + --> $DIR/multiple-auto.rs:47:1 + | +LL | impl D for S {} + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors +