Skip to content

Commit f9b95f9

Browse files
committed
Auto merge of #86461 - crlf0710:rich_vtable, r=nikomatsakis
Refactor vtable format for upcoming trait_upcasting feature. This modifies vtable format: 1. reordering occurrence order of methods coming from different traits 2. include `VPtr`s for supertraits where this vtable cannot be directly reused during trait upcasting. Also, during codegen, the vtables corresponding to these newly included `VPtr` will be requested and generated. For the cases where this vtable can directly used, now the super trait vtable has exactly the same content to some prefix of this one. r? `@bjorn3` cc `@RalfJung` cc `@rust-lang/wg-traits`
2 parents 1c66d11 + fbb353a commit f9b95f9

File tree

15 files changed

+894
-87
lines changed

15 files changed

+894
-87
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
603603
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
604604
rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
605605
rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
606+
rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)),
606607
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
607608
gated!(
608609
omit_gdb_pretty_printer_section, AssumedUsed, template!(Word),

compiler/rustc_infer/src/traits/util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ pub fn anonymize_predicate<'tcx>(
1414
tcx.reuse_or_mk_predicate(pred, new)
1515
}
1616

17-
struct PredicateSet<'tcx> {
17+
pub struct PredicateSet<'tcx> {
1818
tcx: TyCtxt<'tcx>,
1919
set: FxHashSet<ty::Predicate<'tcx>>,
2020
}
2121

2222
impl PredicateSet<'tcx> {
23-
fn new(tcx: TyCtxt<'tcx>) -> Self {
23+
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
2424
Self { tcx, set: Default::default() }
2525
}
2626

27-
fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
27+
pub fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
2828
// We have to be careful here because we want
2929
//
3030
// for<'a> Foo<&'a i32>

compiler/rustc_middle/src/ty/vtable.rs

+39-19
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
use std::convert::TryFrom;
2+
use std::fmt;
23

34
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
4-
use crate::ty::fold::TypeFoldable;
5-
use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt};
5+
use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
66
use rustc_ast::Mutability;
77

8-
#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
8+
#[derive(Clone, Copy, PartialEq, HashStable)]
99
pub enum VtblEntry<'tcx> {
10+
/// destructor of this type (used in vtable header)
1011
MetadataDropInPlace,
12+
/// layout size of this type (used in vtable header)
1113
MetadataSize,
14+
/// layout align of this type (used in vtable header)
1215
MetadataAlign,
16+
/// non-dispatchable associated function that is excluded from trait object
1317
Vacant,
14-
Method(DefId, SubstsRef<'tcx>),
18+
/// dispatchable associated function
19+
Method(Instance<'tcx>),
20+
/// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
21+
TraitVPtr(PolyTraitRef<'tcx>),
22+
}
23+
24+
impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
25+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
// We want to call `Display` on `Instance` and `PolyTraitRef`,
27+
// so we implement this manually.
28+
match self {
29+
VtblEntry::MetadataDropInPlace => write!(f, "MetadataDropInPlace"),
30+
VtblEntry::MetadataSize => write!(f, "MetadataSize"),
31+
VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
32+
VtblEntry::Vacant => write!(f, "Vacant"),
33+
VtblEntry::Method(instance) => write!(f, "Method({})", instance),
34+
VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
35+
}
36+
}
1537
}
1638

1739
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
@@ -36,11 +58,6 @@ impl<'tcx> TyCtxt<'tcx> {
3658
}
3759
drop(vtables_cache);
3860

39-
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
40-
assert!(
41-
!ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst())
42-
);
43-
let param_env = ty::ParamEnv::reveal_all();
4461
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
4562
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
4663
let trait_ref = tcx.erase_regions(trait_ref);
@@ -50,8 +67,9 @@ impl<'tcx> TyCtxt<'tcx> {
5067
COMMON_VTABLE_ENTRIES
5168
};
5269

53-
let layout =
54-
tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation");
70+
let layout = tcx
71+
.layout_of(ty::ParamEnv::reveal_all().and(ty))
72+
.expect("failed to build vtable representation");
5573
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
5674
let size = layout.size.bytes();
5775
let align = layout.align.abi.bytes();
@@ -79,19 +97,21 @@ impl<'tcx> TyCtxt<'tcx> {
7997
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
8098
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
8199
VtblEntry::Vacant => continue,
82-
VtblEntry::Method(def_id, substs) => {
83-
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
84-
assert!(!substs.needs_subst());
85-
100+
VtblEntry::Method(instance) => {
86101
// Prepare the fn ptr we write into the vtable.
87-
let instance =
88-
ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs)
89-
.expect("resolution failed during building vtable representation")
90-
.polymorphize(tcx);
102+
let instance = instance.polymorphize(tcx);
91103
let fn_alloc_id = tcx.create_fn_alloc(instance);
92104
let fn_ptr = Pointer::from(fn_alloc_id);
93105
ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
94106
}
107+
VtblEntry::TraitVPtr(trait_ref) => {
108+
let super_trait_ref = trait_ref.map_bound(|trait_ref| {
109+
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
110+
});
111+
let supertrait_alloc_id = self.vtable_allocation(ty, Some(super_trait_ref));
112+
let vptr = Pointer::from(supertrait_alloc_id);
113+
ScalarMaybeUninit::from_pointer(vptr, &tcx)
114+
}
95115
};
96116
vtable
97117
.write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)

compiler/rustc_mir/src/monomorphize/collector.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1116,13 +1116,13 @@ fn create_mono_items_for_vtable_methods<'tcx>(
11161116
| VtblEntry::MetadataSize
11171117
| VtblEntry::MetadataAlign
11181118
| VtblEntry::Vacant => None,
1119-
VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
1120-
tcx,
1121-
ty::ParamEnv::reveal_all(),
1122-
*def_id,
1123-
substs,
1124-
)
1125-
.filter(|instance| should_codegen_locally(tcx, instance)),
1119+
VtblEntry::TraitVPtr(_) => {
1120+
// all super trait items already covered, so skip them.
1121+
None
1122+
}
1123+
VtblEntry::Method(instance) => {
1124+
Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
1125+
}
11261126
})
11271127
.map(|item| create_fn_mono_item(tcx, item, source));
11281128
output.extend(methods);

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ symbols! {
10471047
rustc_dump_env_program_clauses,
10481048
rustc_dump_program_clauses,
10491049
rustc_dump_user_substs,
1050+
rustc_dump_vtable,
10501051
rustc_error,
10511052
rustc_evaluate_where_clauses,
10521053
rustc_expected_cgu_reuse,

compiler/rustc_trait_selection/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extern crate rustc_data_structures;
3131
extern crate tracing;
3232
#[macro_use]
3333
extern crate rustc_middle;
34+
#[macro_use]
35+
extern crate smallvec;
3436

3537
pub mod autoderef;
3638
pub mod infer;

0 commit comments

Comments
 (0)