Switch to store Instance
directly within VtblEntry
, fix TraitVPtr
representation.
This commit is contained in:
parent
ab171c5279
commit
634638782b
7 changed files with 98 additions and 116 deletions
|
@ -1,18 +1,33 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
|
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
|
||||||
use crate::ty::fold::TypeFoldable;
|
use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
|
||||||
use crate::ty::{self, DefId, PolyExistentialTraitRef, SubstsRef, Ty, TyCtxt};
|
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
|
#[derive(Clone, Copy, PartialEq, HashStable)]
|
||||||
pub enum VtblEntry<'tcx> {
|
pub enum VtblEntry<'tcx> {
|
||||||
MetadataDropInPlace,
|
MetadataDropInPlace,
|
||||||
MetadataSize,
|
MetadataSize,
|
||||||
MetadataAlign,
|
MetadataAlign,
|
||||||
Vacant,
|
Vacant,
|
||||||
Method(DefId, SubstsRef<'tcx>),
|
Method(Instance<'tcx>),
|
||||||
TraitVPtr(PolyExistentialTraitRef<'tcx>),
|
TraitVPtr(PolyTraitRef<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
// We want to call `Display` on `Instance` and `PolyTraitRef`,
|
||||||
|
// so we implement this manually.
|
||||||
|
match self {
|
||||||
|
VtblEntry::MetadataDropInPlace => write!(f, "MetadataDropInPlace"),
|
||||||
|
VtblEntry::MetadataSize => write!(f, "MetadataSize"),
|
||||||
|
VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
|
||||||
|
VtblEntry::Vacant => write!(f, "Vacant"),
|
||||||
|
VtblEntry::Method(instance) => write!(f, "Method({})", instance),
|
||||||
|
VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
|
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
|
||||||
|
@ -37,11 +52,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
drop(vtables_cache);
|
drop(vtables_cache);
|
||||||
|
|
||||||
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
|
|
||||||
assert!(
|
|
||||||
!ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst())
|
|
||||||
);
|
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
|
||||||
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
|
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
|
||||||
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
|
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
|
||||||
let trait_ref = tcx.erase_regions(trait_ref);
|
let trait_ref = tcx.erase_regions(trait_ref);
|
||||||
|
@ -51,8 +61,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
COMMON_VTABLE_ENTRIES
|
COMMON_VTABLE_ENTRIES
|
||||||
};
|
};
|
||||||
|
|
||||||
let layout =
|
let layout = tcx
|
||||||
tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation");
|
.layout_of(ty::ParamEnv::reveal_all().and(ty))
|
||||||
|
.expect("failed to build vtable representation");
|
||||||
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
|
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
|
||||||
let size = layout.size.bytes();
|
let size = layout.size.bytes();
|
||||||
let align = layout.align.abi.bytes();
|
let align = layout.align.abi.bytes();
|
||||||
|
@ -80,21 +91,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
|
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
|
||||||
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
|
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
|
||||||
VtblEntry::Vacant => continue,
|
VtblEntry::Vacant => continue,
|
||||||
VtblEntry::Method(def_id, substs) => {
|
VtblEntry::Method(instance) => {
|
||||||
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
|
|
||||||
assert!(!substs.needs_subst());
|
|
||||||
|
|
||||||
// Prepare the fn ptr we write into the vtable.
|
// Prepare the fn ptr we write into the vtable.
|
||||||
let instance =
|
let instance = instance.polymorphize(tcx);
|
||||||
ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs)
|
|
||||||
.expect("resolution failed during building vtable representation")
|
|
||||||
.polymorphize(tcx);
|
|
||||||
let fn_alloc_id = tcx.create_fn_alloc(instance);
|
let fn_alloc_id = tcx.create_fn_alloc(instance);
|
||||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||||
ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
|
ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
|
||||||
}
|
}
|
||||||
VtblEntry::TraitVPtr(trait_ref) => {
|
VtblEntry::TraitVPtr(trait_ref) => {
|
||||||
let supertrait_alloc_id = self.vtable_allocation(ty, Some(*trait_ref));
|
let super_trait_ref = trait_ref.map_bound(|trait_ref| {
|
||||||
|
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||||
|
});
|
||||||
|
let supertrait_alloc_id = self.vtable_allocation(ty, Some(super_trait_ref));
|
||||||
let vptr = Pointer::from(supertrait_alloc_id);
|
let vptr = Pointer::from(supertrait_alloc_id);
|
||||||
ScalarMaybeUninit::from_pointer(vptr, &tcx)
|
ScalarMaybeUninit::from_pointer(vptr, &tcx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1120,13 +1120,9 @@ fn create_mono_items_for_vtable_methods<'tcx>(
|
||||||
// all super trait items already covered, so skip them.
|
// all super trait items already covered, so skip them.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
|
VtblEntry::Method(instance) => {
|
||||||
tcx,
|
Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
|
||||||
ty::ParamEnv::reveal_all(),
|
}
|
||||||
*def_id,
|
|
||||||
substs,
|
|
||||||
)
|
|
||||||
.filter(|instance| should_codegen_locally(tcx, instance)),
|
|
||||||
})
|
})
|
||||||
.map(|item| create_fn_mono_item(tcx, item, source));
|
.map(|item| create_fn_mono_item(tcx, item, source));
|
||||||
output.extend(methods);
|
output.extend(methods);
|
||||||
|
|
|
@ -614,9 +614,14 @@ fn prepare_vtable_segments<'tcx, T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, entries: &[VtblEntry<'tcx>]) {
|
fn dump_vtable_entries<'tcx>(
|
||||||
let msg = format!("Vtable Entries: {:#?}", entries);
|
tcx: TyCtxt<'tcx>,
|
||||||
tcx.sess.struct_span_err(rustc_span::DUMMY_SP, &msg).emit();
|
sp: Span,
|
||||||
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
|
entries: &[VtblEntry<'tcx>],
|
||||||
|
) {
|
||||||
|
let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries);
|
||||||
|
tcx.sess.struct_span_err(sp, &msg).emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a trait `trait_ref`, iterates the vtable entries
|
/// Given a trait `trait_ref`, iterates the vtable entries
|
||||||
|
@ -678,15 +683,19 @@ fn vtable_entries<'tcx>(
|
||||||
return VtblEntry::Vacant;
|
return VtblEntry::Vacant;
|
||||||
}
|
}
|
||||||
|
|
||||||
VtblEntry::Method(def_id, substs)
|
let instance = ty::Instance::resolve_for_vtable(
|
||||||
|
tcx,
|
||||||
|
ty::ParamEnv::reveal_all(),
|
||||||
|
def_id,
|
||||||
|
substs,
|
||||||
|
)
|
||||||
|
.expect("resolution failed during building vtable representation");
|
||||||
|
VtblEntry::Method(instance)
|
||||||
});
|
});
|
||||||
|
|
||||||
entries.extend(own_entries);
|
entries.extend(own_entries);
|
||||||
|
|
||||||
if emit_vptr {
|
if emit_vptr {
|
||||||
let trait_ref = trait_ref.map_bound(|trait_ref| {
|
|
||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
|
||||||
});
|
|
||||||
entries.push(VtblEntry::TraitVPtr(trait_ref));
|
entries.push(VtblEntry::TraitVPtr(trait_ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,7 +707,8 @@ fn vtable_entries<'tcx>(
|
||||||
let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
|
let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
|
||||||
|
|
||||||
if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
|
if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
|
||||||
dump_vtable_entries(tcx, &entries);
|
let sp = tcx.def_span(trait_ref.def_id());
|
||||||
|
dump_vtable_entries(tcx, sp, trait_ref, &entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
tcx.arena.alloc_from_iter(entries.into_iter())
|
tcx.arena.alloc_from_iter(entries.into_iter())
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
//~^ error Vtable
|
|
||||||
//~^^ error Vtable
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
|
@ -15,11 +13,13 @@ trait B: A {
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait C: A {
|
trait C: A {
|
||||||
|
//~^ error Vtable
|
||||||
fn foo_c(&self) {}
|
fn foo_c(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait D: B + C {
|
trait D: B + C {
|
||||||
|
//~^ error Vtable
|
||||||
fn foo_d(&self) {}
|
fn foo_d(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,35 @@
|
||||||
error: Vtable Entries: [
|
error: Vtable entries for `<S as D>`: [
|
||||||
MetadataDropInPlace,
|
MetadataDropInPlace,
|
||||||
MetadataSize,
|
MetadataSize,
|
||||||
MetadataAlign,
|
MetadataAlign,
|
||||||
Method(
|
Method(<S as A>::foo_a),
|
||||||
DefId(0:4 ~ vtable_diamond[4564]::A::foo_a),
|
Method(<S as B>::foo_b),
|
||||||
[
|
Method(<S as C>::foo_c),
|
||||||
S,
|
TraitVPtr(<S as C>),
|
||||||
],
|
Method(<S as D>::foo_d),
|
||||||
),
|
|
||||||
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,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
--> $DIR/vtable-diamond.rs:21:1
|
||||||
|
|
|
||||||
|
LL | / trait D: B + C {
|
||||||
|
LL | |
|
||||||
|
LL | | fn foo_d(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: Vtable Entries: [
|
error: Vtable entries for `<S as C>`: [
|
||||||
MetadataDropInPlace,
|
MetadataDropInPlace,
|
||||||
MetadataSize,
|
MetadataSize,
|
||||||
MetadataAlign,
|
MetadataAlign,
|
||||||
Method(
|
Method(<S as A>::foo_a),
|
||||||
DefId(0:4 ~ vtable_diamond[4564]::A::foo_a),
|
Method(<S as C>::foo_c),
|
||||||
[
|
|
||||||
S,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Method(
|
|
||||||
DefId(0:8 ~ vtable_diamond[4564]::C::foo_c),
|
|
||||||
[
|
|
||||||
S,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
--> $DIR/vtable-diamond.rs:15:1
|
||||||
|
|
|
||||||
|
LL | / trait C: A {
|
||||||
|
LL | |
|
||||||
|
LL | | fn foo_c(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
//~^ error Vtable
|
|
||||||
//~^^ error Vtable
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
|
@ -10,11 +8,13 @@ trait A {
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait B {
|
trait B {
|
||||||
|
//~^ error Vtable
|
||||||
fn foo_b(&self) {}
|
fn foo_b(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_dump_vtable]
|
#[rustc_dump_vtable]
|
||||||
trait C: A + B {
|
trait C: A + B {
|
||||||
|
//~^ error Vtable
|
||||||
fn foo_c(&self) {}
|
fn foo_c(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,33 @@
|
||||||
error: Vtable Entries: [
|
error: Vtable entries for `<S as C>`: [
|
||||||
MetadataDropInPlace,
|
MetadataDropInPlace,
|
||||||
MetadataSize,
|
MetadataSize,
|
||||||
MetadataAlign,
|
MetadataAlign,
|
||||||
Method(
|
Method(<S as A>::foo_a),
|
||||||
DefId(0:4 ~ vtable_multiple[5246]::A::foo_a),
|
Method(<S as B>::foo_b),
|
||||||
[
|
TraitVPtr(<S as B>),
|
||||||
S,
|
Method(<S as C>::foo_c),
|
||||||
],
|
|
||||||
),
|
|
||||||
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,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
--> $DIR/vtable-multiple.rs:16:1
|
||||||
|
|
|
||||||
|
LL | / trait C: A + B {
|
||||||
|
LL | |
|
||||||
|
LL | | fn foo_c(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: Vtable Entries: [
|
error: Vtable entries for `<S as B>`: [
|
||||||
MetadataDropInPlace,
|
MetadataDropInPlace,
|
||||||
MetadataSize,
|
MetadataSize,
|
||||||
MetadataAlign,
|
MetadataAlign,
|
||||||
Method(
|
Method(<S as B>::foo_b),
|
||||||
DefId(0:6 ~ vtable_multiple[5246]::B::foo_b),
|
|
||||||
[
|
|
||||||
S,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
--> $DIR/vtable-multiple.rs:10:1
|
||||||
|
|
|
||||||
|
LL | / trait B {
|
||||||
|
LL | |
|
||||||
|
LL | | fn foo_b(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue