1 #![feature(rustc_private)]
5 extern crate rustc_codegen_utils;
6 extern crate rustc_driver;
7 extern crate rustc_errors;
8 extern crate rustc_hir;
9 extern crate rustc_interface;
10 extern crate rustc_metadata;
11 extern crate rustc_span;
16 use std::sync::{Arc, Mutex};
18 use rustc::ty::TyCtxt;
19 use rustc_driver::Compilation;
21 use rustc_hir::def_id::LOCAL_CRATE;
22 use rustc_hir::itemlikevisit;
23 use rustc_interface::{interface, Queries};
27 struct MiriCompilerCalls {
28 /// whether we are building for the host
32 impl rustc_driver::Callbacks for MiriCompilerCalls {
33 fn after_analysis<'tcx>(
35 compiler: &interface::Compiler,
36 queries: &'tcx Queries<'tcx>,
38 compiler.session().abort_if_errors();
39 queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
40 if std::env::args().any(|arg| arg == "--test") {
41 struct Visitor<'tcx>(TyCtxt<'tcx>);
42 impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> {
43 fn visit_item(&mut self, i: &'hir hir::Item) {
44 if let hir::ItemKind::Fn(.., body_id) = i.kind {
47 .any(|attr| attr.check_name(rustc_span::symbol::sym::test))
49 let config = MiriConfig::default();
50 let did = self.0.hir().body_owner_def_id(body_id);
51 println!("running test: {}", self.0.def_path_debug_str(did));
52 miri::eval_main(self.0, did, config);
53 self.0.sess.abort_if_errors();
57 fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
58 fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
60 tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
61 } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
62 let config = MiriConfig::default();
63 miri::eval_main(tcx, entry_def_id, config);
65 compiler.session().abort_if_errors();
67 println!("no main function found, assuming auxiliary build");
71 // Continue execution on host target
72 if self.host_target { Compilation::Continue } else { Compilation::Stop }
77 let path = option_env!("MIRI_RUSTC_TEST").map(String::from).unwrap_or_else(|| {
78 std::env::var("MIRI_RUSTC_TEST")
79 .expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
82 let mut mir_not_found = Vec::new();
83 let mut crate_not_found = Vec::new();
85 let mut failed = Vec::new();
86 let mut c_abi_fns = Vec::new();
87 let mut abi = Vec::new();
88 let mut unsupported = Vec::new();
89 let mut unimplemented_intrinsic = Vec::new();
90 let mut limits = Vec::new();
91 let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
92 while let Some(file) = files.pop() {
93 let file = file.unwrap();
94 let path = file.path();
95 if file.metadata().unwrap().is_dir() {
96 if !path.to_str().unwrap().ends_with("auxiliary") {
97 // add subdirs recursively
98 files.extend(std::fs::read_dir(path).unwrap());
102 if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
105 let stderr = std::io::stderr();
106 write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
107 let mut host_target = false;
108 let mut args: Vec<String> = std::env::args()
110 if arg == "--miri_host_target" {
112 false // remove the flag, rustc doesn't know it
118 args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
120 args.push(path.display().to_string());
122 let sysroot_flag = String::from("--sysroot");
123 if !args.contains(&sysroot_flag) {
124 args.push(sysroot_flag);
126 Path::new(&std::env::var("HOME").unwrap())
134 // A threadsafe buffer for writing.
135 #[derive(Default, Clone)]
136 struct BufWriter(Arc<Mutex<Vec<u8>>>);
138 impl Write for BufWriter {
139 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
140 self.0.lock().unwrap().write(buf)
142 fn flush(&mut self) -> io::Result<()> {
143 self.0.lock().unwrap().flush()
146 let buf = BufWriter::default();
147 let output = buf.clone();
148 let result = std::panic::catch_unwind(|| {
149 let _ = rustc_driver::run_compiler(
151 &mut MiriCompilerCalls { host_target },
160 writeln!(stderr.lock(), "ok").unwrap()
163 let output = output.0.lock().unwrap();
164 let output_err = std::str::from_utf8(&output).unwrap();
165 if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
166 let end = text.find('`').unwrap();
167 mir_not_found.push(text[..end].to_string());
168 writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
169 } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
170 let end = text.find('`').unwrap();
171 crate_not_found.push(text[..end].to_string());
172 writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
174 for text in output_err.split("error: ").skip(1) {
175 let end = text.find('\n').unwrap_or(text.len());
176 let c_abi = "can't call C ABI function: ";
177 let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
178 let unsupported_s = "miri does not support ";
179 let abi_s = "can't handle function with ";
180 let limit_s = "reached the configured maximum ";
181 if text.starts_with(c_abi) {
182 c_abi_fns.push(text[c_abi.len()..end].to_string());
183 } else if text.starts_with(unimplemented_intrinsic_s) {
184 unimplemented_intrinsic
185 .push(text[unimplemented_intrinsic_s.len()..end].to_string());
186 } else if text.starts_with(unsupported_s) {
187 unsupported.push(text[unsupported_s.len()..end].to_string());
188 } else if text.starts_with(abi_s) {
189 abi.push(text[abi_s.len()..end].to_string());
190 } else if text.starts_with(limit_s) {
191 limits.push(text[limit_s.len()..end].to_string());
192 } else if text.find("aborting").is_none() {
193 failed.push(text[..end].to_string());
196 writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
201 let stderr = std::io::stderr();
202 let mut stderr = stderr.lock();
205 "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic",
208 crate_not_found.len(),
213 unimplemented_intrinsic.len()
216 writeln!(stderr, "# The \"other reasons\" errors").unwrap();
217 writeln!(stderr, "(sorted, deduplicated)").unwrap();
218 print_vec(&mut stderr, failed);
220 writeln!(stderr, "# can't call C ABI function").unwrap();
221 print_vec(&mut stderr, c_abi_fns);
223 writeln!(stderr, "# unsupported ABI").unwrap();
224 print_vec(&mut stderr, abi);
226 writeln!(stderr, "# unsupported").unwrap();
227 print_vec(&mut stderr, unsupported);
229 writeln!(stderr, "# unimplemented intrinsics").unwrap();
230 print_vec(&mut stderr, unimplemented_intrinsic);
232 writeln!(stderr, "# mir not found").unwrap();
233 print_vec(&mut stderr, mir_not_found);
235 writeln!(stderr, "# crate not found").unwrap();
236 print_vec(&mut stderr, crate_not_found);
239 fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
240 writeln!(stderr, "```").unwrap();
241 for (n, s) in vec_to_hist(v).into_iter().rev() {
242 writeln!(stderr, "{:4} {}", n, s).unwrap();
244 writeln!(stderr, "```").unwrap();
247 fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
249 let mut v = v.into_iter();
250 let mut result = Vec::new();
251 let mut current = v.next();
252 'outer: while let Some(current_val) = current {
255 if next == current_val {
258 result.push((n, current_val));
259 current = Some(next);
263 result.push((n, current_val));