mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
[StableMIR] API to retrieve definitions from crates
Add functions to retrieve function definitions and static items from all crates (local and external). For external crates, add a query to retrieve the number of defs in a foreign crate.
This commit is contained in:
parent
f61306d47b
commit
0ce579f6f3
@ -387,6 +387,7 @@ provide! { tcx, def_id, other, cdata,
|
|||||||
crate_hash => { cdata.root.header.hash }
|
crate_hash => { cdata.root.header.hash }
|
||||||
crate_host_hash => { cdata.host_hash }
|
crate_host_hash => { cdata.host_hash }
|
||||||
crate_name => { cdata.root.header.name }
|
crate_name => { cdata.root.header.name }
|
||||||
|
num_extern_def_ids => { cdata.num_def_ids() }
|
||||||
|
|
||||||
extra_filename => { cdata.root.extra_filename.clone() }
|
extra_filename => { cdata.root.extra_filename.clone() }
|
||||||
|
|
||||||
|
@ -1812,6 +1812,16 @@ rustc_queries! {
|
|||||||
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the number of definitions in a foreign crate.
|
||||||
|
///
|
||||||
|
/// This allows external tools to iterate over all definitions in a foreign crate.
|
||||||
|
///
|
||||||
|
/// This should never be used for the local crate, instead use `iter_local_def_id`.
|
||||||
|
query num_extern_def_ids(_: CrateNum) -> usize {
|
||||||
|
desc { "fetching the number of definitions in a crate" }
|
||||||
|
separate_provide_extern
|
||||||
|
}
|
||||||
|
|
||||||
query lib_features(_: CrateNum) -> &'tcx LibFeatures {
|
query lib_features(_: CrateNum) -> &'tcx LibFeatures {
|
||||||
desc { "calculating the lib features defined in a crate" }
|
desc { "calculating the lib features defined in a crate" }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
@ -34,7 +34,7 @@ use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, I
|
|||||||
|
|
||||||
use crate::rustc_internal::RustcInternal;
|
use crate::rustc_internal::RustcInternal;
|
||||||
use crate::rustc_smir::builder::BodyBuilder;
|
use crate::rustc_smir::builder::BodyBuilder;
|
||||||
use crate::rustc_smir::{Stable, Tables, alloc, new_item_kind, smir_crate};
|
use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
|
||||||
|
|
||||||
impl<'tcx> Context for TablesWrapper<'tcx> {
|
impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
fn target_info(&self) -> MachineInfo {
|
fn target_info(&self) -> MachineInfo {
|
||||||
@ -80,6 +80,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
let krate = crate_num.internal(&mut *tables, tcx);
|
||||||
|
filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
let krate = crate_num.internal(&mut *tables, tcx);
|
||||||
|
filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
|
||||||
|
}
|
||||||
|
|
||||||
fn foreign_module(
|
fn foreign_module(
|
||||||
&self,
|
&self,
|
||||||
mod_def: stable_mir::ty::ForeignModuleDef,
|
mod_def: stable_mir::ty::ForeignModuleDef,
|
||||||
|
@ -15,8 +15,8 @@ use rustc_middle::mir::interpret::AllocId;
|
|||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use stable_mir::abi::Layout;
|
use stable_mir::abi::Layout;
|
||||||
use stable_mir::mir::mono::InstanceDef;
|
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||||
use stable_mir::ty::{MirConstId, Span, TyConstId};
|
use stable_mir::ty::{FnDef, MirConstId, Span, TyConstId};
|
||||||
use stable_mir::{CtorKind, ItemKind};
|
use stable_mir::{CtorKind, ItemKind};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
@ -79,6 +79,36 @@ impl<'tcx> Tables<'tcx> {
|
|||||||
};
|
};
|
||||||
!must_override && self.tcx.is_mir_available(def_id)
|
!must_override && self.tcx.is_mir_available(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_fn_def(&mut self, def_id: DefId) -> Option<FnDef> {
|
||||||
|
if matches!(self.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
|
||||||
|
Some(self.fn_def(def_id))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_static(&mut self, def_id: DefId) -> Option<StaticDef> {
|
||||||
|
matches!(self.tcx.def_kind(def_id), DefKind::Static { .. }).then(|| self.static_def(def_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over the definitions of the given crate.
|
||||||
|
pub(crate) fn filter_def_ids<F, T>(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec<T>
|
||||||
|
where
|
||||||
|
F: FnMut(DefId) -> Option<T>,
|
||||||
|
{
|
||||||
|
if krate == LOCAL_CRATE {
|
||||||
|
tcx.iter_local_def_id().filter_map(|did| func(did.to_def_id())).collect()
|
||||||
|
} else {
|
||||||
|
let num_definitions = tcx.num_extern_def_ids(krate);
|
||||||
|
(0..num_definitions)
|
||||||
|
.filter_map(move |i| {
|
||||||
|
let def_id = DefId { krate, index: rustc_span::def_id::DefIndex::from_usize(i) };
|
||||||
|
func(def_id)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a stable mir crate from a given crate number.
|
/// Build a stable mir crate from a given crate number.
|
||||||
|
@ -34,6 +34,12 @@ pub trait Context {
|
|||||||
/// Check whether the body of a function is available.
|
/// Check whether the body of a function is available.
|
||||||
fn has_body(&self, item: DefId) -> bool;
|
fn has_body(&self, item: DefId) -> bool;
|
||||||
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
|
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
|
||||||
|
|
||||||
|
/// Retrieve all functions defined in this crate.
|
||||||
|
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>;
|
||||||
|
|
||||||
|
/// Retrieve all static items defined in this crate.
|
||||||
|
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>;
|
||||||
fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
|
fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
|
||||||
fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
|
fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
|
||||||
fn all_trait_decls(&self) -> TraitDecls;
|
fn all_trait_decls(&self) -> TraitDecls;
|
||||||
|
@ -25,8 +25,9 @@ use serde::Serialize;
|
|||||||
use crate::compiler_interface::with;
|
use crate::compiler_interface::with;
|
||||||
pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
|
pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
|
||||||
pub use crate::error::*;
|
pub use crate::error::*;
|
||||||
|
use crate::mir::mono::StaticDef;
|
||||||
use crate::mir::{Body, Mutability};
|
use crate::mir::{Body, Mutability};
|
||||||
use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
|
use crate::ty::{FnDef, ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
|
||||||
|
|
||||||
pub mod abi;
|
pub mod abi;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -96,6 +97,16 @@ impl Crate {
|
|||||||
pub fn trait_impls(&self) -> ImplTraitDecls {
|
pub fn trait_impls(&self) -> ImplTraitDecls {
|
||||||
with(|cx| cx.trait_impls(self.id))
|
with(|cx| cx.trait_impls(self.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a list of function definitions from this crate independent on their visibility.
|
||||||
|
pub fn fn_defs(&self) -> Vec<FnDef> {
|
||||||
|
with(|cx| cx.crate_functions(self.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a list of static items defined in this crate independent on their visibility.
|
||||||
|
pub fn statics(&self) -> Vec<StaticDef> {
|
||||||
|
with(|cx| cx.crate_statics(self.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
|
||||||
|
149
tests/ui-fulldeps/stable-mir/check_crate_defs.rs
Normal file
149
tests/ui-fulldeps/stable-mir/check_crate_defs.rs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
//@ run-pass
|
||||||
|
//! Test information about crate definitions (local and external).
|
||||||
|
|
||||||
|
//@ ignore-stage1
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
//@ ignore-remote
|
||||||
|
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
|
|
||||||
|
extern crate rustc_hir;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rustc_smir;
|
||||||
|
extern crate rustc_driver;
|
||||||
|
extern crate rustc_interface;
|
||||||
|
extern crate stable_mir;
|
||||||
|
|
||||||
|
use rustc_smir::rustc_internal;
|
||||||
|
use stable_mir::CrateDef;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
const CRATE_NAME: &str = "crate_defs";
|
||||||
|
|
||||||
|
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||||
|
fn test_stable_mir() -> ControlFlow<()> {
|
||||||
|
// Find items in the local crate.
|
||||||
|
let local = stable_mir::local_crate();
|
||||||
|
check_items(&local.statics(), &["PRIVATE_STATIC", "dummy::PUBLIC_STATIC"]);
|
||||||
|
check_items(
|
||||||
|
&local.fn_defs(),
|
||||||
|
&[
|
||||||
|
"top_level",
|
||||||
|
"dummy::public_fn",
|
||||||
|
"dummy::private_fn",
|
||||||
|
"dummy::PrivateStruct::new",
|
||||||
|
"<dummy::PrivateStruct as std::ops::Drop>::drop",
|
||||||
|
"DummyTrait::method",
|
||||||
|
"<T as DummyTrait>::method",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Find items inside core crate.
|
||||||
|
// FIXME: We are currently missing primitive type methods and trait implementations for external
|
||||||
|
// crates.
|
||||||
|
let core = stable_mir::find_crates("core").pop().expect("Cannot find `core` crate");
|
||||||
|
contains(
|
||||||
|
&core.fn_defs(),
|
||||||
|
&[
|
||||||
|
"std::fmt::Debug::fmt",
|
||||||
|
"std::option::Option::<T>::is_some",
|
||||||
|
"std::ptr::swap",
|
||||||
|
"<std::slice::Iter<'a, T> as std::iter::Iterator>::next",
|
||||||
|
"core::num::<impl u8>::abs_diff",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// Ensure nothing crashes. There is no public static in core that we can test here.
|
||||||
|
let _ = core.statics();
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the list of definitions matches the expected list.
|
||||||
|
/// Note that order doesn't matter.
|
||||||
|
fn check_items<T: CrateDef>(items: &[T], expected: &[&str]) {
|
||||||
|
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
|
||||||
|
let item_names: HashSet<_> = items.iter().map(|item| item.name()).collect();
|
||||||
|
assert_eq!(item_names, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that the list contains the expected items.
|
||||||
|
fn contains<T: CrateDef + std::fmt::Debug>(items: &[T], expected: &[&str]) {
|
||||||
|
let expected: HashSet<_> = expected.iter().map(|s| s.to_string()).collect();
|
||||||
|
let item_names = items.iter().map(|item| item.name()).collect();
|
||||||
|
let not_found: Vec<_> = expected.difference(&item_names).collect();
|
||||||
|
assert!(not_found.is_empty(), "Missing items: {:?}", not_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This test will generate and analyze a dummy crate using the stable mir.
|
||||||
|
/// For that, it will first write the dummy crate into a file.
|
||||||
|
/// Then it will create a `StableMir` using custom arguments and then
|
||||||
|
/// it will run the compiler.
|
||||||
|
fn main() {
|
||||||
|
let path = "crate_definitions.rs";
|
||||||
|
generate_input(&path).unwrap();
|
||||||
|
let args = vec![
|
||||||
|
"rustc".to_string(),
|
||||||
|
"--crate-type=lib".to_string(),
|
||||||
|
"--crate-name".to_string(),
|
||||||
|
CRATE_NAME.to_string(),
|
||||||
|
path.to_string(),
|
||||||
|
];
|
||||||
|
run!(args, test_stable_mir).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
|
let mut file = std::fs::File::create(path)?;
|
||||||
|
write!(
|
||||||
|
file,
|
||||||
|
r#"
|
||||||
|
#![allow(dead_code, unused_variables)]
|
||||||
|
static PRIVATE_STATIC: u8 = 0;
|
||||||
|
fn top_level() -> &'static str {{
|
||||||
|
"hello"
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub trait DummyTrait {{
|
||||||
|
fn method(&self) -> Self;
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl<T: Copy> DummyTrait for T {{
|
||||||
|
fn method(&self) -> T {{
|
||||||
|
*self
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub mod dummy {{
|
||||||
|
pub static mut PUBLIC_STATIC: Option<char> = None;
|
||||||
|
|
||||||
|
pub fn public_fn(input: bool) -> bool {{
|
||||||
|
private_fn(!input)
|
||||||
|
}}
|
||||||
|
|
||||||
|
fn private_fn(input: bool) -> bool {{
|
||||||
|
todo!()
|
||||||
|
}}
|
||||||
|
|
||||||
|
struct PrivateStruct {{
|
||||||
|
field: u32,
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl PrivateStruct {{
|
||||||
|
fn new() -> Self {{
|
||||||
|
Self {{ field: 42 }}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Drop for PrivateStruct {{
|
||||||
|
fn drop(&mut self) {{
|
||||||
|
println!("Dropping PrivateStruct");
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user