mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #152669 - makai410:rpub-vtable, r=celinval
rustc_public: add `vtable_entries()` to `TraitRef` Resolves: https://github.com/rust-lang/project-stable-mir/issues/103
This commit is contained in:
@@ -20,7 +20,8 @@
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
|
||||
ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
|
||||
Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
|
||||
TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
|
||||
TraitDecl, TraitDef, TraitRef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
|
||||
VtblEntry,
|
||||
};
|
||||
use crate::unstable::{RustcInternal, Stable, new_item_kind};
|
||||
use crate::{
|
||||
@@ -838,6 +839,25 @@ pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
|
||||
let did = tables[def_id];
|
||||
cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect()
|
||||
}
|
||||
|
||||
/// Get all vtable entries of a trait.
|
||||
pub(crate) fn vtable_entries(&self, trait_ref: &TraitRef) -> Vec<VtblEntry> {
|
||||
let mut tables = self.tables.borrow_mut();
|
||||
let cx = &*self.cx.borrow();
|
||||
cx.vtable_entries(trait_ref.internal(&mut *tables, cx.tcx))
|
||||
.iter()
|
||||
.map(|v| v.stable(&mut *tables, cx))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns the vtable entry at the given index.
|
||||
///
|
||||
/// Returns `None` if the index is out of bounds.
|
||||
pub(crate) fn vtable_entry(&self, trait_ref: &TraitRef, idx: usize) -> Option<VtblEntry> {
|
||||
let mut tables = self.tables.borrow_mut();
|
||||
let cx = &*self.cx.borrow();
|
||||
cx.vtable_entry(trait_ref.internal(&mut *tables, cx.tcx), idx).stable(&mut *tables, cx)
|
||||
}
|
||||
}
|
||||
|
||||
// A thread local variable that stores a pointer to [`CompilerInterface`].
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use crate::abi::{FnAbi, Layout};
|
||||
use crate::crate_def::{CrateDef, CrateDefType};
|
||||
use crate::mir::alloc::{AllocId, read_target_int, read_target_uint};
|
||||
use crate::mir::mono::StaticDef;
|
||||
use crate::mir::mono::{Instance, StaticDef};
|
||||
use crate::target::MachineInfo;
|
||||
use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex};
|
||||
|
||||
@@ -1440,6 +1440,18 @@ pub fn self_ty(&self) -> Ty {
|
||||
};
|
||||
self_ty
|
||||
}
|
||||
|
||||
/// Retrieve all vtable entries.
|
||||
pub fn vtable_entries(&self) -> Vec<VtblEntry> {
|
||||
with(|cx| cx.vtable_entries(self))
|
||||
}
|
||||
|
||||
/// Returns the vtable entry at the given index.
|
||||
///
|
||||
/// Returns `None` if the index is out of bounds.
|
||||
pub fn vtable_entry(&self, idx: usize) -> Option<VtblEntry> {
|
||||
with(|cx| cx.vtable_entry(self, idx))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
@@ -1656,3 +1668,19 @@ pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum VtblEntry {
|
||||
/// destructor of this type (used in vtable header)
|
||||
MetadataDropInPlace,
|
||||
/// layout size of this type (used in vtable header)
|
||||
MetadataSize,
|
||||
/// layout align of this type (used in vtable header)
|
||||
MetadataAlign,
|
||||
/// non-dispatchable associated function that is excluded from trait object
|
||||
Vacant,
|
||||
/// dispatchable associated function
|
||||
Method(Instance),
|
||||
/// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
|
||||
TraitVPtr(TraitRef),
|
||||
}
|
||||
|
||||
@@ -1139,3 +1139,25 @@ fn stable<'cx>(
|
||||
crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_middle::ty::VtblEntry<'tcx> {
|
||||
type T = crate::ty::VtblEntry;
|
||||
|
||||
fn stable<'cx>(
|
||||
&self,
|
||||
tables: &mut Tables<'cx, BridgeTys>,
|
||||
cx: &CompilerCtxt<'cx, BridgeTys>,
|
||||
) -> Self::T {
|
||||
use crate::ty::VtblEntry;
|
||||
match self {
|
||||
ty::VtblEntry::MetadataDropInPlace => VtblEntry::MetadataDropInPlace,
|
||||
ty::VtblEntry::MetadataSize => VtblEntry::MetadataSize,
|
||||
ty::VtblEntry::MetadataAlign => VtblEntry::MetadataAlign,
|
||||
ty::VtblEntry::Vacant => VtblEntry::Vacant,
|
||||
ty::VtblEntry::Method(instance) => VtblEntry::Method(instance.stable(tables, cx)),
|
||||
ty::VtblEntry::TraitVPtr(trait_ref) => {
|
||||
VtblEntry::TraitVPtr(trait_ref.stable(tables, cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder,
|
||||
ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List,
|
||||
PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy,
|
||||
ValTree, VariantDef,
|
||||
ValTree, VariantDef, VtblEntry,
|
||||
};
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_session::cstore::ForeignModule;
|
||||
@@ -757,4 +757,16 @@ pub fn associated_items(&self, def_id: DefId) -> Vec<AssocItem> {
|
||||
};
|
||||
assoc_items
|
||||
}
|
||||
|
||||
/// Get all vtable entries of a trait.
|
||||
pub fn vtable_entries(&self, trait_ref: TraitRef<'tcx>) -> Vec<VtblEntry<'tcx>> {
|
||||
self.tcx.vtable_entries(trait_ref).to_vec()
|
||||
}
|
||||
|
||||
/// Returns the vtable entry at the given index.
|
||||
///
|
||||
/// Returns `None` if the index is out of bounds.
|
||||
pub fn vtable_entry(&self, trait_ref: TraitRef<'tcx>, idx: usize) -> Option<VtblEntry<'tcx>> {
|
||||
self.vtable_entries(trait_ref).get(idx).copied()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
//@ run-pass
|
||||
// Test that users are able to use rustc_public to retrieve vtable info.
|
||||
|
||||
//@ ignore-stage1
|
||||
//@ ignore-cross-compile
|
||||
//@ ignore-remote
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
#[macro_use]
|
||||
extern crate rustc_public;
|
||||
|
||||
use rustc_public::ty::VtblEntry;
|
||||
use rustc_public::CrateDef;
|
||||
use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
const CRATE_NAME: &str = "vtable_test";
|
||||
|
||||
/// This function uses the rustc_public APIs to test the `vtable_entries()`.
|
||||
fn test_vtable_entries() -> ControlFlow<()> {
|
||||
let local_crate = rustc_public::local_crate();
|
||||
let local_impls = local_crate.trait_impls();
|
||||
let child_impl = local_impls
|
||||
.iter()
|
||||
.find(|i| i.trimmed_name() == "<Concrete as Child>")
|
||||
.expect("Could not find <Concrete as Child>");
|
||||
|
||||
let child_trait_ref = child_impl.trait_impl().value;
|
||||
let entries = child_trait_ref.vtable_entries();
|
||||
match &entries[..] {
|
||||
[
|
||||
VtblEntry::MetadataDropInPlace,
|
||||
VtblEntry::MetadataSize,
|
||||
VtblEntry::MetadataAlign,
|
||||
VtblEntry::Method(primary),
|
||||
VtblEntry::Method(secondary),
|
||||
VtblEntry::TraitVPtr(secondary_vptr),
|
||||
VtblEntry::Method(child),
|
||||
] => {
|
||||
assert!(
|
||||
primary.name().contains("primary"),
|
||||
"Expected primary method at index 3"
|
||||
);
|
||||
assert!(
|
||||
secondary.name().contains("secondary"),
|
||||
"Expected secondary method at index 4"
|
||||
);
|
||||
let vptr_str = secondary_vptr.def_id.name();
|
||||
assert!(
|
||||
vptr_str.contains("Secondary"),
|
||||
"Expected Secondary VPtr at index 5"
|
||||
);
|
||||
assert!(
|
||||
child.name().contains("child"),
|
||||
"Expected child method at index 6"
|
||||
);
|
||||
}
|
||||
_ => panic!(
|
||||
"Unexpected vtable layout for <Concrete as Child>. Found: {:#?}",
|
||||
entries
|
||||
),
|
||||
}
|
||||
let vacant_impl = local_impls
|
||||
.iter()
|
||||
.find(|i| i.trimmed_name() == "<Concrete as WithVacant>")
|
||||
.expect("Could not find <Concrete as WithVacant>");
|
||||
let vacant_trait_ref = vacant_impl.trait_impl().value;
|
||||
let vacant_entries = vacant_trait_ref.vtable_entries();
|
||||
match &vacant_entries[..] {
|
||||
[
|
||||
VtblEntry::MetadataDropInPlace,
|
||||
VtblEntry::MetadataSize,
|
||||
VtblEntry::MetadataAlign,
|
||||
VtblEntry::Method(valid),
|
||||
] => {
|
||||
assert!(valid.name().contains("valid"), "Expected valid method");
|
||||
}
|
||||
_ => panic!(
|
||||
"Unexpected vtable layout for <Concrete as WithVacant>. Found: {:#?}",
|
||||
vacant_entries
|
||||
),
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = "vtable_input.rs";
|
||||
generate_input(&path).unwrap();
|
||||
let args = &[
|
||||
"rustc".to_string(),
|
||||
"--crate-type=lib".to_string(),
|
||||
"--crate-name".to_string(),
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, test_vtable_entries).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
let mut file = std::fs::File::create(path)?;
|
||||
write!(
|
||||
file,
|
||||
r#"
|
||||
pub struct Concrete;
|
||||
|
||||
pub trait Primary {{
|
||||
fn primary(&self);
|
||||
}}
|
||||
|
||||
pub trait Secondary {{
|
||||
fn secondary(&self);
|
||||
}}
|
||||
|
||||
pub trait Child: Primary + Secondary {{
|
||||
fn child(&self);
|
||||
}}
|
||||
|
||||
impl Primary for Concrete {{
|
||||
fn primary(&self) {{}}
|
||||
}}
|
||||
|
||||
impl Secondary for Concrete {{
|
||||
fn secondary(&self) {{}}
|
||||
}}
|
||||
|
||||
impl Child for Concrete {{
|
||||
fn child(&self) {{}}
|
||||
}}
|
||||
|
||||
pub trait WithVacant {{
|
||||
fn valid(&self);
|
||||
|
||||
fn excluded<T>(&self, meow: T) where Self: Sized;
|
||||
}}
|
||||
|
||||
impl WithVacant for Concrete {{
|
||||
fn valid(&self) {{}}
|
||||
fn excluded<T>(&self, meow: T) {{}}
|
||||
}}
|
||||
|
||||
fn main() {{}}
|
||||
"#
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user