1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
//@ 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)]
#![feature(control_flow_enum)]
#[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(())
}
|