//@ 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", "::drop", "DummyTrait::method", "::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::::is_some", "std::ptr::swap", " as std::iter::Iterator>::next", "core::num::::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(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(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 DummyTrait for T {{ fn method(&self) -> T {{ *self }} }} pub mod dummy {{ pub static mut PUBLIC_STATIC: Option = 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(()) }