142 lines
4.6 KiB
Rust
142 lines
4.6 KiB
Rust
//@ run-pass
|
|
//! Test that users are able to use stable mir APIs to retrieve information about crate definitions.
|
|
|
|
//@ ignore-stage1
|
|
//@ ignore-cross-compile
|
|
//@ ignore-remote
|
|
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
|
//@ edition: 2021
|
|
|
|
#![feature(rustc_private)]
|
|
#![feature(assert_matches)]
|
|
|
|
#[macro_use]
|
|
extern crate rustc_smir;
|
|
extern crate rustc_driver;
|
|
extern crate rustc_interface;
|
|
extern crate stable_mir;
|
|
|
|
use std::assert_matches::assert_matches;
|
|
use mir::{mono::Instance, TerminatorKind::*};
|
|
use stable_mir::mir::mono::InstanceKind;
|
|
use rustc_smir::rustc_internal;
|
|
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
|
|
use stable_mir::*;
|
|
use std::io::Write;
|
|
use std::ops::ControlFlow;
|
|
|
|
const CRATE_NAME: &str = "input";
|
|
|
|
/// This function uses the Stable MIR APIs to get information about the test crate.
|
|
fn test_stable_mir() -> ControlFlow<()> {
|
|
let entry = stable_mir::entry_fn().unwrap();
|
|
let main_fn = Instance::try_from(entry).unwrap();
|
|
assert_eq!(main_fn.name(), "main");
|
|
assert_eq!(main_fn.trimmed_name(), "main");
|
|
|
|
let instances = get_instances(main_fn.body().unwrap());
|
|
assert_eq!(instances.len(), 3);
|
|
test_fn(instances[0], "from_u32", "std::char::from_u32", "core");
|
|
test_fn(instances[1], "Vec::<u8>::new", "std::vec::Vec::<u8>::new", "alloc");
|
|
test_fn(instances[2], "ctpop::<u8>", "std::intrinsics::ctpop::<u8>", "core");
|
|
test_vec_new(instances[1]);
|
|
ControlFlow::Continue(())
|
|
}
|
|
|
|
fn test_fn(instance: Instance, expected_trimmed: &str, expected_qualified: &str, krate: &str) {
|
|
let trimmed = instance.trimmed_name();
|
|
let qualified = instance.name();
|
|
assert_eq!(&trimmed, expected_trimmed);
|
|
assert_eq!(&qualified, expected_qualified);
|
|
|
|
if instance.kind == InstanceKind::Intrinsic {
|
|
let intrinsic = instance.intrinsic_name().unwrap();
|
|
let (trimmed_base, _trimmed_args) = trimmed.split_once("::").unwrap();
|
|
assert_eq!(intrinsic, trimmed_base);
|
|
return;
|
|
}
|
|
assert!(instance.intrinsic_name().is_none());
|
|
|
|
let item = CrateItem::try_from(instance).unwrap();
|
|
let trimmed = item.trimmed_name();
|
|
let qualified = item.name();
|
|
assert_eq!(trimmed, expected_trimmed.replace("u8", "T"));
|
|
assert_eq!(qualified, expected_qualified.replace("u8", "T"));
|
|
assert_eq!(&item.krate().name, krate);
|
|
}
|
|
|
|
fn extract_elem_ty(ty: Ty) -> Ty {
|
|
match ty.kind() {
|
|
TyKind::RigidTy(RigidTy::Adt(_, args)) => {
|
|
*args.0[0].expect_ty()
|
|
}
|
|
_ => unreachable!("Expected Vec ADT, but found: {ty:?}")
|
|
}
|
|
}
|
|
|
|
/// Check signature and type of `Vec::<u8>::new` and its generic version.
|
|
fn test_vec_new(instance: mir::mono::Instance) {
|
|
let sig = instance.fn_abi().unwrap();
|
|
assert_eq!(&sig.args, &[]);
|
|
let elem_ty = extract_elem_ty(sig.ret.ty);
|
|
assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8)));
|
|
|
|
// Get the signature for Vec::<T>::new.
|
|
let item = CrateItem::try_from(instance).unwrap();
|
|
let ty = item.ty();
|
|
let gen_sig = ty.kind().fn_sig().unwrap().skip_binder();
|
|
let gen_ty = extract_elem_ty(gen_sig.output());
|
|
assert_matches!(gen_ty.kind(), TyKind::Param(_));
|
|
}
|
|
|
|
/// Inspect the instance body
|
|
fn get_instances(body: mir::Body) -> Vec<Instance> {
|
|
body.blocks.iter().filter_map(|bb| {
|
|
match &bb.terminator.kind {
|
|
Call { func, .. } => {
|
|
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable!
|
|
() };
|
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
|
Instance::resolve(def, &args).ok()
|
|
}
|
|
_ => {
|
|
None
|
|
}
|
|
}
|
|
}).collect::<Vec<_>>()
|
|
}
|
|
|
|
/// 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 = "defs_input.rs";
|
|
generate_input(&path).unwrap();
|
|
let args = vec![
|
|
"rustc".to_string(),
|
|
"-Cpanic=abort".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#"
|
|
#![feature(core_intrinsics)]
|
|
|
|
fn main() {{
|
|
let _c = core::char::from_u32(99);
|
|
let _v = Vec::<u8>::new();
|
|
let _i = std::intrinsics::ctpop::<u8>(0);
|
|
}}
|
|
"#
|
|
)?;
|
|
Ok(())
|
|
}
|