]> git.lizzy.rs Git - rust.git/blob - tests/compiletest.rs
Address things complained about by clippy
[rust.git] / tests / compiletest.rs
1 extern crate compiletest_rs as compiletest;
2
3 use std::path::{PathBuf, Path};
4 use std::io::Write;
5
6 fn compile_fail(sysroot: &Path) {
7     let flags = format!("--sysroot {} -Dwarnings", sysroot.to_str().expect("non utf8 path"));
8     for_all_targets(sysroot, |target| {
9         let mut config = compiletest::default_config();
10         config.host_rustcflags = Some(flags.clone());
11         config.mode = "compile-fail".parse().expect("Invalid mode");
12         config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
13         config.rustc_path = "target/debug/miri".into();
14         config.src_base = PathBuf::from("tests/compile-fail".to_string());
15         config.target = target.to_owned();
16         config.target_rustcflags = Some(flags.clone());
17         compiletest::run_tests(&config);
18     });
19 }
20
21 fn run_pass() {
22     let mut config = compiletest::default_config();
23     config.mode = "run-pass".parse().expect("Invalid mode");
24     config.src_base = PathBuf::from("tests/run-pass".to_string());
25     config.target_rustcflags = Some("-Dwarnings".to_string());
26     config.host_rustcflags = Some("-Dwarnings".to_string());
27     compiletest::run_tests(&config);
28 }
29
30 fn miri_pass(path: &str, target: &str, host: &str) {
31     let mut config = compiletest::default_config();
32     config.mode = "mir-opt".parse().expect("Invalid mode");
33     config.src_base = PathBuf::from(path);
34     config.target = target.to_owned();
35     config.host = host.to_owned();
36     config.rustc_path = PathBuf::from("target/debug/miri");
37     // don't actually execute the final binary, it might be for other targets and we only care
38     // about running miri, not the binary.
39     config.runtool = Some("echo \"\" || ".to_owned());
40     if target == host {
41         std::env::set_var("MIRI_HOST_TARGET", "yes");
42     }
43     compiletest::run_tests(&config);
44     std::env::set_var("MIRI_HOST_TARGET", "");
45 }
46
47 fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
48     let mut path = path.into();
49     path.push("lib");
50     path.metadata().map(|m| m.is_dir()).unwrap_or(false)
51 }
52
53 fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
54     let target_dir = sysroot.join("lib").join("rustlib");
55     println!("target dir: {}", target_dir.to_str().unwrap());
56     for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
57         let entry = entry.unwrap();
58         if !is_target_dir(entry.path()) { continue; }
59         let target = entry.file_name().into_string().unwrap();
60         let stderr = std::io::stderr();
61         writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
62         f(target);
63     }
64 }
65
66 #[test]
67 fn compile_test() {
68     let sysroot = std::process::Command::new("rustc")
69         .arg("--print")
70         .arg("sysroot")
71         .output()
72         .expect("rustc not found")
73         .stdout;
74     let sysroot = std::str::from_utf8(&sysroot).expect("sysroot is not utf8").trim();
75     let sysroot = &Path::new(&sysroot);
76     let host = std::process::Command::new("rustc")
77         .arg("-vV")
78         .output()
79         .expect("rustc not found for -vV")
80         .stdout;
81     let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
82     let host = host.split("\nhost: ").nth(1).expect("no host: part in rustc -vV");
83     let host = host.split('\n').next().expect("no \n after host");
84
85     if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
86         let mut mir_not_found = Vec::new();
87         let mut crate_not_found = Vec::new();
88         let mut success = 0;
89         let mut failed = Vec::new();
90         let mut c_abi_fns = Vec::new();
91         let mut abi = Vec::new();
92         let mut unsupported = Vec::new();
93         let mut unimplemented_intrinsic = Vec::new();
94         let mut limits = Vec::new();
95         let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
96         while let Some(file) = files.pop() {
97             let file = file.unwrap();
98             let path = file.path();
99             if file.metadata().unwrap().is_dir() {
100                 if !path.to_str().unwrap().ends_with("auxiliary") {
101                     // add subdirs recursively
102                     files.extend(std::fs::read_dir(path).unwrap());
103                 }
104                 continue;
105             }
106             if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
107                 continue;
108             }
109             let stderr = std::io::stderr();
110             write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
111             let mut cmd = std::process::Command::new("target/debug/miri");
112             cmd.arg(path);
113             let libs = Path::new(&sysroot).join("lib");
114             let sysroot = libs.join("rustlib").join(&host).join("lib");
115             let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
116             cmd.env(compiletest::procsrv::dylib_env_var(), paths);
117
118             match cmd.output() {
119                 Ok(ref output) if output.status.success() => {
120                     success += 1;
121                     writeln!(stderr.lock(), "ok").unwrap()
122                 },
123                 Ok(output) => {
124                     let output_err = std::str::from_utf8(&output.stderr).unwrap();
125                     if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
126                         let end = text.find('`').unwrap();
127                         mir_not_found.push(text[..end].to_string());
128                         writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
129                     } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
130                         let end = text.find('`').unwrap();
131                         crate_not_found.push(text[..end].to_string());
132                         writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
133                     } else {
134                         for text in output_err.split("error: ").skip(1) {
135                             let end = text.find('\n').unwrap_or(text.len());
136                             let c_abi = "can't call C ABI function: ";
137                             let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
138                             let unsupported_s = "miri does not support ";
139                             let abi_s = "can't handle function with ";
140                             let limit_s = "reached the configured maximum ";
141                             if text.starts_with(c_abi) {
142                                 c_abi_fns.push(text[c_abi.len()..end].to_string());
143                             } else if text.starts_with(unimplemented_intrinsic_s) {
144                                 unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
145                             } else if text.starts_with(unsupported_s) {
146                                 unsupported.push(text[unsupported_s.len()..end].to_string());
147                             } else if text.starts_with(abi_s) {
148                                 abi.push(text[abi_s.len()..end].to_string());
149                             } else if text.starts_with(limit_s) {
150                                 limits.push(text[limit_s.len()..end].to_string());
151                             } else if text.find("aborting").is_none() {
152                                 failed.push(text[..end].to_string());
153                             }
154                         }
155                         writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
156                         writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
157                         writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
158                     }
159                 }
160                 Err(e) => {
161                     writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
162                     panic!("failed to execute miri");
163                 },
164             }
165         }
166         let stderr = std::io::stderr();
167         let mut stderr = stderr.lock();
168         writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
169                           {} C fn, {} ABI, {} unsupported, {} intrinsic",
170                           success, mir_not_found.len(), crate_not_found.len(), failed.len(),
171                           c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
172         writeln!(stderr, "# The \"other reasons\" errors").unwrap();
173         writeln!(stderr, "(sorted, deduplicated)").unwrap();
174         print_vec(&mut stderr, failed);
175
176         writeln!(stderr, "# can't call C ABI function").unwrap();
177         print_vec(&mut stderr, c_abi_fns);
178
179         writeln!(stderr, "# unsupported ABI").unwrap();
180         print_vec(&mut stderr, abi);
181
182         writeln!(stderr, "# unsupported").unwrap();
183         print_vec(&mut stderr, unsupported);
184
185         writeln!(stderr, "# unimplemented intrinsics").unwrap();
186         print_vec(&mut stderr, unimplemented_intrinsic);
187
188         writeln!(stderr, "# mir not found").unwrap();
189         print_vec(&mut stderr, mir_not_found);
190
191         writeln!(stderr, "# crate not found").unwrap();
192         print_vec(&mut stderr, crate_not_found);
193
194         panic!("ran miri on rustc test suite. Test failing for convenience");
195     } else {
196         run_pass();
197         for_all_targets(sysroot, |target| {
198             miri_pass("tests/run-pass", &target, host);
199         });
200         compile_fail(sysroot);
201     }
202 }
203
204 fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
205     writeln!(stderr, "```").unwrap();
206     for (n, s) in vec_to_hist(v).into_iter().rev() {
207         writeln!(stderr, "{:4} {}", n, s).unwrap();
208     }
209     writeln!(stderr, "```").unwrap();
210 }
211
212 fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
213     v.sort();
214     let mut v = v.into_iter();
215     let mut result = Vec::new();
216     let mut current = v.next();
217     'outer: while let Some(current_val) = current {
218         let mut n = 1;
219         for next in &mut v {
220             if next == current_val {
221                 n += 1;
222             } else {
223                 result.push((n, current_val));
224                 current = Some(next);
225                 continue 'outer;
226             }
227         }
228         result.push((n, current_val));
229         break;
230     }
231     result.sort();
232     result
233 }