]> git.lizzy.rs Git - rust.git/blob - src/tools/compiletest/src/runtest.rs
Auto merge of #44877 - nvzqz:box-conversions, r=alexcrichton
[rust.git] / src / tools / compiletest / src / runtest.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use common::Config;
12 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
13 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
14 use common::{Incremental, RunMake, Ui, MirOpt};
15 use diff;
16 use errors::{self, ErrorKind, Error};
17 use filetime::FileTime;
18 use json;
19 use header::TestProps;
20 use test::TestPaths;
21 use util::logv;
22
23 use std::collections::HashMap;
24 use std::collections::HashSet;
25 use std::env;
26 use std::ffi::OsString;
27 use std::fs::{self, File, create_dir_all};
28 use std::io::prelude::*;
29 use std::io::{self, BufReader};
30 use std::path::{Path, PathBuf};
31 use std::process::{Command, Output, ExitStatus, Stdio};
32 use std::str;
33
34 use extract_gdb_version;
35
36 /// The name of the environment variable that holds dynamic library locations.
37 pub fn dylib_env_var() -> &'static str {
38     if cfg!(windows) {
39         "PATH"
40     } else if cfg!(target_os = "macos") {
41         "DYLD_LIBRARY_PATH"
42     } else if cfg!(target_os = "haiku") {
43         "LIBRARY_PATH"
44     } else {
45         "LD_LIBRARY_PATH"
46     }
47 }
48
49 pub fn run(config: Config, testpaths: &TestPaths) {
50     match &*config.target {
51
52         "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
53             if !config.adb_device_status {
54                 panic!("android device not available");
55             }
56         }
57
58         _ => {
59             // android has its own gdb handling
60             if config.mode == DebugInfoGdb && config.gdb.is_none() {
61                 panic!("gdb not available but debuginfo gdb debuginfo test requested");
62             }
63         }
64     }
65
66     if config.verbose {
67         // We're going to be dumping a lot of info. Start on a new line.
68         print!("\n\n");
69     }
70     debug!("running {:?}", testpaths.file.display());
71     let base_props = TestProps::from_file(&testpaths.file, &config);
72
73     let base_cx = TestCx { config: &config,
74                            props: &base_props,
75                            testpaths,
76                            revision: None };
77     base_cx.init_all();
78
79     if base_props.revisions.is_empty() {
80         base_cx.run_revision()
81     } else {
82         for revision in &base_props.revisions {
83             let mut revision_props = base_props.clone();
84             revision_props.load_from(&testpaths.file, Some(revision), &config);
85             let rev_cx = TestCx {
86                 config: &config,
87                 props: &revision_props,
88                 testpaths,
89                 revision: Some(revision)
90             };
91             rev_cx.run_revision();
92         }
93     }
94
95     base_cx.complete_all();
96
97     File::create(::stamp(&config, testpaths)).unwrap();
98 }
99
100 struct TestCx<'test> {
101     config: &'test Config,
102     props: &'test TestProps,
103     testpaths: &'test TestPaths,
104     revision: Option<&'test str>
105 }
106
107 struct DebuggerCommands {
108     commands: Vec<String>,
109     check_lines: Vec<String>,
110     breakpoint_lines: Vec<usize>,
111 }
112
113 impl<'test> TestCx<'test> {
114     /// invoked once before any revisions have been processed
115     fn init_all(&self) {
116         assert!(self.revision.is_none(), "init_all invoked for a revision");
117         if let Incremental = self.config.mode {
118             self.init_incremental_test()
119         }
120     }
121
122     /// Code executed for each revision in turn (or, if there are no
123     /// revisions, exactly once, with revision == None).
124     fn run_revision(&self) {
125         match self.config.mode {
126             CompileFail |
127             ParseFail => self.run_cfail_test(),
128             RunFail => self.run_rfail_test(),
129             RunPass => self.run_rpass_test(),
130             RunPassValgrind => self.run_valgrind_test(),
131             Pretty => self.run_pretty_test(),
132             DebugInfoGdb => self.run_debuginfo_gdb_test(),
133             DebugInfoLldb => self.run_debuginfo_lldb_test(),
134             Codegen => self.run_codegen_test(),
135             Rustdoc => self.run_rustdoc_test(),
136             CodegenUnits => self.run_codegen_units_test(),
137             Incremental => self.run_incremental_test(),
138             RunMake => self.run_rmake_test(),
139             Ui => self.run_ui_test(),
140             MirOpt => self.run_mir_opt_test(),
141         }
142     }
143
144     /// Invoked after all revisions have executed.
145     fn complete_all(&self) {
146         assert!(self.revision.is_none(), "init_all invoked for a revision");
147     }
148
149     fn run_cfail_test(&self) {
150         let proc_res = self.compile_test();
151
152         if self.props.must_compile_successfully {
153             if !proc_res.status.success() {
154                 self.fatal_proc_rec(
155                     "test compilation failed although it shouldn't!",
156                     &proc_res);
157             }
158         } else {
159             if proc_res.status.success() {
160                 self.fatal_proc_rec(
161                     &format!("{} test compiled successfully!", self.config.mode)[..],
162                     &proc_res);
163             }
164
165             self.check_correct_failure_status(&proc_res);
166         }
167
168         let output_to_check = self.get_output(&proc_res);
169         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
170         if !expected_errors.is_empty() {
171             if !self.props.error_patterns.is_empty() {
172                 self.fatal("both error pattern and expected errors specified");
173             }
174             self.check_expected_errors(expected_errors, &proc_res);
175         } else {
176             self.check_error_patterns(&output_to_check, &proc_res);
177         }
178
179         self.check_no_compiler_crash(&proc_res);
180         self.check_forbid_output(&output_to_check, &proc_res);
181     }
182
183     fn run_rfail_test(&self) {
184         let proc_res = self.compile_test();
185
186         if !proc_res.status.success() {
187             self.fatal_proc_rec("compilation failed!", &proc_res);
188         }
189
190         let proc_res = self.exec_compiled_test();
191
192         // The value our Makefile configures valgrind to return on failure
193         const VALGRIND_ERR: i32 = 100;
194         if proc_res.status.code() == Some(VALGRIND_ERR) {
195             self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
196         }
197
198         let output_to_check = self.get_output(&proc_res);
199         self.check_correct_failure_status(&proc_res);
200         self.check_error_patterns(&output_to_check, &proc_res);
201     }
202
203     fn get_output(&self, proc_res: &ProcRes) -> String {
204         if self.props.check_stdout {
205             format!("{}{}", proc_res.stdout, proc_res.stderr)
206         } else {
207             proc_res.stderr.clone()
208         }
209     }
210
211     fn check_correct_failure_status(&self, proc_res: &ProcRes) {
212         // The value the rust runtime returns on failure
213         const RUST_ERR: i32 = 101;
214         if proc_res.status.code() != Some(RUST_ERR) {
215             self.fatal_proc_rec(
216                 &format!("failure produced the wrong error: {}",
217                          proc_res.status),
218                 proc_res);
219         }
220     }
221
222     fn run_rpass_test(&self) {
223         let proc_res = self.compile_test();
224
225         if !proc_res.status.success() {
226             self.fatal_proc_rec("compilation failed!", &proc_res);
227         }
228
229         // FIXME(#41968): Move this check to tidy?
230         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
231         assert!(expected_errors.is_empty(),
232                 "run-pass tests with expected warnings should be moved to ui/");
233
234         let proc_res = self.exec_compiled_test();
235
236         if !proc_res.status.success() {
237             self.fatal_proc_rec("test run failed!", &proc_res);
238         }
239     }
240
241     fn run_valgrind_test(&self) {
242         assert!(self.revision.is_none(), "revisions not relevant here");
243
244         if self.config.valgrind_path.is_none() {
245             assert!(!self.config.force_valgrind);
246             return self.run_rpass_test();
247         }
248
249         let mut proc_res = self.compile_test();
250
251         if !proc_res.status.success() {
252             self.fatal_proc_rec("compilation failed!", &proc_res);
253         }
254
255         let mut new_config = self.config.clone();
256         new_config.runtool = new_config.valgrind_path.clone();
257         let new_cx = TestCx { config: &new_config, ..*self };
258         proc_res = new_cx.exec_compiled_test();
259
260         if !proc_res.status.success() {
261             self.fatal_proc_rec("test run failed!", &proc_res);
262         }
263     }
264
265     fn run_pretty_test(&self) {
266         if self.props.pp_exact.is_some() {
267             logv(self.config, "testing for exact pretty-printing".to_owned());
268         } else {
269             logv(self.config, "testing for converging pretty-printing".to_owned());
270         }
271
272         let rounds = match self.props.pp_exact { Some(_) => 1, None => 2 };
273
274         let mut src = String::new();
275         File::open(&self.testpaths.file).unwrap().read_to_string(&mut src).unwrap();
276         let mut srcs = vec![src];
277
278         let mut round = 0;
279         while round < rounds {
280             logv(self.config, format!("pretty-printing round {} revision {:?}",
281                                       round, self.revision));
282             let proc_res = self.print_source(srcs[round].to_owned(), &self.props.pretty_mode);
283
284             if !proc_res.status.success() {
285                 self.fatal_proc_rec(&format!("pretty-printing failed in round {} revision {:?}",
286                                              round, self.revision),
287                                     &proc_res);
288             }
289
290             let ProcRes{ stdout, .. } = proc_res;
291             srcs.push(stdout);
292             round += 1;
293         }
294
295         let mut expected = match self.props.pp_exact {
296             Some(ref file) => {
297                 let filepath = self.testpaths.file.parent().unwrap().join(file);
298                 let mut s = String::new();
299                 File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
300                 s
301             }
302             None => { srcs[srcs.len() - 2].clone() }
303         };
304         let mut actual = srcs[srcs.len() - 1].clone();
305
306         if self.props.pp_exact.is_some() {
307             // Now we have to care about line endings
308             let cr = "\r".to_owned();
309             actual = actual.replace(&cr, "").to_owned();
310             expected = expected.replace(&cr, "").to_owned();
311         }
312
313         self.compare_source(&expected, &actual);
314
315         // If we're only making sure that the output matches then just stop here
316         if self.props.pretty_compare_only { return; }
317
318         // Finally, let's make sure it actually appears to remain valid code
319         let proc_res = self.typecheck_source(actual);
320         if !proc_res.status.success() {
321             self.fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
322         }
323
324         if !self.props.pretty_expanded { return }
325
326         // additionally, run `--pretty expanded` and try to build it.
327         let proc_res = self.print_source(srcs[round].clone(), "expanded");
328         if !proc_res.status.success() {
329             self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
330         }
331
332         let ProcRes{ stdout: expanded_src, .. } = proc_res;
333         let proc_res = self.typecheck_source(expanded_src);
334         if !proc_res.status.success() {
335             self.fatal_proc_rec(
336                 "pretty-printed source (expanded) does not typecheck",
337                 &proc_res);
338         }
339     }
340
341     fn print_source(&self, src: String, pretty_type: &str) -> ProcRes {
342         let aux_dir = self.aux_output_dir_name();
343
344         let mut rustc = Command::new(&self.config.rustc_path);
345         rustc.arg("-")
346             .arg("-Zunstable-options")
347             .args(&["--unpretty", &pretty_type])
348             .args(&["--target", &self.config.target])
349             .arg("-L").arg(&aux_dir)
350             .args(self.split_maybe_args(&self.config.target_rustcflags))
351             .args(&self.props.compile_flags)
352             .envs(self.props.exec_env.clone());
353
354         self.compose_and_run(rustc,
355                              self.config.compile_lib_path.to_str().unwrap(),
356                              Some(aux_dir.to_str().unwrap()),
357                              Some(src))
358     }
359
360     fn compare_source(&self,
361                       expected: &str,
362                       actual: &str) {
363         if expected != actual {
364             self.error("pretty-printed source does not match expected source");
365             println!("\n\
366 expected:\n\
367 ------------------------------------------\n\
368 {}\n\
369 ------------------------------------------\n\
370 actual:\n\
371 ------------------------------------------\n\
372 {}\n\
373 ------------------------------------------\n\
374 \n",
375                      expected, actual);
376             panic!();
377         }
378     }
379
380     fn typecheck_source(&self, src: String) -> ProcRes {
381         let mut rustc = Command::new(&self.config.rustc_path);
382
383         let out_dir = self.output_base_name().with_extension("pretty-out");
384         let _ = fs::remove_dir_all(&out_dir);
385         create_dir_all(&out_dir).unwrap();
386
387         let target = if self.props.force_host {
388             &*self.config.host
389         } else {
390             &*self.config.target
391         };
392
393         let aux_dir = self.aux_output_dir_name();
394
395         rustc.arg("-")
396             .arg("-Zno-trans")
397             .arg("--out-dir").arg(&out_dir)
398             .arg(&format!("--target={}", target))
399             .arg("-L").arg(&self.config.build_base)
400             .arg("-L").arg(aux_dir);
401
402         if let Some(revision) = self.revision {
403             rustc.args(&["--cfg", revision]);
404         }
405
406         rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
407         rustc.args(&self.props.compile_flags);
408
409         self.compose_and_run_compiler(rustc, Some(src))
410     }
411
412     fn run_debuginfo_gdb_test(&self) {
413         assert!(self.revision.is_none(), "revisions not relevant here");
414
415         let config = Config {
416             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
417             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
418             .. self.config.clone()
419         };
420
421         let test_cx = TestCx {
422             config: &config,
423             ..*self
424         };
425
426         test_cx.run_debuginfo_gdb_test_no_opt();
427     }
428
429     fn run_debuginfo_gdb_test_no_opt(&self) {
430         let prefixes = if self.config.gdb_native_rust {
431             // GDB with Rust
432             static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"];
433             println!("NOTE: compiletest thinks it is using GDB with native rust support");
434             PREFIXES
435         } else {
436             // Generic GDB
437             static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"];
438             println!("NOTE: compiletest thinks it is using GDB without native rust support");
439             PREFIXES
440         };
441
442         let DebuggerCommands {
443             commands,
444             check_lines,
445             breakpoint_lines
446         } = self.parse_debugger_commands(prefixes);
447         let mut cmds = commands.join("\n");
448
449         // compile test file (it should have 'compile-flags:-g' in the header)
450         let compiler_run_result = self.compile_test();
451         if !compiler_run_result.status.success() {
452             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
453         }
454
455         let exe_file = self.make_exe_name();
456
457         let debugger_run_result;
458         match &*self.config.target {
459             "arm-linux-androideabi" |
460             "armv7-linux-androideabi" |
461             "aarch64-linux-android" => {
462
463                 cmds = cmds.replace("run", "continue");
464
465                 let tool_path = match self.config.android_cross_path.to_str() {
466                     Some(x) => x.to_owned(),
467                     None => self.fatal("cannot find android cross path")
468                 };
469
470                 // write debugger script
471                 let mut script_str = String::with_capacity(2048);
472                 script_str.push_str(&format!("set charset {}\n", Self::charset()));
473                 script_str.push_str(&format!("set sysroot {}\n", tool_path));
474                 script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
475                 script_str.push_str("target remote :5039\n");
476                 script_str.push_str(&format!("set solib-search-path \
477                                               ./{}/stage2/lib/rustlib/{}/lib/\n",
478                                              self.config.host, self.config.target));
479                 for line in &breakpoint_lines {
480                     script_str.push_str(&format!("break {:?}:{}\n",
481                                                  self.testpaths.file.file_name()
482                                                  .unwrap()
483                                                  .to_string_lossy(),
484                                                  *line)[..]);
485                 }
486                 script_str.push_str(&cmds);
487                 script_str.push_str("\nquit\n");
488
489                 debug!("script_str = {}", script_str);
490                 self.dump_output_file(&script_str, "debugger.script");
491
492                 let adb_path = &self.config.adb_path;
493
494                 Command::new(adb_path)
495                     .arg("push")
496                     .arg(&exe_file)
497                     .arg(&self.config.adb_test_dir)
498                     .status()
499                     .expect(&format!("failed to exec `{:?}`", adb_path));
500
501                 Command::new(adb_path)
502                     .args(&["forward", "tcp:5039", "tcp:5039"])
503                     .status()
504                     .expect(&format!("failed to exec `{:?}`", adb_path));
505
506                 let adb_arg = format!("export LD_LIBRARY_PATH={}; \
507                                        gdbserver{} :5039 {}/{}",
508                                       self.config.adb_test_dir.clone(),
509                                       if self.config.target.contains("aarch64")
510                                       {"64"} else {""},
511                                       self.config.adb_test_dir.clone(),
512                                       exe_file.file_name().unwrap().to_str()
513                                       .unwrap());
514
515                 debug!("adb arg: {}", adb_arg);
516                 let mut adb = Command::new(adb_path)
517                     .args(&["shell", &adb_arg])
518                     .stdout(Stdio::piped())
519                     .stderr(Stdio::inherit())
520                     .spawn()
521                     .expect(&format!("failed to exec `{:?}`", adb_path));
522
523                 // Wait for the gdbserver to print out "Listening on port ..."
524                 // at which point we know that it's started and then we can
525                 // execute the debugger below.
526                 let mut stdout = BufReader::new(adb.stdout.take().unwrap());
527                 let mut line = String::new();
528                 loop {
529                     line.truncate(0);
530                     stdout.read_line(&mut line).unwrap();
531                     if line.starts_with("Listening on port 5039") {
532                         break
533                     }
534                 }
535                 drop(stdout);
536
537                 let debugger_script = self.make_out_name("debugger.script");
538                 // FIXME (#9639): This needs to handle non-utf8 paths
539                 let debugger_opts =
540                     vec!["-quiet".to_owned(),
541                          "-batch".to_owned(),
542                          "-nx".to_owned(),
543                          format!("-command={}", debugger_script.to_str().unwrap())];
544
545                 let mut gdb_path = tool_path;
546                 gdb_path.push_str("/bin/gdb");
547                 let Output {
548                     status,
549                     stdout,
550                     stderr
551                 } = Command::new(&gdb_path)
552                     .args(&debugger_opts)
553                     .output()
554                     .expect(&format!("failed to exec `{:?}`", gdb_path));
555                 let cmdline = {
556                     let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
557                     gdb.args(&debugger_opts);
558                     let cmdline = self.make_cmdline(&gdb, "");
559                     logv(self.config, format!("executing {}", cmdline));
560                     cmdline
561                 };
562
563                 debugger_run_result = ProcRes {
564                     status,
565                     stdout: String::from_utf8(stdout).unwrap(),
566                     stderr: String::from_utf8(stderr).unwrap(),
567                     cmdline,
568                 };
569                 if adb.kill().is_err() {
570                     println!("Adb process is already finished.");
571                 }
572             }
573
574             _ => {
575                 let rust_src_root = self.config.find_rust_src_root().expect(
576                     "Could not find Rust source root",
577                 );
578                 let rust_pp_module_rel_path = Path::new("./src/etc");
579                 let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
580                                                            .to_str()
581                                                            .unwrap()
582                                                            .to_owned();
583                 // write debugger script
584                 let mut script_str = String::with_capacity(2048);
585                 script_str.push_str(&format!("set charset {}\n", Self::charset()));
586                 script_str.push_str("show version\n");
587
588                 match self.config.gdb_version {
589                     Some(version) => {
590                         println!("NOTE: compiletest thinks it is using GDB version {}",
591                                  version);
592
593                         if version > extract_gdb_version("7.4").unwrap() {
594                             // Add the directory containing the pretty printers to
595                             // GDB's script auto loading safe path
596                             script_str.push_str(
597                                 &format!("add-auto-load-safe-path {}\n",
598                                          rust_pp_module_abs_path.replace(r"\", r"\\"))
599                             );
600                         }
601                     }
602                     _ => {
603                         println!("NOTE: compiletest does not know which version of \
604                                   GDB it is using");
605                     }
606                 }
607
608                 // The following line actually doesn't have to do anything with
609                 // pretty printing, it just tells GDB to print values on one line:
610                 script_str.push_str("set print pretty off\n");
611
612                 // Add the pretty printer directory to GDB's source-file search path
613                 script_str.push_str(&format!("directory {}\n",
614                                              rust_pp_module_abs_path));
615
616                 // Load the target executable
617                 script_str.push_str(&format!("file {}\n",
618                                              exe_file.to_str().unwrap()
619                                              .replace(r"\", r"\\")));
620
621                 // Force GDB to print values in the Rust format.
622                 if self.config.gdb_native_rust {
623                     script_str.push_str("set language rust\n");
624                 }
625
626                 // Add line breakpoints
627                 for line in &breakpoint_lines {
628                     script_str.push_str(&format!("break '{}':{}\n",
629                                                  self.testpaths.file.file_name().unwrap()
630                                                  .to_string_lossy(),
631                                                  *line));
632                 }
633
634                 script_str.push_str(&cmds);
635                 script_str.push_str("\nquit\n");
636
637                 debug!("script_str = {}", script_str);
638                 self.dump_output_file(&script_str, "debugger.script");
639
640                 let debugger_script = self.make_out_name("debugger.script");
641
642                 // FIXME (#9639): This needs to handle non-utf8 paths
643                 let debugger_opts =
644                     vec!["-quiet".to_owned(),
645                          "-batch".to_owned(),
646                          "-nx".to_owned(),
647                          format!("-command={}", debugger_script.to_str().unwrap())];
648
649                 let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
650                 gdb.args(&debugger_opts)
651                     .env("PYTHONPATH", rust_pp_module_abs_path);
652
653                 debugger_run_result =
654                     self.compose_and_run(gdb,
655                                          self.config.run_lib_path.to_str().unwrap(),
656                                          None,
657                                          None);
658             }
659         }
660
661         if !debugger_run_result.status.success() {
662             self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
663         }
664
665         self.check_debugger_output(&debugger_run_result, &check_lines);
666     }
667
668     fn run_debuginfo_lldb_test(&self) {
669         assert!(self.revision.is_none(), "revisions not relevant here");
670
671         if self.config.lldb_python_dir.is_none() {
672             self.fatal("Can't run LLDB test because LLDB's python path is not set.");
673         }
674
675         let config = Config {
676             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
677             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
678             .. self.config.clone()
679         };
680
681
682         let test_cx = TestCx {
683             config: &config,
684             ..*self
685         };
686
687         test_cx.run_debuginfo_lldb_test_no_opt();
688     }
689
690     fn run_debuginfo_lldb_test_no_opt(&self) {
691         // compile test file (it should have 'compile-flags:-g' in the header)
692         let compile_result = self.compile_test();
693         if !compile_result.status.success() {
694             self.fatal_proc_rec("compilation failed!", &compile_result);
695         }
696
697         let exe_file = self.make_exe_name();
698
699         match self.config.lldb_version {
700             Some(ref version) => {
701                 println!("NOTE: compiletest thinks it is using LLDB version {}",
702                          version);
703             }
704             _ => {
705                 println!("NOTE: compiletest does not know which version of \
706                           LLDB it is using");
707             }
708         }
709
710         // Parse debugger commands etc from test files
711         let DebuggerCommands {
712             commands,
713             check_lines,
714             breakpoint_lines,
715             ..
716         } = self.parse_debugger_commands(&["lldb"]);
717
718         // Write debugger script:
719         // We don't want to hang when calling `quit` while the process is still running
720         let mut script_str = String::from("settings set auto-confirm true\n");
721
722         // Make LLDB emit its version, so we have it documented in the test output
723         script_str.push_str("version\n");
724
725         // Switch LLDB into "Rust mode"
726         let rust_src_root = self.config.find_rust_src_root().expect(
727             "Could not find Rust source root",
728         );
729         let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
730         let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
731                                                    .to_str()
732                                                    .unwrap()
733                                                    .to_owned();
734
735         script_str.push_str(&format!("command script import {}\n",
736                                      &rust_pp_module_abs_path[..])[..]);
737         script_str.push_str("type summary add --no-value ");
738         script_str.push_str("--python-function lldb_rust_formatters.print_val ");
739         script_str.push_str("-x \".*\" --category Rust\n");
740         script_str.push_str("type category enable Rust\n");
741
742         // Set breakpoints on every line that contains the string "#break"
743         let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
744         for line in &breakpoint_lines {
745             script_str.push_str(&format!("breakpoint set --file '{}' --line {}\n",
746                                          source_file_name,
747                                          line));
748         }
749
750         // Append the other commands
751         for line in &commands {
752             script_str.push_str(line);
753             script_str.push_str("\n");
754         }
755
756         // Finally, quit the debugger
757         script_str.push_str("\nquit\n");
758
759         // Write the script into a file
760         debug!("script_str = {}", script_str);
761         self.dump_output_file(&script_str, "debugger.script");
762         let debugger_script = self.make_out_name("debugger.script");
763
764         // Let LLDB execute the script via lldb_batchmode.py
765         let debugger_run_result = self.run_lldb(&exe_file,
766                                                 &debugger_script,
767                                                 &rust_src_root);
768
769         if !debugger_run_result.status.success() {
770             self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
771         }
772
773         self.check_debugger_output(&debugger_run_result, &check_lines);
774     }
775
776     fn run_lldb(&self,
777                 test_executable: &Path,
778                 debugger_script: &Path,
779                 rust_src_root: &Path)
780                 -> ProcRes {
781         // Prepare the lldb_batchmode which executes the debugger script
782         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
783         self.cmd2procres(Command::new(&self.config.lldb_python)
784                          .arg(&lldb_script_path)
785                          .arg(test_executable)
786                          .arg(debugger_script)
787                          .env("PYTHONPATH",
788                               self.config.lldb_python_dir.as_ref().unwrap()))
789     }
790
791     fn cmd2procres(&self, cmd: &mut Command) -> ProcRes {
792         let (status, out, err) = match cmd.output() {
793             Ok(Output { status, stdout, stderr }) => {
794                 (status,
795                  String::from_utf8(stdout).unwrap(),
796                  String::from_utf8(stderr).unwrap())
797             },
798             Err(e) => {
799                 self.fatal(&format!("Failed to setup Python process for \
800                                       LLDB script: {}", e))
801             }
802         };
803
804         self.dump_output(&out, &err);
805         ProcRes {
806             status,
807             stdout: out,
808             stderr: err,
809             cmdline: format!("{:?}", cmd)
810         }
811     }
812
813     fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
814         let directives = debugger_prefixes.iter().map(|prefix| (
815             format!("{}-command", prefix),
816             format!("{}-check", prefix),
817         )).collect::<Vec<_>>();
818
819         let mut breakpoint_lines = vec![];
820         let mut commands = vec![];
821         let mut check_lines = vec![];
822         let mut counter = 1;
823         let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
824         for line in reader.lines() {
825             match line {
826                 Ok(line) => {
827                     if line.contains("#break") {
828                         breakpoint_lines.push(counter);
829                     }
830
831                     for &(ref command_directive, ref check_directive) in &directives {
832                         self.config.parse_name_value_directive(
833                             &line,
834                             command_directive).map(|cmd| {
835                                 commands.push(cmd)
836                             });
837
838                         self.config.parse_name_value_directive(
839                             &line,
840                             check_directive).map(|cmd| {
841                                 check_lines.push(cmd)
842                             });
843                     }
844                 }
845                 Err(e) => {
846                     self.fatal(&format!("Error while parsing debugger commands: {}", e))
847                 }
848             }
849             counter += 1;
850         }
851
852         DebuggerCommands {
853             commands,
854             check_lines,
855             breakpoint_lines,
856         }
857     }
858
859     fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
860         if options.is_none() {
861             return None;
862         }
863
864         // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
865         let options_to_remove = [
866             "-O".to_owned(),
867             "-g".to_owned(),
868             "--debuginfo".to_owned()
869         ];
870         let new_options =
871             self.split_maybe_args(options).into_iter()
872                                           .filter(|x| !options_to_remove.contains(x))
873                                           .collect::<Vec<String>>();
874
875         Some(new_options.join(" "))
876     }
877
878     fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[String]) {
879         let num_check_lines = check_lines.len();
880
881         let mut check_line_index = 0;
882         for line in debugger_run_result.stdout.lines() {
883             if check_line_index >= num_check_lines {
884                 break;
885             }
886
887             if check_single_line(line, &(check_lines[check_line_index])[..]) {
888                 check_line_index += 1;
889             }
890         }
891         if check_line_index != num_check_lines && num_check_lines > 0 {
892             self.fatal_proc_rec(&format!("line not found in debugger output: {}",
893                                          check_lines[check_line_index]),
894                                 debugger_run_result);
895         }
896
897         fn check_single_line(line: &str, check_line: &str) -> bool {
898             // Allow check lines to leave parts unspecified (e.g., uninitialized
899             // bits in the  wrong case of an enum) with the notation "[...]".
900             let line = line.trim();
901             let check_line = check_line.trim();
902             let can_start_anywhere = check_line.starts_with("[...]");
903             let can_end_anywhere = check_line.ends_with("[...]");
904
905             let check_fragments: Vec<&str> = check_line.split("[...]")
906                                                        .filter(|frag| !frag.is_empty())
907                                                        .collect();
908             if check_fragments.is_empty() {
909                 return true;
910             }
911
912             let (mut rest, first_fragment) = if can_start_anywhere {
913                 match line.find(check_fragments[0]) {
914                     Some(pos) => (&line[pos + check_fragments[0].len() ..], 1),
915                     None => return false
916                 }
917             } else {
918                 (line, 0)
919             };
920
921             for current_fragment in &check_fragments[first_fragment..] {
922                 match rest.find(current_fragment) {
923                     Some(pos) => {
924                         rest = &rest[pos + current_fragment.len() .. ];
925                     }
926                     None => return false
927                 }
928             }
929
930             if !can_end_anywhere && !rest.is_empty() {
931                 return false;
932             }
933
934             true
935         }
936     }
937
938     fn check_error_patterns(&self,
939                             output_to_check: &str,
940                             proc_res: &ProcRes) {
941         if self.props.error_patterns.is_empty() {
942             if self.props.must_compile_successfully {
943                 return
944             } else {
945                 self.fatal(&format!("no error pattern specified in {:?}",
946                                     self.testpaths.file.display()));
947             }
948         }
949         let mut next_err_idx = 0;
950         let mut next_err_pat = self.props.error_patterns[next_err_idx].trim();
951         let mut done = false;
952         for line in output_to_check.lines() {
953             if line.contains(next_err_pat) {
954                 debug!("found error pattern {}", next_err_pat);
955                 next_err_idx += 1;
956                 if next_err_idx == self.props.error_patterns.len() {
957                     debug!("found all error patterns");
958                     done = true;
959                     break;
960                 }
961                 next_err_pat = self.props.error_patterns[next_err_idx].trim();
962             }
963         }
964         if done { return; }
965
966         let missing_patterns = &self.props.error_patterns[next_err_idx..];
967         if missing_patterns.len() == 1 {
968             self.fatal_proc_rec(
969                 &format!("error pattern '{}' not found!", missing_patterns[0]),
970                 proc_res);
971         } else {
972             for pattern in missing_patterns {
973                 self.error(&format!("error pattern '{}' not found!", *pattern));
974             }
975             self.fatal_proc_rec("multiple error patterns not found", proc_res);
976         }
977     }
978
979     fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
980         for line in proc_res.stderr.lines() {
981             if line.contains("error: internal compiler error") {
982                 self.fatal_proc_rec("compiler encountered internal error", proc_res);
983             }
984         }
985     }
986
987     fn check_forbid_output(&self,
988                            output_to_check: &str,
989                            proc_res: &ProcRes) {
990         for pat in &self.props.forbid_output {
991             if output_to_check.contains(pat) {
992                 self.fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
993             }
994         }
995     }
996
997     fn check_expected_errors(&self,
998                              expected_errors: Vec<errors::Error>,
999                              proc_res: &ProcRes) {
1000         if proc_res.status.success() &&
1001             expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) {
1002             self.fatal_proc_rec("process did not return an error status", proc_res);
1003         }
1004
1005         let file_name =
1006             format!("{}", self.testpaths.file.display())
1007             .replace(r"\", "/"); // on windows, translate all '\' path separators to '/'
1008
1009         // If the testcase being checked contains at least one expected "help"
1010         // message, then we'll ensure that all "help" messages are expected.
1011         // Otherwise, all "help" messages reported by the compiler will be ignored.
1012         // This logic also applies to "note" messages.
1013         let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
1014         let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
1015
1016         // Parse the JSON output from the compiler and extract out the messages.
1017         let actual_errors = json::parse_output(&file_name, &proc_res.stderr, proc_res);
1018         let mut unexpected = Vec::new();
1019         let mut found = vec![false; expected_errors.len()];
1020         for actual_error in &actual_errors {
1021             let opt_index =
1022                 expected_errors
1023                 .iter()
1024                 .enumerate()
1025                 .position(|(index, expected_error)| {
1026                     !found[index] &&
1027                         actual_error.line_num == expected_error.line_num &&
1028                         (expected_error.kind.is_none() ||
1029                          actual_error.kind == expected_error.kind) &&
1030                         actual_error.msg.contains(&expected_error.msg)
1031                 });
1032
1033             match opt_index {
1034                 Some(index) => {
1035                     // found a match, everybody is happy
1036                     assert!(!found[index]);
1037                     found[index] = true;
1038                 }
1039
1040                 None => {
1041                     if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
1042                         self.error(
1043                             &format!("{}:{}: unexpected {:?}: '{}'",
1044                                      file_name,
1045                                      actual_error.line_num,
1046                                      actual_error.kind.as_ref()
1047                                      .map_or(String::from("message"),
1048                                              |k| k.to_string()),
1049                                      actual_error.msg));
1050                         unexpected.push(actual_error);
1051                     }
1052                 }
1053             }
1054         }
1055
1056         let mut not_found = Vec::new();
1057         // anything not yet found is a problem
1058         for (index, expected_error) in expected_errors.iter().enumerate() {
1059             if !found[index] {
1060                 self.error(
1061                     &format!("{}:{}: expected {} not found: {}",
1062                              file_name,
1063                              expected_error.line_num,
1064                              expected_error.kind.as_ref()
1065                              .map_or("message".into(),
1066                                      |k| k.to_string()),
1067                              expected_error.msg));
1068                 not_found.push(expected_error);
1069             }
1070         }
1071
1072         if !unexpected.is_empty() || !not_found.is_empty() {
1073             self.error(
1074                 &format!("{} unexpected errors found, {} expected errors not found",
1075                          unexpected.len(), not_found.len()));
1076             println!("status: {}\ncommand: {}",
1077                    proc_res.status, proc_res.cmdline);
1078             if !unexpected.is_empty() {
1079                 println!("unexpected errors (from JSON output): {:#?}\n", unexpected);
1080             }
1081             if !not_found.is_empty() {
1082                 println!("not found errors (from test file): {:#?}\n", not_found);
1083             }
1084             panic!();
1085         }
1086     }
1087
1088     /// Returns true if we should report an error about `actual_error`,
1089     /// which did not match any of the expected error. We always require
1090     /// errors/warnings to be explicitly listed, but only require
1091     /// helps/notes if there are explicit helps/notes given.
1092     fn is_unexpected_compiler_message(&self,
1093                                       actual_error: &Error,
1094                                       expect_help: bool,
1095                                       expect_note: bool)
1096                                       -> bool {
1097         match actual_error.kind {
1098             Some(ErrorKind::Help) => expect_help,
1099             Some(ErrorKind::Note) => expect_note,
1100             Some(ErrorKind::Error) |
1101             Some(ErrorKind::Warning) => true,
1102             Some(ErrorKind::Suggestion) |
1103             None => false
1104         }
1105     }
1106
1107     fn compile_test(&self) -> ProcRes {
1108         let mut rustc = self.make_compile_args(
1109             &self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name()));
1110
1111         rustc.arg("-L").arg(&self.aux_output_dir_name());
1112
1113         match self.config.mode {
1114             CompileFail | Ui => {
1115                 // compile-fail and ui tests tend to have tons of unused code as
1116                 // it's just testing various pieces of the compile, but we don't
1117                 // want to actually assert warnings about all this code. Instead
1118                 // let's just ignore unused code warnings by defaults and tests
1119                 // can turn it back on if needed.
1120                 rustc.args(&["-A", "unused"]);
1121             }
1122             _ => {}
1123         }
1124
1125         self.compose_and_run_compiler(rustc, None)
1126     }
1127
1128     fn document(&self, out_dir: &Path) -> ProcRes {
1129         if self.props.build_aux_docs {
1130             for rel_ab in &self.props.aux_builds {
1131                 let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1132                 let aux_props = self.props.from_aux_file(&aux_testpaths.file,
1133                                                          self.revision,
1134                                                          self.config);
1135                 let aux_cx = TestCx {
1136                     config: self.config,
1137                     props: &aux_props,
1138                     testpaths: &aux_testpaths,
1139                     revision: self.revision
1140                 };
1141                 let auxres = aux_cx.document(out_dir);
1142                 if !auxres.status.success() {
1143                     return auxres;
1144                 }
1145             }
1146         }
1147
1148         let aux_dir = self.aux_output_dir_name();
1149
1150         let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed");
1151         let mut rustdoc = Command::new(rustdoc_path);
1152
1153         rustdoc.arg("-L").arg(aux_dir)
1154             .arg("-o").arg(out_dir)
1155             .arg(&self.testpaths.file)
1156             .args(&self.props.compile_flags);
1157
1158         self.compose_and_run_compiler(rustdoc, None)
1159     }
1160
1161     fn exec_compiled_test(&self) -> ProcRes {
1162         let env = &self.props.exec_env;
1163
1164         match &*self.config.target {
1165             // This is pretty similar to below, we're transforming:
1166             //
1167             //      program arg1 arg2
1168             //
1169             // into
1170             //
1171             //      remote-test-client run program:support-lib.so arg1 arg2
1172             //
1173             // The test-client program will upload `program` to the emulator
1174             // along with all other support libraries listed (in this case
1175             // `support-lib.so`. It will then execute the program on the
1176             // emulator with the arguments specified (in the environment we give
1177             // the process) and then report back the same result.
1178             _ if self.config.remote_test_client.is_some() => {
1179                 let aux_dir = self.aux_output_dir_name();
1180                 let ProcArgs { mut prog, args } = self.make_run_args();
1181                 if let Ok(entries) = aux_dir.read_dir() {
1182                     for entry in entries {
1183                         let entry = entry.unwrap();
1184                         if !entry.path().is_file() {
1185                             continue
1186                         }
1187                         prog.push_str(":");
1188                         prog.push_str(entry.path().to_str().unwrap());
1189                     }
1190                 }
1191                 let mut test_client = Command::new(
1192                     self.config.remote_test_client.as_ref().unwrap());
1193                 test_client
1194                     .args(&["run", &prog])
1195                     .args(args)
1196                     .envs(env.clone());
1197                 self.compose_and_run(test_client,
1198                                      self.config.run_lib_path.to_str().unwrap(),
1199                                      Some(aux_dir.to_str().unwrap()),
1200                                      None)
1201             }
1202             _ => {
1203                 let aux_dir = self.aux_output_dir_name();
1204                 let ProcArgs { prog, args } = self.make_run_args();
1205                 let mut program = Command::new(&prog);
1206                 program.args(args)
1207                     .current_dir(&self.output_base_name().parent().unwrap())
1208                     .envs(env.clone());
1209                 self.compose_and_run(program,
1210                                      self.config.run_lib_path.to_str().unwrap(),
1211                                      Some(aux_dir.to_str().unwrap()),
1212                                      None)
1213             }
1214         }
1215     }
1216
1217     /// For each `aux-build: foo/bar` annotation, we check to find the
1218     /// file in a `aux` directory relative to the test itself.
1219     fn compute_aux_test_paths(&self, rel_ab: &str) -> TestPaths {
1220         let test_ab = self.testpaths.file
1221                                     .parent()
1222                                     .expect("test file path has no parent")
1223                                     .join("auxiliary")
1224                                     .join(rel_ab);
1225         if !test_ab.exists() {
1226             self.fatal(&format!("aux-build `{}` source not found", test_ab.display()))
1227         }
1228
1229         TestPaths {
1230             file: test_ab,
1231             base: self.testpaths.base.clone(),
1232             relative_dir: self.testpaths.relative_dir
1233                                         .join("auxiliary")
1234                                         .join(rel_ab)
1235                                         .parent()
1236                                         .expect("aux-build path has no parent")
1237                                         .to_path_buf()
1238         }
1239     }
1240
1241     fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
1242         if !self.props.aux_builds.is_empty() {
1243             create_dir_all(&self.aux_output_dir_name()).unwrap();
1244         }
1245
1246         let aux_dir = self.aux_output_dir_name();
1247
1248         for rel_ab in &self.props.aux_builds {
1249             let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1250             let aux_props = self.props.from_aux_file(&aux_testpaths.file,
1251                                                      self.revision,
1252                                                      self.config);
1253             let aux_output = {
1254                 let f = self.make_lib_name(&self.testpaths.file);
1255                 let parent = f.parent().unwrap();
1256                 TargetLocation::ThisDirectory(parent.to_path_buf())
1257             };
1258             let aux_cx = TestCx {
1259                 config: self.config,
1260                 props: &aux_props,
1261                 testpaths: &aux_testpaths,
1262                 revision: self.revision
1263             };
1264             let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
1265
1266             let crate_type = if aux_props.no_prefer_dynamic {
1267                 None
1268             } else if (self.config.target.contains("musl") && !aux_props.force_host) ||
1269                       self.config.target.contains("emscripten") {
1270                 // We primarily compile all auxiliary libraries as dynamic libraries
1271                 // to avoid code size bloat and large binaries as much as possible
1272                 // for the test suite (otherwise including libstd statically in all
1273                 // executables takes up quite a bit of space).
1274                 //
1275                 // For targets like MUSL or Emscripten, however, there is no support for
1276                 // dynamic libraries so we just go back to building a normal library. Note,
1277                 // however, that for MUSL if the library is built with `force_host` then
1278                 // it's ok to be a dylib as the host should always support dylibs.
1279                 Some("lib")
1280             } else {
1281                 Some("dylib")
1282             };
1283
1284             if let Some(crate_type) = crate_type {
1285                 aux_rustc.args(&["--crate-type", crate_type]);
1286             }
1287
1288             aux_rustc.arg("-L").arg(&aux_dir);
1289
1290             let auxres = aux_cx.compose_and_run(aux_rustc,
1291                                                 aux_cx.config.compile_lib_path.to_str().unwrap(),
1292                                                 Some(aux_dir.to_str().unwrap()),
1293                                                 None);
1294             if !auxres.status.success() {
1295                 self.fatal_proc_rec(
1296                     &format!("auxiliary build of {:?} failed to compile: ",
1297                              aux_testpaths.file.display()),
1298                     &auxres);
1299             }
1300         }
1301
1302         rustc.envs(self.props.rustc_env.clone());
1303         self.compose_and_run(rustc,
1304                              self.config.compile_lib_path.to_str().unwrap(),
1305                              Some(aux_dir.to_str().unwrap()),
1306                              input)
1307     }
1308
1309     fn compose_and_run(&self,
1310                        mut command: Command,
1311                        lib_path: &str,
1312                        aux_path: Option<&str>,
1313                        input: Option<String>) -> ProcRes {
1314         let cmdline =
1315         {
1316             let cmdline = self.make_cmdline(&command, lib_path);
1317             logv(self.config, format!("executing {}", cmdline));
1318             cmdline
1319         };
1320
1321         command
1322             .stdout(Stdio::piped())
1323             .stderr(Stdio::piped())
1324             .stdin(Stdio::piped());
1325
1326         // Need to be sure to put both the lib_path and the aux path in the dylib
1327         // search path for the child.
1328         let mut path = env::split_paths(&env::var_os(dylib_env_var()).unwrap_or(OsString::new()))
1329             .collect::<Vec<_>>();
1330         if let Some(p) = aux_path {
1331             path.insert(0, PathBuf::from(p))
1332         }
1333         path.insert(0, PathBuf::from(lib_path));
1334
1335         // Add the new dylib search path var
1336         let newpath = env::join_paths(&path).unwrap();
1337         command.env(dylib_env_var(), newpath);
1338
1339         let mut child = command.spawn().expect(&format!("failed to exec `{:?}`", &command));
1340         if let Some(input) = input {
1341             child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
1342         }
1343         let Output { status, stdout, stderr } = child.wait_with_output().unwrap();
1344
1345         let result = ProcRes {
1346             status,
1347             stdout: String::from_utf8(stdout).unwrap(),
1348             stderr: String::from_utf8(stderr).unwrap(),
1349             cmdline,
1350         };
1351
1352         self.dump_output(&result.stdout, &result.stderr);
1353
1354         result
1355     }
1356
1357     fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
1358         let mut rustc = Command::new(&self.config.rustc_path);
1359         rustc.arg(input_file)
1360             .arg("-L").arg(&self.config.build_base);
1361
1362         // Optionally prevent default --target if specified in test compile-flags.
1363         let custom_target = self.props.compile_flags
1364             .iter()
1365             .fold(false, |acc, x| acc || x.starts_with("--target"));
1366
1367         if !custom_target {
1368             let target = if self.props.force_host {
1369                 &*self.config.host
1370             } else {
1371                 &*self.config.target
1372             };
1373
1374             rustc.arg(&format!("--target={}", target));
1375         }
1376
1377         if let Some(revision) = self.revision {
1378             rustc.args(&["--cfg", revision]);
1379         }
1380
1381         if let Some(ref incremental_dir) = self.props.incremental_dir {
1382             rustc.args(&["-Z", &format!("incremental={}", incremental_dir.display())]);
1383         }
1384
1385         match self.config.mode {
1386             CompileFail |
1387             ParseFail |
1388             Incremental => {
1389                 // If we are extracting and matching errors in the new
1390                 // fashion, then you want JSON mode. Old-skool error
1391                 // patterns still match the raw compiler output.
1392                 if self.props.error_patterns.is_empty() {
1393                     rustc.args(&["--error-format", "json"]);
1394                 }
1395             }
1396             MirOpt => {
1397                 rustc.args(&[
1398                     "-Zdump-mir=all",
1399                     "-Zmir-opt-level=3",
1400                     "-Zdump-mir-exclude-pass-number"]);
1401
1402                 let mir_dump_dir = self.get_mir_dump_dir();
1403                 create_dir_all(mir_dump_dir.as_path()).unwrap();
1404                 let mut dir_opt = "-Zdump-mir-dir=".to_string();
1405                 dir_opt.push_str(mir_dump_dir.to_str().unwrap());
1406                 debug!("dir_opt: {:?}", dir_opt);
1407
1408                 rustc.arg(dir_opt);
1409             }
1410             RunPass |
1411             RunFail |
1412             RunPassValgrind |
1413             Pretty |
1414             DebugInfoGdb |
1415             DebugInfoLldb |
1416             Codegen |
1417             Rustdoc |
1418             RunMake |
1419             Ui |
1420             CodegenUnits => {
1421                 // do not use JSON output
1422             }
1423         }
1424
1425         if !self.props.no_prefer_dynamic {
1426             rustc.args(&["-C", "prefer-dynamic"]);
1427         }
1428
1429         match output_file {
1430             TargetLocation::ThisFile(path) => {
1431                 rustc.arg("-o").arg(path);
1432             }
1433             TargetLocation::ThisDirectory(path) => {
1434                 rustc.arg("--out-dir").arg(path);
1435             }
1436         }
1437
1438         if self.props.force_host {
1439             rustc.args(self.split_maybe_args(&self.config.host_rustcflags));
1440         } else {
1441             rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
1442         }
1443
1444         rustc.args(&self.props.compile_flags);
1445
1446         rustc
1447     }
1448
1449     fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
1450         // what we return here is not particularly important, as it
1451         // happens; rustc ignores everything except for the directory.
1452         let auxname = self.output_testname(auxfile);
1453         self.aux_output_dir_name().join(&auxname)
1454     }
1455
1456     fn make_exe_name(&self) -> PathBuf {
1457         let mut f = self.output_base_name();
1458         // FIXME: This is using the host architecture exe suffix, not target!
1459         if self.config.target.contains("emscripten") {
1460             let mut fname = f.file_name().unwrap().to_os_string();
1461             fname.push(".js");
1462             f.set_file_name(&fname);
1463         } else if !env::consts::EXE_SUFFIX.is_empty() {
1464             let mut fname = f.file_name().unwrap().to_os_string();
1465             fname.push(env::consts::EXE_SUFFIX);
1466             f.set_file_name(&fname);
1467         }
1468         f
1469     }
1470
1471     fn make_run_args(&self) -> ProcArgs {
1472         // If we've got another tool to run under (valgrind),
1473         // then split apart its command
1474         let mut args = self.split_maybe_args(&self.config.runtool);
1475
1476         // If this is emscripten, then run tests under nodejs
1477         if self.config.target.contains("emscripten") {
1478             if let Some(ref p) = self.config.nodejs {
1479                 args.push(p.clone());
1480             } else {
1481                 self.fatal("no NodeJS binary found (--nodejs)");
1482             }
1483         }
1484
1485         let exe_file = self.make_exe_name();
1486
1487         // FIXME (#9639): This needs to handle non-utf8 paths
1488         args.push(exe_file.to_str().unwrap().to_owned());
1489
1490         // Add the arguments in the run_flags directive
1491         args.extend(self.split_maybe_args(&self.props.run_flags));
1492
1493         let prog = args.remove(0);
1494          ProcArgs {
1495             prog,
1496             args,
1497         }
1498     }
1499
1500     fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<String> {
1501         match *argstr {
1502             Some(ref s) => {
1503                 s
1504                     .split(' ')
1505                     .filter_map(|s| {
1506                         if s.chars().all(|c| c.is_whitespace()) {
1507                             None
1508                         } else {
1509                             Some(s.to_owned())
1510                         }
1511                     }).collect()
1512             }
1513             None => Vec::new()
1514         }
1515     }
1516
1517     fn make_cmdline(&self, command: &Command, libpath: &str) -> String {
1518         use util;
1519
1520         // Linux and mac don't require adjusting the library search path
1521         if cfg!(unix) {
1522             format!("{:?}", command)
1523         } else {
1524             // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1525             // for diagnostic purposes
1526             fn lib_path_cmd_prefix(path: &str) -> String {
1527                 format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
1528             }
1529
1530             format!("{} {:?}", lib_path_cmd_prefix(libpath), command)
1531         }
1532     }
1533
1534     fn dump_output(&self, out: &str, err: &str) {
1535         let revision = if let Some(r) = self.revision {
1536             format!("{}.", r)
1537         } else {
1538             String::new()
1539         };
1540
1541         self.dump_output_file(out, &format!("{}out", revision));
1542         self.dump_output_file(err, &format!("{}err", revision));
1543         self.maybe_dump_to_stdout(out, err);
1544     }
1545
1546     fn dump_output_file(&self,
1547                         out: &str,
1548                         extension: &str) {
1549         let outfile = self.make_out_name(extension);
1550         File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1551     }
1552
1553     fn make_out_name(&self, extension: &str) -> PathBuf {
1554         self.output_base_name().with_extension(extension)
1555     }
1556
1557     fn aux_output_dir_name(&self) -> PathBuf {
1558         let f = self.output_base_name();
1559         let mut fname = f.file_name().unwrap().to_os_string();
1560         fname.push(&format!(".{}.libaux", self.config.mode));
1561         f.with_file_name(&fname)
1562     }
1563
1564     fn output_testname(&self, filepath: &Path) -> PathBuf {
1565         PathBuf::from(filepath.file_stem().unwrap())
1566     }
1567
1568     /// Given a test path like `compile-fail/foo/bar.rs` Returns a name like
1569     ///
1570     ///     <output>/foo/bar-stage1
1571     fn output_base_name(&self) -> PathBuf {
1572         let dir = self.config.build_base.join(&self.testpaths.relative_dir);
1573
1574         // Note: The directory `dir` is created during `collect_tests_from_dir`
1575         dir
1576             .join(&self.output_testname(&self.testpaths.file))
1577             .with_extension(&self.config.stage_id)
1578     }
1579
1580     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
1581         if self.config.verbose {
1582             println!("------{}------------------------------", "stdout");
1583             println!("{}", out);
1584             println!("------{}------------------------------", "stderr");
1585             println!("{}", err);
1586             println!("------------------------------------------");
1587         }
1588     }
1589
1590     fn error(&self, err: &str) {
1591         match self.revision {
1592             Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1593             None => println!("\nerror: {}", err)
1594         }
1595     }
1596
1597     fn fatal(&self, err: &str) -> ! {
1598         self.error(err); panic!();
1599     }
1600
1601     fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
1602         self.try_print_open_handles();
1603         self.error(err);
1604         proc_res.fatal(None);
1605     }
1606
1607     // This function is a poor man's attempt to debug rust-lang/rust#38620, if
1608     // that's closed then this should be deleted
1609     //
1610     // This is a very "opportunistic" debugging attempt, so we ignore all
1611     // errors here.
1612     fn try_print_open_handles(&self) {
1613         if !cfg!(windows) {
1614             return
1615         }
1616         if self.config.mode != Incremental {
1617             return
1618         }
1619
1620         let filename = match self.testpaths.file.file_stem() {
1621             Some(path) => path,
1622             None => return,
1623         };
1624
1625         let mut cmd = Command::new("handle.exe");
1626         cmd.arg("-a").arg("-u");
1627         cmd.arg(filename);
1628         cmd.arg("-nobanner");
1629         let output = match cmd.output() {
1630             Ok(output) => output,
1631             Err(_) => return,
1632         };
1633         println!("---------------------------------------------------");
1634         println!("ran extra command to debug rust-lang/rust#38620: ");
1635         println!("{:?}", cmd);
1636         println!("result: {}", output.status);
1637         println!("--- stdout ----------------------------------------");
1638         println!("{}", String::from_utf8_lossy(&output.stdout));
1639         println!("--- stderr ----------------------------------------");
1640         println!("{}", String::from_utf8_lossy(&output.stderr));
1641         println!("---------------------------------------------------");
1642     }
1643
1644     // codegen tests (using FileCheck)
1645
1646     fn compile_test_and_save_ir(&self) -> ProcRes {
1647         let aux_dir = self.aux_output_dir_name();
1648
1649         let output_file = TargetLocation::ThisDirectory(
1650             self.output_base_name().parent().unwrap().to_path_buf());
1651         let mut rustc = self.make_compile_args(&self.testpaths.file, output_file);
1652         rustc.arg("-L").arg(aux_dir)
1653             .arg("--emit=llvm-ir");
1654
1655         self.compose_and_run_compiler(rustc, None)
1656     }
1657
1658     fn check_ir_with_filecheck(&self) -> ProcRes {
1659         let irfile = self.output_base_name().with_extension("ll");
1660         let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
1661         filecheck.arg("--input-file").arg(irfile)
1662             .arg(&self.testpaths.file);
1663         self.compose_and_run(filecheck, "", None, None)
1664     }
1665
1666     fn run_codegen_test(&self) {
1667         assert!(self.revision.is_none(), "revisions not relevant here");
1668
1669         if self.config.llvm_filecheck.is_none() {
1670             self.fatal("missing --llvm-filecheck");
1671         }
1672
1673         let mut proc_res = self.compile_test_and_save_ir();
1674         if !proc_res.status.success() {
1675             self.fatal_proc_rec("compilation failed!", &proc_res);
1676         }
1677
1678         proc_res = self.check_ir_with_filecheck();
1679         if !proc_res.status.success() {
1680             self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
1681         }
1682     }
1683
1684     fn charset() -> &'static str {
1685         // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1686         if cfg!(target_os = "bitrig") {
1687             "auto"
1688         } else if cfg!(target_os = "freebsd") {
1689             "ISO-8859-1"
1690         } else {
1691             "UTF-8"
1692         }
1693     }
1694
1695     fn run_rustdoc_test(&self) {
1696         assert!(self.revision.is_none(), "revisions not relevant here");
1697
1698         let out_dir = self.output_base_name();
1699         let _ = fs::remove_dir_all(&out_dir);
1700         create_dir_all(&out_dir).unwrap();
1701
1702         let proc_res = self.document(&out_dir);
1703         if !proc_res.status.success() {
1704             self.fatal_proc_rec("rustdoc failed!", &proc_res);
1705         }
1706
1707         if self.props.check_test_line_numbers_match {
1708             self.check_rustdoc_test_option(proc_res);
1709         } else {
1710             let root = self.config.find_rust_src_root().unwrap();
1711             let res = self.cmd2procres(
1712                 Command::new(&self.config.docck_python)
1713                     .arg(root.join("src/etc/htmldocck.py"))
1714                     .arg(out_dir)
1715                     .arg(&self.testpaths.file),
1716             );
1717             if !res.status.success() {
1718                 self.fatal_proc_rec("htmldocck failed!", &res);
1719             }
1720         }
1721     }
1722
1723     fn get_lines<P: AsRef<Path>>(&self, path: &P,
1724                                  mut other_files: Option<&mut Vec<String>>) -> Vec<usize> {
1725         let mut file = fs::File::open(path)
1726                                 .expect("markdown_test_output_check_entry File::open failed");
1727         let mut content = String::new();
1728         file.read_to_string(&mut content)
1729             .expect("markdown_test_output_check_entry read_to_string failed");
1730         let mut ignore = false;
1731         content.lines()
1732                .enumerate()
1733                .filter_map(|(line_nb, line)| {
1734                    if (line.trim_left().starts_with("pub mod ") ||
1735                        line.trim_left().starts_with("mod ")) &&
1736                       line.ends_with(';') {
1737                        if let Some(ref mut other_files) = other_files {
1738                            other_files.push(line.rsplit("mod ")
1739                                       .next()
1740                                       .unwrap()
1741                                       .replace(";", ""));
1742                        }
1743                        None
1744                    } else {
1745                        let sline = line.split("///").last().unwrap_or("");
1746                        let line = sline.trim_left();
1747                        if line.starts_with("```") {
1748                            if ignore {
1749                                ignore = false;
1750                                None
1751                            } else {
1752                                ignore = true;
1753                                Some(line_nb + 1)
1754                            }
1755                        } else {
1756                            None
1757                        }
1758                    }
1759                })
1760                .collect()
1761     }
1762
1763     fn check_rustdoc_test_option(&self, res: ProcRes) {
1764         let mut other_files = Vec::new();
1765         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
1766         let cwd = env::current_dir().unwrap();
1767         files.insert(self.testpaths.file.strip_prefix(&cwd)
1768                                         .unwrap_or(&self.testpaths.file)
1769                                         .to_str()
1770                                         .unwrap()
1771                                         .replace('\\', "/"),
1772                      self.get_lines(&self.testpaths.file, Some(&mut other_files)));
1773         for other_file in other_files {
1774             let mut path = self.testpaths.file.clone();
1775             path.set_file_name(&format!("{}.rs", other_file));
1776             files.insert(path.strip_prefix(&cwd)
1777                              .unwrap_or(&path)
1778                              .to_str()
1779                              .unwrap()
1780                              .replace('\\', "/"),
1781                          self.get_lines(&path, None));
1782         }
1783
1784         let mut tested = 0;
1785         for _ in res.stdout.split('\n')
1786                            .filter(|s| s.starts_with("test "))
1787                            .inspect(|s| {
1788                                let tmp: Vec<&str> = s.split(" - ").collect();
1789                                if tmp.len() == 2 {
1790                                    let path = tmp[0].rsplit("test ").next().unwrap();
1791                                    if let Some(ref mut v) = files.get_mut(
1792                                                                 &path.replace('\\', "/")) {
1793                                        tested += 1;
1794                                        let mut iter = tmp[1].split("(line ");
1795                                        iter.next();
1796                                        let line = iter.next()
1797                                                       .unwrap_or(")")
1798                                                       .split(')')
1799                                                       .next()
1800                                                       .unwrap_or("0")
1801                                                       .parse()
1802                                                       .unwrap_or(0);
1803                                        if let Ok(pos) = v.binary_search(&line) {
1804                                            v.remove(pos);
1805                                        } else {
1806                                            self.fatal_proc_rec(
1807                                                &format!("Not found doc test: \"{}\" in \"{}\":{:?}",
1808                                                         s, path, v),
1809                                                &res);
1810                                        }
1811                                    }
1812                                }
1813                            }) {}
1814         if tested == 0 {
1815             self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res);
1816         } else {
1817             for (entry, v) in &files {
1818                 if !v.is_empty() {
1819                     self.fatal_proc_rec(&format!("Not found test at line{} \"{}\":{:?}",
1820                                                  if v.len() > 1 { "s" } else { "" }, entry, v),
1821                                         &res);
1822                 }
1823             }
1824         }
1825     }
1826
1827     fn run_codegen_units_test(&self) {
1828         assert!(self.revision.is_none(), "revisions not relevant here");
1829
1830         let proc_res = self.compile_test();
1831
1832         if !proc_res.status.success() {
1833             self.fatal_proc_rec("compilation failed!", &proc_res);
1834         }
1835
1836         self.check_no_compiler_crash(&proc_res);
1837
1838         const PREFIX: &'static str = "TRANS_ITEM ";
1839         const CGU_MARKER: &'static str = "@@";
1840
1841         let actual: Vec<TransItem> = proc_res
1842             .stdout
1843             .lines()
1844             .filter(|line| line.starts_with(PREFIX))
1845             .map(str_to_trans_item)
1846             .collect();
1847
1848         let expected: Vec<TransItem> = errors::load_errors(&self.testpaths.file, None)
1849             .iter()
1850             .map(|e| str_to_trans_item(&e.msg[..]))
1851             .collect();
1852
1853         let mut missing = Vec::new();
1854         let mut wrong_cgus = Vec::new();
1855
1856         for expected_item in &expected {
1857             let actual_item_with_same_name = actual.iter()
1858                                                    .find(|ti| ti.name == expected_item.name);
1859
1860             if let Some(actual_item) = actual_item_with_same_name {
1861                 if !expected_item.codegen_units.is_empty() &&
1862                    // Also check for codegen units
1863                    expected_item.codegen_units != actual_item.codegen_units {
1864                     wrong_cgus.push((expected_item.clone(), actual_item.clone()));
1865                 }
1866             } else {
1867                 missing.push(expected_item.string.clone());
1868             }
1869         }
1870
1871         let unexpected: Vec<_> =
1872             actual.iter()
1873                   .filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
1874                   .map(|acgu| acgu.string.clone())
1875                   .collect();
1876
1877         if !missing.is_empty() {
1878             missing.sort();
1879
1880             println!("\nThese items should have been contained but were not:\n");
1881
1882             for item in &missing {
1883                 println!("{}", item);
1884             }
1885
1886             println!("\n");
1887         }
1888
1889         if !unexpected.is_empty() {
1890             let sorted = {
1891                 let mut sorted = unexpected.clone();
1892                 sorted.sort();
1893                 sorted
1894             };
1895
1896             println!("\nThese items were contained but should not have been:\n");
1897
1898             for item in sorted {
1899                 println!("{}", item);
1900             }
1901
1902             println!("\n");
1903         }
1904
1905         if !wrong_cgus.is_empty() {
1906             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
1907             println!("\nThe following items were assigned to wrong codegen units:\n");
1908
1909             for &(ref expected_item, ref actual_item) in &wrong_cgus {
1910                 println!("{}", expected_item.name);
1911                 println!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
1912                 println!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
1913                 println!("");
1914             }
1915         }
1916
1917         if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())
1918         {
1919             panic!();
1920         }
1921
1922         #[derive(Clone, Eq, PartialEq)]
1923         struct TransItem {
1924             name: String,
1925             codegen_units: HashSet<String>,
1926             string: String,
1927         }
1928
1929         // [TRANS_ITEM] name [@@ (cgu)+]
1930         fn str_to_trans_item(s: &str) -> TransItem {
1931             let s = if s.starts_with(PREFIX) {
1932                 (&s[PREFIX.len()..]).trim()
1933             } else {
1934                 s.trim()
1935             };
1936
1937             let full_string = format!("{}{}", PREFIX, s.trim().to_owned());
1938
1939             let parts: Vec<&str> = s.split(CGU_MARKER)
1940                                     .map(str::trim)
1941                                     .filter(|s| !s.is_empty())
1942                                     .collect();
1943
1944             let name = parts[0].trim();
1945
1946             let cgus = if parts.len() > 1 {
1947                 let cgus_str = parts[1];
1948
1949                 cgus_str.split(' ')
1950                         .map(str::trim)
1951                         .filter(|s| !s.is_empty())
1952                         .map(str::to_owned)
1953                         .collect()
1954             }
1955             else {
1956                 HashSet::new()
1957             };
1958
1959             TransItem {
1960                 name: name.to_owned(),
1961                 codegen_units: cgus,
1962                 string: full_string,
1963             }
1964         }
1965
1966         fn codegen_units_to_str(cgus: &HashSet<String>) -> String
1967         {
1968             let mut cgus: Vec<_> = cgus.iter().collect();
1969             cgus.sort();
1970
1971             let mut string = String::new();
1972             for cgu in cgus {
1973                 string.push_str(&cgu[..]);
1974                 string.push_str(" ");
1975             }
1976
1977             string
1978         }
1979     }
1980
1981     fn init_incremental_test(&self) {
1982         // (See `run_incremental_test` for an overview of how incremental tests work.)
1983
1984         // Before any of the revisions have executed, create the
1985         // incremental workproduct directory.  Delete any old
1986         // incremental work products that may be there from prior
1987         // runs.
1988         let incremental_dir = self.incremental_dir();
1989         if incremental_dir.exists() {
1990             // Canonicalizing the path will convert it to the //?/ format
1991             // on Windows, which enables paths longer than 260 character
1992             let canonicalized = incremental_dir.canonicalize().unwrap();
1993             fs::remove_dir_all(canonicalized).unwrap();
1994         }
1995         fs::create_dir_all(&incremental_dir).unwrap();
1996
1997         if self.config.verbose {
1998             print!("init_incremental_test: incremental_dir={}", incremental_dir.display());
1999         }
2000     }
2001
2002     fn run_incremental_test(&self) {
2003         // Basic plan for a test incremental/foo/bar.rs:
2004         // - load list of revisions rpass1, cfail2, rpass3
2005         //   - each should begin with `rpass`, `cfail`, or `cfail`
2006         //   - if `rpass`, expect compile and execution to succeed
2007         //   - if `cfail`, expect compilation to fail
2008         //   - if `rfail`, expect execution to fail
2009         // - create a directory build/foo/bar.incremental
2010         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass1
2011         //   - because name of revision starts with "rpass", expect success
2012         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C cfail2
2013         //   - because name of revision starts with "cfail", expect an error
2014         //   - load expected errors as usual, but filter for those that end in `[rfail2]`
2015         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass3
2016         //   - because name of revision starts with "rpass", expect success
2017         // - execute build/foo/bar.exe and save output
2018         //
2019         // FIXME -- use non-incremental mode as an oracle? That doesn't apply
2020         // to #[rustc_dirty] and clean tests I guess
2021
2022         let revision = self.revision.expect("incremental tests require a list of revisions");
2023
2024         // Incremental workproduct directory should have already been created.
2025         let incremental_dir = self.incremental_dir();
2026         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
2027
2028         // Add an extra flag pointing at the incremental directory.
2029         let mut revision_props = self.props.clone();
2030         revision_props.incremental_dir = Some(incremental_dir);
2031         revision_props.compile_flags.push(String::from("-Zincremental-info"));
2032
2033         let revision_cx = TestCx {
2034             config: self.config,
2035             props: &revision_props,
2036             testpaths: self.testpaths,
2037             revision: self.revision,
2038         };
2039
2040         if self.config.verbose {
2041             print!("revision={:?} revision_props={:#?}", revision, revision_props);
2042         }
2043
2044         if revision.starts_with("rpass") {
2045             revision_cx.run_rpass_test();
2046         } else if revision.starts_with("rfail") {
2047             revision_cx.run_rfail_test();
2048         } else if revision.starts_with("cfail") {
2049             revision_cx.run_cfail_test();
2050         } else {
2051             revision_cx.fatal(
2052                 "revision name must begin with rpass, rfail, or cfail");
2053         }
2054     }
2055
2056     /// Directory where incremental work products are stored.
2057     fn incremental_dir(&self) -> PathBuf {
2058         self.output_base_name().with_extension("inc")
2059     }
2060
2061     fn run_rmake_test(&self) {
2062         // FIXME(#11094): we should fix these tests
2063         if self.config.host != self.config.target {
2064             return
2065         }
2066
2067         let cwd = env::current_dir().unwrap();
2068         let src_root = self.config.src_base.parent().unwrap()
2069                                            .parent().unwrap()
2070                                            .parent().unwrap();
2071         let src_root = cwd.join(&src_root);
2072
2073         let tmpdir = cwd.join(self.output_base_name());
2074         if tmpdir.exists() {
2075             self.aggressive_rm_rf(&tmpdir).unwrap();
2076         }
2077         create_dir_all(&tmpdir).unwrap();
2078
2079         let host = &self.config.host;
2080         let make = if host.contains("bitrig") || host.contains("dragonfly") ||
2081             host.contains("freebsd") || host.contains("netbsd") ||
2082             host.contains("openbsd") {
2083             "gmake"
2084         } else {
2085             "make"
2086         };
2087
2088         let mut cmd = Command::new(make);
2089         cmd.current_dir(&self.testpaths.file)
2090            .env("TARGET", &self.config.target)
2091            .env("PYTHON", &self.config.docck_python)
2092            .env("S", src_root)
2093            .env("RUST_BUILD_STAGE", &self.config.stage_id)
2094            .env("RUSTC", cwd.join(&self.config.rustc_path))
2095            .env("RUSTDOC",
2096                cwd.join(&self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed")))
2097            .env("TMPDIR", &tmpdir)
2098            .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
2099            .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
2100            .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
2101            .env("LLVM_COMPONENTS", &self.config.llvm_components)
2102            .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags);
2103
2104         // We don't want RUSTFLAGS set from the outside to interfere with
2105         // compiler flags set in the test cases:
2106         cmd.env_remove("RUSTFLAGS");
2107
2108         if self.config.target.contains("msvc") {
2109             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
2110             // and that `lib.exe` lives next to it.
2111             let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
2112
2113             // MSYS doesn't like passing flags of the form `/foo` as it thinks it's
2114             // a path and instead passes `C:\msys64\foo`, so convert all
2115             // `/`-arguments to MSVC here to `-` arguments.
2116             let cflags = self.config.cflags.split(' ').map(|s| s.replace("/", "-"))
2117                                                  .collect::<Vec<_>>().join(" ");
2118
2119             cmd.env("IS_MSVC", "1")
2120                .env("IS_WINDOWS", "1")
2121                .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
2122                .env("CC", format!("'{}' {}", self.config.cc, cflags))
2123                .env("CXX", &self.config.cxx);
2124         } else {
2125             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
2126                .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags));
2127
2128             if self.config.target.contains("windows") {
2129                 cmd.env("IS_WINDOWS", "1");
2130             }
2131         }
2132
2133         let output = cmd.output().expect("failed to spawn `make`");
2134         if !output.status.success() {
2135             let res = ProcRes {
2136                 status: output.status,
2137                 stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
2138                 stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
2139                 cmdline: format!("{:?}", cmd),
2140             };
2141             self.fatal_proc_rec("make failed", &res);
2142         }
2143     }
2144
2145     fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
2146         for e in path.read_dir()? {
2147             let entry = e?;
2148             let path = entry.path();
2149             if entry.file_type()?.is_dir() {
2150                 self.aggressive_rm_rf(&path)?;
2151             } else {
2152                 // Remove readonly files as well on windows (by default we can't)
2153                 fs::remove_file(&path).or_else(|e| {
2154                     if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied {
2155                         let mut meta = entry.metadata()?.permissions();
2156                         meta.set_readonly(false);
2157                         fs::set_permissions(&path, meta)?;
2158                         fs::remove_file(&path)
2159                     } else {
2160                         Err(e)
2161                     }
2162                 })?;
2163             }
2164         }
2165         fs::remove_dir(path)
2166     }
2167
2168     fn run_ui_test(&self) {
2169         let proc_res = self.compile_test();
2170
2171         let expected_stderr_path = self.expected_output_path("stderr");
2172         let expected_stderr = self.load_expected_output(&expected_stderr_path);
2173
2174         let expected_stdout_path = self.expected_output_path("stdout");
2175         let expected_stdout = self.load_expected_output(&expected_stdout_path);
2176
2177         let normalized_stdout =
2178             self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
2179         let normalized_stderr =
2180             self.normalize_output(&proc_res.stderr, &self.props.normalize_stderr);
2181
2182         let mut errors = 0;
2183         errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2184         errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
2185
2186         if errors > 0 {
2187             println!("To update references, run this command from build directory:");
2188             let relative_path_to_file =
2189                 self.testpaths.relative_dir
2190                               .join(self.testpaths.file.file_name().unwrap());
2191             println!("{}/update-references.sh '{}' '{}'",
2192                      self.config.src_base.display(),
2193                      self.config.build_base.display(),
2194                      relative_path_to_file.display());
2195             self.fatal_proc_rec(&format!("{} errors occurred comparing output.", errors),
2196                                 &proc_res);
2197         }
2198
2199         if self.props.run_pass {
2200             let proc_res = self.exec_compiled_test();
2201
2202             if !proc_res.status.success() {
2203                 self.fatal_proc_rec("test run failed!", &proc_res);
2204             }
2205         }
2206     }
2207
2208     fn run_mir_opt_test(&self) {
2209         let proc_res = self.compile_test();
2210
2211         if !proc_res.status.success() {
2212             self.fatal_proc_rec("compilation failed!", &proc_res);
2213         }
2214
2215         let proc_res = self.exec_compiled_test();
2216
2217         if !proc_res.status.success() {
2218             self.fatal_proc_rec("test run failed!", &proc_res);
2219         }
2220         self.check_mir_dump();
2221     }
2222
2223     fn check_mir_dump(&self) {
2224         let mut test_file_contents = String::new();
2225         fs::File::open(self.testpaths.file.clone()).unwrap()
2226                                                    .read_to_string(&mut test_file_contents)
2227                                                    .unwrap();
2228         if let Some(idx) =  test_file_contents.find("// END RUST SOURCE") {
2229             let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
2230             let tests_text_str = String::from(tests_text);
2231             let mut curr_test : Option<&str> = None;
2232             let mut curr_test_contents = Vec::new();
2233             for l in tests_text_str.lines() {
2234                 debug!("line: {:?}", l);
2235                 if l.starts_with("// START ") {
2236                     let (_, t) = l.split_at("// START ".len());
2237                     curr_test = Some(t);
2238                 } else if l.starts_with("// END") {
2239                     let (_, t) = l.split_at("// END ".len());
2240                     if Some(t) != curr_test {
2241                         panic!("mismatched START END test name");
2242                     }
2243                     self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
2244                     curr_test = None;
2245                     curr_test_contents.clear();
2246                 } else if l.is_empty() {
2247                     // ignore
2248                 } else if l.starts_with("// ") {
2249                     let (_, test_content) = l.split_at("// ".len());
2250                     curr_test_contents.push(test_content);
2251                 }
2252             }
2253         }
2254     }
2255
2256     fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
2257         let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap());
2258         let source_file = &self.testpaths.file;
2259         let output_time = t(output_file);
2260         let source_time = t(source_file);
2261         if source_time > output_time {
2262             debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
2263             panic!("test source file `{}` is newer than potentially stale output file `{}`.",
2264                    source_file.display(), test_name);
2265         }
2266     }
2267
2268     fn compare_mir_test_output(&self, test_name: &str, expected_content: &[&str]) {
2269         let mut output_file = PathBuf::new();
2270         output_file.push(self.get_mir_dump_dir());
2271         output_file.push(test_name);
2272         debug!("comparing the contests of: {:?}", output_file);
2273         debug!("with: {:?}", expected_content);
2274         self.check_mir_test_timestamp(test_name, &output_file);
2275
2276         let mut dumped_file = fs::File::open(output_file.clone()).unwrap();
2277         let mut dumped_string = String::new();
2278         dumped_file.read_to_string(&mut dumped_string).unwrap();
2279         let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty());
2280         let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty());
2281
2282         // We expect each non-empty line from expected_content to appear
2283         // in the dump in order, but there may be extra lines interleaved
2284         while let Some(expected_line) = expected_lines.next() {
2285             let e_norm = normalize_mir_line(expected_line);
2286             if e_norm.is_empty() {
2287                 continue;
2288             };
2289             let mut found = false;
2290             while let Some(dumped_line) = dumped_lines.next() {
2291                 let d_norm = normalize_mir_line(dumped_line);
2292                 debug!("found: {:?}", d_norm);
2293                 debug!("expected: {:?}", e_norm);
2294                 if e_norm == d_norm {
2295                     found = true;
2296                     break;
2297                 };
2298             }
2299             if !found {
2300                 let normalize_all = dumped_string.lines()
2301                                                  .map(nocomment_mir_line)
2302                                                  .filter(|l| !l.is_empty())
2303                                                  .collect::<Vec<_>>()
2304                                                  .join("\n");
2305                 panic!("ran out of mir dump output to match against.\n\
2306                         Did not find expected line: {:?}\n\
2307                         Expected:\n{}\n\
2308                         Actual:\n{}",
2309                         expected_line,
2310                         expected_content.join("\n"),
2311                         normalize_all);
2312             }
2313         }
2314     }
2315
2316     fn get_mir_dump_dir(&self) -> PathBuf {
2317         let mut mir_dump_dir = PathBuf::from(self.config.build_base
2318                                                     .as_path()
2319                                                     .to_str()
2320                                                     .unwrap());
2321         debug!("input_file: {:?}", self.testpaths.file);
2322         mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap());
2323         mir_dump_dir
2324     }
2325
2326     fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
2327         let parent_dir = self.testpaths.file.parent().unwrap();
2328         let parent_dir_str = parent_dir.display().to_string();
2329         let mut normalized = output.replace(&parent_dir_str, "$DIR")
2330               .replace("\\", "/") // normalize for paths on windows
2331               .replace("\r\n", "\n") // normalize for linebreaks on windows
2332               .replace("\t", "\\t"); // makes tabs visible
2333         for rule in custom_rules {
2334             normalized = normalized.replace(&rule.0, &rule.1);
2335         }
2336         normalized
2337     }
2338
2339     fn expected_output_path(&self, kind: &str) -> PathBuf {
2340         let extension = match self.revision {
2341             Some(r) => format!("{}.{}", r, kind),
2342             None => kind.to_string(),
2343         };
2344         self.testpaths.file.with_extension(extension)
2345     }
2346
2347     fn load_expected_output(&self, path: &Path) -> String {
2348         if !path.exists() {
2349             return String::new();
2350         }
2351
2352         let mut result = String::new();
2353         match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) {
2354             Ok(_) => result,
2355             Err(e) => {
2356                 self.fatal(&format!("failed to load expected output from `{}`: {}",
2357                                     path.display(), e))
2358             }
2359         }
2360     }
2361
2362     fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
2363         if actual == expected {
2364             return 0;
2365         }
2366
2367         println!("normalized {}:\n{}\n", kind, actual);
2368         println!("expected {}:\n{}\n", kind, expected);
2369         println!("diff of {}:\n", kind);
2370
2371         for diff in diff::lines(expected, actual) {
2372             match diff {
2373                 diff::Result::Left(l)    => println!("-{}", l),
2374                 diff::Result::Both(l, _) => println!(" {}", l),
2375                 diff::Result::Right(r)   => println!("+{}", r),
2376             }
2377         }
2378
2379         let output_file = self.output_base_name().with_extension(kind);
2380         match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
2381             Ok(()) => { }
2382             Err(e) => {
2383                 self.fatal(&format!("failed to write {} to `{}`: {}",
2384                                     kind, output_file.display(), e))
2385             }
2386         }
2387
2388         println!("\nThe actual {0} differed from the expected {0}.", kind);
2389         println!("Actual {} saved to {}", kind, output_file.display());
2390         1
2391     }
2392 }
2393
2394 struct ProcArgs {
2395     prog: String,
2396     args: Vec<String>,
2397 }
2398
2399 pub struct ProcRes {
2400     status: ExitStatus,
2401     stdout: String,
2402     stderr: String,
2403     cmdline: String,
2404 }
2405
2406 impl ProcRes {
2407     pub fn fatal(&self, err: Option<&str>) -> ! {
2408         if let Some(e) = err {
2409             println!("\nerror: {}", e);
2410         }
2411         print!("\
2412             status: {}\n\
2413             command: {}\n\
2414             stdout:\n\
2415             ------------------------------------------\n\
2416             {}\n\
2417             ------------------------------------------\n\
2418             stderr:\n\
2419             ------------------------------------------\n\
2420             {}\n\
2421             ------------------------------------------\n\
2422             \n",
2423                self.status, self.cmdline, self.stdout,
2424                self.stderr);
2425         panic!();
2426     }
2427 }
2428
2429 enum TargetLocation {
2430     ThisFile(PathBuf),
2431     ThisDirectory(PathBuf),
2432 }
2433
2434 fn normalize_mir_line(line: &str) -> String {
2435     nocomment_mir_line(line).replace(char::is_whitespace, "")
2436 }
2437
2438 fn nocomment_mir_line(line: &str) -> &str {
2439     if let Some(idx) = line.find("//") {
2440         let (l, _) = line.split_at(idx);
2441         l.trim_right()
2442     } else {
2443         line
2444     }
2445 }