Skip to content

Commit 08d7e9d

Browse files
Rework rustc_dump_vtable
1 parent 5a45ab9 commit 08d7e9d

23 files changed

+510
-288
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
11361136
),
11371137
rustc_attr!(
11381138
TEST, rustc_dump_vtable, Normal, template!(Word),
1139-
WarnFollowing, EncodeCrossCrate::Yes
1139+
WarnFollowing, EncodeCrossCrate::No
11401140
),
11411141
rustc_attr!(
11421142
TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),

compiler/rustc_hir_analysis/src/collect/dump.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use rustc_hir as hir;
12
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
23
use rustc_hir::intravisit;
34
use rustc_middle::hir::nested_filter;
4-
use rustc_middle::ty::TyCtxt;
5+
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
56
use rustc_span::sym;
67

78
pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
@@ -87,3 +88,82 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
8788
}
8889
}
8990
}
91+
92+
pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
93+
for id in tcx.hir().items() {
94+
let def_id = id.owner_id.def_id;
95+
96+
let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else {
97+
continue;
98+
};
99+
100+
let vtable_entries = match tcx.hir().item(id).kind {
101+
hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
102+
let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
103+
if trait_ref.has_non_region_param() {
104+
tcx.dcx().span_err(
105+
attr.span,
106+
"`rustc_dump_vtable` must be applied to non-generic impl",
107+
);
108+
continue;
109+
}
110+
if !tcx.is_dyn_compatible(trait_ref.def_id) {
111+
tcx.dcx().span_err(
112+
attr.span,
113+
"`rustc_dump_vtable` must be applied to dyn-compatible trait",
114+
);
115+
continue;
116+
}
117+
let Ok(trait_ref) = tcx
118+
.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
119+
else {
120+
tcx.dcx().span_err(
121+
attr.span,
122+
"`rustc_dump_vtable` applied to impl header that cannot be normalized",
123+
);
124+
continue;
125+
};
126+
tcx.vtable_entries(ty::Binder::dummy(trait_ref))
127+
}
128+
hir::ItemKind::TyAlias(_, _) => {
129+
let ty = tcx.type_of(def_id).instantiate_identity();
130+
if ty.has_non_region_param() {
131+
tcx.dcx().span_err(
132+
attr.span,
133+
"`rustc_dump_vtable` must be applied to non-generic type",
134+
);
135+
continue;
136+
}
137+
let Ok(ty) =
138+
tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
139+
else {
140+
tcx.dcx().span_err(
141+
attr.span,
142+
"`rustc_dump_vtable` applied to type alias that cannot be normalized",
143+
);
144+
continue;
145+
};
146+
let ty::Dynamic(data, _, _) = *ty.kind() else {
147+
tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type");
148+
continue;
149+
};
150+
if let Some(principal) = data.principal() {
151+
tcx.vtable_entries(
152+
principal.map_bound(|principal| principal.with_self_ty(tcx, ty)),
153+
)
154+
} else {
155+
TyCtxt::COMMON_VTABLE_ENTRIES
156+
}
157+
}
158+
_ => {
159+
tcx.dcx().span_err(
160+
attr.span,
161+
"`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
162+
);
163+
continue;
164+
}
165+
};
166+
167+
tcx.dcx().span_err(tcx.def_span(def_id), format!("vtable entries: {vtable_entries:#?}"));
168+
}
169+
}

compiler/rustc_hir_analysis/src/lib.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
152152
});
153153

154154
if tcx.features().rustc_attrs() {
155-
tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
156-
tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
157-
collect::dump::opaque_hidden_types(tcx);
158-
collect::dump::predicates_and_item_bounds(tcx);
159-
collect::dump::def_parents(tcx);
155+
tcx.sess.time("dumping_rustc_attr_data", || {
156+
outlives::dump::inferred_outlives(tcx);
157+
variance::dump::variances(tcx);
158+
collect::dump::opaque_hidden_types(tcx);
159+
collect::dump::predicates_and_item_bounds(tcx);
160+
collect::dump::def_parents(tcx);
161+
collect::dump::vtables(tcx);
162+
});
160163
}
161164

162165
// Make sure we evaluate all static and (non-associated) const items, even if unused.

compiler/rustc_trait_selection/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement
148148
trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
149149
trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement
150150
151-
trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
152-
153151
trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
154152
.label = empty on-clause here
155153

compiler/rustc_trait_selection/src/errors.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
1212
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
1313
use rustc_macros::{Diagnostic, Subdiagnostic};
1414
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
15-
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
15+
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt};
1616
use rustc_span::{BytePos, Ident, Span, Symbol, kw};
1717

1818
use crate::error_reporting::infer::ObligationCauseAsDiagArg;
@@ -22,15 +22,6 @@ use crate::fluent_generated as fluent;
2222

2323
pub mod note_and_explain;
2424

25-
#[derive(Diagnostic)]
26-
#[diag(trait_selection_dump_vtable_entries)]
27-
pub struct DumpVTableEntries<'a> {
28-
#[primary_span]
29-
pub span: Span,
30-
pub trait_ref: PolyTraitRef<'a>,
31-
pub entries: String,
32-
}
33-
3425
#[derive(Diagnostic)]
3526
#[diag(trait_selection_unable_to_construct_constant_value)]
3627
pub struct UnableToConstructConstantValue<'a> {

compiler/rustc_trait_selection/src/traits/vtable.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ use rustc_middle::query::Providers;
1111
use rustc_middle::ty::{
1212
self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
1313
};
14-
use rustc_span::{DUMMY_SP, Span, sym};
14+
use rustc_span::DUMMY_SP;
1515
use smallvec::{SmallVec, smallvec};
1616
use tracing::debug;
1717

18-
use crate::errors::DumpVTableEntries;
1918
use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
2019

2120
#[derive(Clone, Debug)]
@@ -192,15 +191,6 @@ fn maybe_iter<I: Iterator>(i: Option<I>) -> impl Iterator<Item = I::Item> {
192191
i.into_iter().flatten()
193192
}
194193

195-
fn dump_vtable_entries<'tcx>(
196-
tcx: TyCtxt<'tcx>,
197-
sp: Span,
198-
trait_ref: ty::PolyTraitRef<'tcx>,
199-
entries: &[VtblEntry<'tcx>],
200-
) {
201-
tcx.dcx().emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") });
202-
}
203-
204194
fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
205195
own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some()
206196
}
@@ -317,11 +307,6 @@ fn vtable_entries<'tcx>(
317307

318308
let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
319309

320-
if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
321-
let sp = tcx.def_span(trait_ref.def_id());
322-
dump_vtable_entries(tcx, sp, trait_ref, &entries);
323-
}
324-
325310
tcx.arena.alloc_from_iter(entries)
326311
}
327312

src/doc/rustc-dev-guide/src/compiler-debugging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ Here are some notable ones:
275275
| `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. |
276276
| `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. |
277277
| `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. |
278-
| `rustc_dump_vtable` | |
278+
| `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. |
279279
| `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
280280
| `rustc_layout` | [See this section](#debugging-type-layouts). |
281281
| `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. |
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![feature(rustc_attrs)]
2+
3+
trait Supertrait<T> {
4+
fn _print_numbers(&self, mem: &[usize; 100]) {
5+
}
6+
}
7+
impl<T> Supertrait<T> for () {}
8+
9+
trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
10+
fn say_hello(&self, _: &usize) {
11+
}
12+
}
13+
impl<T, U> Trait<T, U> for () {}
14+
15+
// We should observe compatibility between these two vtables.
16+
17+
#[rustc_dump_vtable]
18+
type First = dyn for<'a> Trait<&'static (), &'a ()>;
19+
//~^ ERROR vtable entries
20+
21+
#[rustc_dump_vtable]
22+
type Second = dyn Trait<&'static (), &'static ()>;
23+
//~^ ERROR vtable entries
24+
25+
fn main() {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: vtable entries: [
2+
MetadataDropInPlace,
3+
MetadataSize,
4+
MetadataAlign,
5+
Method(<dyn for<'a> Trait<&(), &'a ()> as Supertrait<&()>>::_print_numbers - shim(reify)),
6+
Method(<dyn for<'a> Trait<&(), &'a ()> as Supertrait<&()>>::_print_numbers - shim(reify)),
7+
TraitVPtr(for<'a> <dyn for<'a> Trait<&(), &'a ()> as Supertrait<&'a ()>>),
8+
Method(<dyn for<'a> Trait<&(), &'a ()> as Trait<&(), &()>>::say_hello - shim(reify)),
9+
]
10+
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:18:1
11+
|
12+
LL | type First = dyn for<'a> Trait<&'static (), &'a ()>;
13+
| ^^^^^^^^^^
14+
15+
error: vtable entries: [
16+
MetadataDropInPlace,
17+
MetadataSize,
18+
MetadataAlign,
19+
Method(<dyn Trait<&(), &()> as Supertrait<&()>>::_print_numbers - shim(reify)),
20+
Method(<dyn Trait<&(), &()> as Trait<&(), &()>>::say_hello - shim(reify)),
21+
]
22+
--> $DIR/multiple-supertraits-modulo-binder-vtable.rs:22:1
23+
|
24+
LL | type Second = dyn Trait<&'static (), &'static ()>;
25+
| ^^^^^^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![feature(rustc_attrs)]
2+
3+
#![feature(trait_upcasting)]
4+
5+
trait Supertrait<T> {
6+
fn _print_numbers(&self, mem: &[usize; 100]) {
7+
println!("{mem:?}");
8+
}
9+
}
10+
impl<T> Supertrait<T> for () {}
11+
12+
trait Identity {
13+
type Selff;
14+
}
15+
impl<Selff> Identity for Selff {
16+
type Selff = Selff;
17+
}
18+
19+
trait Middle<T>: Supertrait<()> + Supertrait<T> {
20+
fn say_hello(&self, _: &usize) {
21+
println!("Hello!");
22+
}
23+
}
24+
impl<T> Middle<T> for () {}
25+
26+
trait Trait: Middle<<() as Identity>::Selff> {}
27+
28+
#[rustc_dump_vtable]
29+
impl Trait for () {}
30+
//~^ ERROR vtable entries
31+
32+
#[rustc_dump_vtable]
33+
type Virtual = dyn Middle<()>;
34+
//~^ ERROR vtable entries
35+
36+
fn main() {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: vtable entries: [
2+
MetadataDropInPlace,
3+
MetadataSize,
4+
MetadataAlign,
5+
Method(<() as Supertrait<()>>::_print_numbers),
6+
Method(<() as Supertrait<()>>::_print_numbers),
7+
TraitVPtr(<() as Supertrait<<() as Identity>::Selff>>),
8+
Method(<() as Middle<()>>::say_hello),
9+
]
10+
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:29:1
11+
|
12+
LL | impl Trait for () {}
13+
| ^^^^^^^^^^^^^^^^^
14+
15+
error: vtable entries: [
16+
MetadataDropInPlace,
17+
MetadataSize,
18+
MetadataAlign,
19+
Method(<dyn Middle<()> as Supertrait<()>>::_print_numbers - shim(reify)),
20+
Method(<dyn Middle<()> as Middle<()>>::say_hello - shim(reify)),
21+
]
22+
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:33:1
23+
|
24+
LL | type Virtual = dyn Middle<()>;
25+
| ^^^^^^^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+

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

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
//
33
// This test makes sure that multiple marker (method-less) traits can reuse the
44
// same pointer for upcasting.
5-
//
6-
//@ build-fail
5+
76
#![crate_type = "lib"]
87
#![feature(rustc_attrs)]
98

@@ -17,31 +16,35 @@ trait T {
1716
fn method(&self) {}
1817
}
1918

20-
#[rustc_dump_vtable]
21-
trait A: M0 + M1 + M2 + T {} //~ error: vtable entries for `<S as A>`:
19+
trait A: M0 + M1 + M2 + T {}
2220

23-
#[rustc_dump_vtable]
24-
trait B: M0 + M1 + T + M2 {} //~ error: vtable entries for `<S as B>`:
21+
trait B: M0 + M1 + T + M2 {}
2522

26-
#[rustc_dump_vtable]
27-
trait C: M0 + T + M1 + M2 {} //~ error: vtable entries for `<S as C>`:
23+
trait C: M0 + T + M1 + M2 {}
2824

29-
#[rustc_dump_vtable]
30-
trait D: T + M0 + M1 + M2 {} //~ error: vtable entries for `<S as D>`:
25+
trait D: T + M0 + M1 + M2 {}
3126

3227
struct S;
3328

3429
impl M0 for S {}
3530
impl M1 for S {}
3631
impl M2 for S {}
3732
impl T for S {}
33+
34+
#[rustc_dump_vtable]
3835
impl A for S {}
36+
//~^ ERROR vtable entries
37+
38+
#[rustc_dump_vtable]
3939
impl B for S {}
40+
//~^ ERROR vtable entries
41+
42+
#[rustc_dump_vtable]
4043
impl C for S {}
41-
impl D for S {}
44+
//~^ ERROR vtable entries
4245

43-
pub fn require_vtables() {
44-
fn require_vtables(_: &dyn A, _: &dyn B, _: &dyn C, _: &dyn D) {}
46+
#[rustc_dump_vtable]
47+
impl D for S {}
48+
//~^ ERROR vtable entries
4549

46-
require_vtables(&S, &S, &S, &S)
47-
}
50+
fn main() {}

0 commit comments

Comments
 (0)