forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcheck_defs.rs
141 lines (124 loc) · 4.53 KB
/
check_defs.rs
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
//@ 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
//@ edition: 2021
#![feature(rustc_private)]
#![feature(assert_matches)]
extern crate rustc_middle;
#[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(())
}