diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index b1c725ecd85..36d035cdfd3 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -603,6 +603,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)), + rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), gated!( omit_gdb_pretty_printer_section, AssumedUsed, template!(Word), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a8f969782b2..c0f63f40853 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1047,6 +1047,7 @@ symbols! { rustc_dump_env_program_clauses, rustc_dump_program_clauses, rustc_dump_user_substs, + rustc_dump_vtable, rustc_error, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9537aa20e7a..5c3b3926f4c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -34,7 +34,7 @@ use rustc_middle::ty::{ self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness, COMMON_VTABLE_ENTRIES, }; -use rustc_span::Span; +use rustc_span::{sym, Span}; use smallvec::SmallVec; use std::fmt::Debug; @@ -614,6 +614,11 @@ fn prepare_vtable_segments<'tcx, T>( } } +fn dump_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, entries: &[VtblEntry<'tcx>]) { + let msg = format!("Vtable Entries: {:#?}", entries); + tcx.sess.struct_span_err(rustc_span::DUMMY_SP, &msg).emit(); +} + /// Given a trait `trait_ref`, iterates the vtable entries /// that come from `trait_ref`, including its supertraits. fn vtable_entries<'tcx>( @@ -691,6 +696,11 @@ fn vtable_entries<'tcx>( }; let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback); + + if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) { + dump_vtable_entries(tcx, &entries); + } + tcx.arena.alloc_from_iter(entries.into_iter()) } diff --git a/src/test/ui/traits/vtable/vtable-diamond.rs b/src/test/ui/traits/vtable/vtable-diamond.rs new file mode 100644 index 00000000000..ea26c60af72 --- /dev/null +++ b/src/test/ui/traits/vtable/vtable-diamond.rs @@ -0,0 +1,39 @@ +// build-fail +//~^ error Vtable +//~^^ error Vtable +#![feature(rustc_attrs)] + +#[rustc_dump_vtable] +trait A { + fn foo_a(&self) {} +} + +#[rustc_dump_vtable] +trait B: A { + fn foo_b(&self) {} +} + +#[rustc_dump_vtable] +trait C: A { + fn foo_c(&self) {} +} + +#[rustc_dump_vtable] +trait D: B + C { + fn foo_d(&self) {} +} + +struct S; + +impl A for S {} +impl B for S {} +impl C for S {} +impl D for S {} + +fn foo(d: &dyn D) { + d.foo_d(); +} + +fn main() { + foo(&S); +} diff --git a/src/test/ui/traits/vtable/vtable-diamond.stderr b/src/test/ui/traits/vtable/vtable-diamond.stderr new file mode 100644 index 00000000000..582c8184107 --- /dev/null +++ b/src/test/ui/traits/vtable/vtable-diamond.stderr @@ -0,0 +1,56 @@ +error: Vtable Entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method( + DefId(0:4 ~ vtable_diamond[4564]::A::foo_a), + [ + S, + ], + ), + Method( + DefId(0:6 ~ vtable_diamond[4564]::B::foo_b), + [ + S, + ], + ), + Method( + DefId(0:8 ~ vtable_diamond[4564]::C::foo_c), + [ + S, + ], + ), + TraitVPtr( + Binder( + C, + [], + ), + ), + Method( + DefId(0:10 ~ vtable_diamond[4564]::D::foo_d), + [ + S, + ], + ), +] + +error: Vtable Entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method( + DefId(0:4 ~ vtable_diamond[4564]::A::foo_a), + [ + S, + ], + ), + Method( + DefId(0:8 ~ vtable_diamond[4564]::C::foo_c), + [ + S, + ], + ), +] + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/traits/vtable/vtable-multiple.rs b/src/test/ui/traits/vtable/vtable-multiple.rs new file mode 100644 index 00000000000..d689ae96d41 --- /dev/null +++ b/src/test/ui/traits/vtable/vtable-multiple.rs @@ -0,0 +1,31 @@ +// build-fail +//~^ error Vtable +//~^^ error Vtable +#![feature(rustc_attrs)] + +#[rustc_dump_vtable] +trait A { + fn foo_a(&self) {} +} + +#[rustc_dump_vtable] +trait B { + fn foo_b(&self) {} +} + +#[rustc_dump_vtable] +trait C: A + B { + fn foo_c(&self) {} +} + +struct S; + +impl A for S {} +impl B for S {} +impl C for S {} + +fn foo(c: &dyn C) {} + +fn main() { + foo(&S); +} diff --git a/src/test/ui/traits/vtable/vtable-multiple.stderr b/src/test/ui/traits/vtable/vtable-multiple.stderr new file mode 100644 index 00000000000..222fe9cb0e4 --- /dev/null +++ b/src/test/ui/traits/vtable/vtable-multiple.stderr @@ -0,0 +1,44 @@ +error: Vtable Entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method( + DefId(0:4 ~ vtable_multiple[5246]::A::foo_a), + [ + S, + ], + ), + Method( + DefId(0:6 ~ vtable_multiple[5246]::B::foo_b), + [ + S, + ], + ), + TraitVPtr( + Binder( + B, + [], + ), + ), + Method( + DefId(0:8 ~ vtable_multiple[5246]::C::foo_c), + [ + S, + ], + ), +] + +error: Vtable Entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method( + DefId(0:6 ~ vtable_multiple[5246]::B::foo_b), + [ + S, + ], + ), +] + +error: aborting due to 2 previous errors +