]> git.lizzy.rs Git - rust.git/blob - src/bin/miri-rustc-tests.rs
avoid using unchecked casts or arithmetic
[rust.git] / src / bin / miri-rustc-tests.rs
1 #![feature(rustc_private)]
2 extern crate getopts;
3 extern crate miri;
4 extern crate rustc;
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;
12
13 use std::io;
14 use std::io::Write;
15 use std::path::Path;
16 use std::sync::{Arc, Mutex};
17
18 use rustc::ty::TyCtxt;
19 use rustc_driver::Compilation;
20 use rustc_hir as hir;
21 use rustc_hir::def_id::LOCAL_CRATE;
22 use rustc_hir::itemlikevisit;
23 use rustc_interface::{interface, Queries};
24
25 use miri::MiriConfig;
26
27 struct MiriCompilerCalls {
28     /// whether we are building for the host
29     host_target: bool,
30 }
31
32 impl rustc_driver::Callbacks for MiriCompilerCalls {
33     fn after_analysis<'tcx>(
34         &mut self,
35         compiler: &interface::Compiler,
36         queries: &'tcx Queries<'tcx>,
37     ) -> Compilation {
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 {
45                             if i.attrs
46                                 .iter()
47                                 .any(|attr| attr.check_name(rustc_span::symbol::sym::test))
48                             {
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();
54                             }
55                         }
56                     }
57                     fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
58                     fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
59                 }
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);
64
65                 compiler.session().abort_if_errors();
66             } else {
67                 println!("no main function found, assuming auxiliary build");
68             }
69         });
70
71         // Continue execution on host target
72         if self.host_target { Compilation::Continue } else { Compilation::Stop }
73     }
74 }
75
76 fn main() {
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")
80     });
81
82     let mut mir_not_found = Vec::new();
83     let mut crate_not_found = Vec::new();
84     let mut success = 0;
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());
99             }
100             continue;
101         }
102         if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
103             continue;
104         }
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()
109             .filter(|arg| {
110                 if arg == "--miri_host_target" {
111                     host_target = true;
112                     false // remove the flag, rustc doesn't know it
113                 } else {
114                     true
115                 }
116             })
117             .collect();
118         args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
119         // file to process
120         args.push(path.display().to_string());
121
122         let sysroot_flag = String::from("--sysroot");
123         if !args.contains(&sysroot_flag) {
124             args.push(sysroot_flag);
125             args.push(
126                 Path::new(&std::env::var("HOME").unwrap())
127                     .join(".xargo")
128                     .join("HOST")
129                     .display()
130                     .to_string(),
131             );
132         }
133
134         // A threadsafe buffer for writing.
135         #[derive(Default, Clone)]
136         struct BufWriter(Arc<Mutex<Vec<u8>>>);
137
138         impl Write for BufWriter {
139             fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
140                 self.0.lock().unwrap().write(buf)
141             }
142             fn flush(&mut self) -> io::Result<()> {
143                 self.0.lock().unwrap().flush()
144             }
145         }
146         let buf = BufWriter::default();
147         let output = buf.clone();
148         let result = std::panic::catch_unwind(|| {
149             let _ = rustc_driver::run_compiler(
150                 &args,
151                 &mut MiriCompilerCalls { host_target },
152                 None,
153                 Some(Box::new(buf)),
154             );
155         });
156
157         match result {
158             Ok(()) => {
159                 success += 1;
160                 writeln!(stderr.lock(), "ok").unwrap()
161             }
162             Err(_) => {
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();
173                 } else {
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());
194                         }
195                     }
196                     writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
197                 }
198             }
199         }
200     }
201     let stderr = std::io::stderr();
202     let mut stderr = stderr.lock();
203     writeln!(
204         stderr,
205         "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic",
206         success,
207         mir_not_found.len(),
208         crate_not_found.len(),
209         failed.len(),
210         c_abi_fns.len(),
211         abi.len(),
212         unsupported.len(),
213         unimplemented_intrinsic.len()
214     )
215     .unwrap();
216     writeln!(stderr, "# The \"other reasons\" errors").unwrap();
217     writeln!(stderr, "(sorted, deduplicated)").unwrap();
218     print_vec(&mut stderr, failed);
219
220     writeln!(stderr, "# can't call C ABI function").unwrap();
221     print_vec(&mut stderr, c_abi_fns);
222
223     writeln!(stderr, "# unsupported ABI").unwrap();
224     print_vec(&mut stderr, abi);
225
226     writeln!(stderr, "# unsupported").unwrap();
227     print_vec(&mut stderr, unsupported);
228
229     writeln!(stderr, "# unimplemented intrinsics").unwrap();
230     print_vec(&mut stderr, unimplemented_intrinsic);
231
232     writeln!(stderr, "# mir not found").unwrap();
233     print_vec(&mut stderr, mir_not_found);
234
235     writeln!(stderr, "# crate not found").unwrap();
236     print_vec(&mut stderr, crate_not_found);
237 }
238
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();
243     }
244     writeln!(stderr, "```").unwrap();
245 }
246
247 fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
248     v.sort();
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 {
253         let mut n = 1;
254         for next in &mut v {
255             if next == current_val {
256                 n += 1;
257             } else {
258                 result.push((n, current_val));
259                 current = Some(next);
260                 continue 'outer;
261             }
262         }
263         result.push((n, current_val));
264         break;
265     }
266     result.sort();
267     result
268 }