]> git.lizzy.rs Git - rust.git/blob - src/tools/compiletest/src/runtest.rs
d2a0c776b33e683f4c830b62bd458d2de45cce6a
[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.find_rust_src_root()
576                                         .expect("Could not find Rust source root");
577                 let rust_pp_module_rel_path = Path::new("./src/etc");
578                 let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
579                                                            .to_str()
580                                                            .unwrap()
581                                                            .to_owned();
582                 // write debugger script
583                 let mut script_str = String::with_capacity(2048);
584                 script_str.push_str(&format!("set charset {}\n", Self::charset()));
585                 script_str.push_str("show version\n");
586
587                 match self.config.gdb_version {
588                     Some(version) => {
589                         println!("NOTE: compiletest thinks it is using GDB version {}",
590                                  version);
591
592                         if version > extract_gdb_version("7.4").unwrap() {
593                             // Add the directory containing the pretty printers to
594                             // GDB's script auto loading safe path
595                             script_str.push_str(
596                                 &format!("add-auto-load-safe-path {}\n",
597                                          rust_pp_module_abs_path.replace(r"\", r"\\"))
598                             );
599                         }
600                     }
601                     _ => {
602                         println!("NOTE: compiletest does not know which version of \
603                                   GDB it is using");
604                     }
605                 }
606
607                 // The following line actually doesn't have to do anything with
608                 // pretty printing, it just tells GDB to print values on one line:
609                 script_str.push_str("set print pretty off\n");
610
611                 // Add the pretty printer directory to GDB's source-file search path
612                 script_str.push_str(&format!("directory {}\n",
613                                              rust_pp_module_abs_path));
614
615                 // Load the target executable
616                 script_str.push_str(&format!("file {}\n",
617                                              exe_file.to_str().unwrap()
618                                              .replace(r"\", r"\\")));
619
620                 // Force GDB to print values in the Rust format.
621                 if self.config.gdb_native_rust {
622                     script_str.push_str("set language rust\n");
623                 }
624
625                 // Add line breakpoints
626                 for line in &breakpoint_lines {
627                     script_str.push_str(&format!("break '{}':{}\n",
628                                                  self.testpaths.file.file_name().unwrap()
629                                                  .to_string_lossy(),
630                                                  *line));
631                 }
632
633                 script_str.push_str(&cmds);
634                 script_str.push_str("\nquit\n");
635
636                 debug!("script_str = {}", script_str);
637                 self.dump_output_file(&script_str, "debugger.script");
638
639                 let debugger_script = self.make_out_name("debugger.script");
640
641                 // FIXME (#9639): This needs to handle non-utf8 paths
642                 let debugger_opts =
643                     vec!["-quiet".to_owned(),
644                          "-batch".to_owned(),
645                          "-nx".to_owned(),
646                          format!("-command={}", debugger_script.to_str().unwrap())];
647
648                 let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
649                 gdb.args(&debugger_opts)
650                     .env("PYTHONPATH", rust_pp_module_abs_path);
651
652                 debugger_run_result =
653                     self.compose_and_run(gdb,
654                                          self.config.run_lib_path.to_str().unwrap(),
655                                          None,
656                                          None);
657             }
658         }
659
660         if !debugger_run_result.status.success() {
661             self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
662         }
663
664         self.check_debugger_output(&debugger_run_result, &check_lines);
665     }
666
667     fn find_rust_src_root(&self) -> Option<PathBuf> {
668         let mut path = self.config.src_base.clone();
669         let path_postfix = Path::new("src/etc/lldb_batchmode.py");
670
671         while path.pop() {
672             if path.join(&path_postfix).is_file() {
673                 return Some(path);
674             }
675         }
676
677         None
678     }
679
680     fn run_debuginfo_lldb_test(&self) {
681         assert!(self.revision.is_none(), "revisions not relevant here");
682
683         if self.config.lldb_python_dir.is_none() {
684             self.fatal("Can't run LLDB test because LLDB's python path is not set.");
685         }
686
687         let config = Config {
688             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
689             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
690             .. self.config.clone()
691         };
692
693
694         let test_cx = TestCx {
695             config: &config,
696             ..*self
697         };
698
699         test_cx.run_debuginfo_lldb_test_no_opt();
700     }
701
702     fn run_debuginfo_lldb_test_no_opt(&self) {
703         // compile test file (it should have 'compile-flags:-g' in the header)
704         let compile_result = self.compile_test();
705         if !compile_result.status.success() {
706             self.fatal_proc_rec("compilation failed!", &compile_result);
707         }
708
709         let exe_file = self.make_exe_name();
710
711         match self.config.lldb_version {
712             Some(ref version) => {
713                 println!("NOTE: compiletest thinks it is using LLDB version {}",
714                          version);
715             }
716             _ => {
717                 println!("NOTE: compiletest does not know which version of \
718                           LLDB it is using");
719             }
720         }
721
722         // Parse debugger commands etc from test files
723         let DebuggerCommands {
724             commands,
725             check_lines,
726             breakpoint_lines,
727             ..
728         } = self.parse_debugger_commands(&["lldb"]);
729
730         // Write debugger script:
731         // We don't want to hang when calling `quit` while the process is still running
732         let mut script_str = String::from("settings set auto-confirm true\n");
733
734         // Make LLDB emit its version, so we have it documented in the test output
735         script_str.push_str("version\n");
736
737         // Switch LLDB into "Rust mode"
738         let rust_src_root = self.find_rust_src_root().expect("Could not find Rust source root");
739         let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
740         let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
741                                                    .to_str()
742                                                    .unwrap()
743                                                    .to_owned();
744
745         script_str.push_str(&format!("command script import {}\n",
746                                      &rust_pp_module_abs_path[..])[..]);
747         script_str.push_str("type summary add --no-value ");
748         script_str.push_str("--python-function lldb_rust_formatters.print_val ");
749         script_str.push_str("-x \".*\" --category Rust\n");
750         script_str.push_str("type category enable Rust\n");
751
752         // Set breakpoints on every line that contains the string "#break"
753         let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
754         for line in &breakpoint_lines {
755             script_str.push_str(&format!("breakpoint set --file '{}' --line {}\n",
756                                          source_file_name,
757                                          line));
758         }
759
760         // Append the other commands
761         for line in &commands {
762             script_str.push_str(line);
763             script_str.push_str("\n");
764         }
765
766         // Finally, quit the debugger
767         script_str.push_str("\nquit\n");
768
769         // Write the script into a file
770         debug!("script_str = {}", script_str);
771         self.dump_output_file(&script_str, "debugger.script");
772         let debugger_script = self.make_out_name("debugger.script");
773
774         // Let LLDB execute the script via lldb_batchmode.py
775         let debugger_run_result = self.run_lldb(&exe_file,
776                                                 &debugger_script,
777                                                 &rust_src_root);
778
779         if !debugger_run_result.status.success() {
780             self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
781         }
782
783         self.check_debugger_output(&debugger_run_result, &check_lines);
784     }
785
786     fn run_lldb(&self,
787                 test_executable: &Path,
788                 debugger_script: &Path,
789                 rust_src_root: &Path)
790                 -> ProcRes {
791         // Prepare the lldb_batchmode which executes the debugger script
792         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
793         self.cmd2procres(Command::new(&self.config.lldb_python)
794                          .arg(&lldb_script_path)
795                          .arg(test_executable)
796                          .arg(debugger_script)
797                          .env("PYTHONPATH",
798                               self.config.lldb_python_dir.as_ref().unwrap()))
799     }
800
801     fn cmd2procres(&self, cmd: &mut Command) -> ProcRes {
802         let (status, out, err) = match cmd.output() {
803             Ok(Output { status, stdout, stderr }) => {
804                 (status,
805                  String::from_utf8(stdout).unwrap(),
806                  String::from_utf8(stderr).unwrap())
807             },
808             Err(e) => {
809                 self.fatal(&format!("Failed to setup Python process for \
810                                       LLDB script: {}", e))
811             }
812         };
813
814         self.dump_output(&out, &err);
815         ProcRes {
816             status,
817             stdout: out,
818             stderr: err,
819             cmdline: format!("{:?}", cmd)
820         }
821     }
822
823     fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
824         let directives = debugger_prefixes.iter().map(|prefix| (
825             format!("{}-command", prefix),
826             format!("{}-check", prefix),
827         )).collect::<Vec<_>>();
828
829         let mut breakpoint_lines = vec![];
830         let mut commands = vec![];
831         let mut check_lines = vec![];
832         let mut counter = 1;
833         let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
834         for line in reader.lines() {
835             match line {
836                 Ok(line) => {
837                     if line.contains("#break") {
838                         breakpoint_lines.push(counter);
839                     }
840
841                     for &(ref command_directive, ref check_directive) in &directives {
842                         self.config.parse_name_value_directive(
843                             &line,
844                             command_directive).map(|cmd| {
845                                 commands.push(cmd)
846                             });
847
848                         self.config.parse_name_value_directive(
849                             &line,
850                             check_directive).map(|cmd| {
851                                 check_lines.push(cmd)
852                             });
853                     }
854                 }
855                 Err(e) => {
856                     self.fatal(&format!("Error while parsing debugger commands: {}", e))
857                 }
858             }
859             counter += 1;
860         }
861
862         DebuggerCommands {
863             commands,
864             check_lines,
865             breakpoint_lines,
866         }
867     }
868
869     fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
870         if options.is_none() {
871             return None;
872         }
873
874         // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
875         let options_to_remove = [
876             "-O".to_owned(),
877             "-g".to_owned(),
878             "--debuginfo".to_owned()
879         ];
880         let new_options =
881             self.split_maybe_args(options).into_iter()
882                                           .filter(|x| !options_to_remove.contains(x))
883                                           .collect::<Vec<String>>();
884
885         Some(new_options.join(" "))
886     }
887
888     fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[String]) {
889         let num_check_lines = check_lines.len();
890
891         let mut check_line_index = 0;
892         for line in debugger_run_result.stdout.lines() {
893             if check_line_index >= num_check_lines {
894                 break;
895             }
896
897             if check_single_line(line, &(check_lines[check_line_index])[..]) {
898                 check_line_index += 1;
899             }
900         }
901         if check_line_index != num_check_lines && num_check_lines > 0 {
902             self.fatal_proc_rec(&format!("line not found in debugger output: {}",
903                                          check_lines[check_line_index]),
904                                 debugger_run_result);
905         }
906
907         fn check_single_line(line: &str, check_line: &str) -> bool {
908             // Allow check lines to leave parts unspecified (e.g., uninitialized
909             // bits in the  wrong case of an enum) with the notation "[...]".
910             let line = line.trim();
911             let check_line = check_line.trim();
912             let can_start_anywhere = check_line.starts_with("[...]");
913             let can_end_anywhere = check_line.ends_with("[...]");
914
915             let check_fragments: Vec<&str> = check_line.split("[...]")
916                                                        .filter(|frag| !frag.is_empty())
917                                                        .collect();
918             if check_fragments.is_empty() {
919                 return true;
920             }
921
922             let (mut rest, first_fragment) = if can_start_anywhere {
923                 match line.find(check_fragments[0]) {
924                     Some(pos) => (&line[pos + check_fragments[0].len() ..], 1),
925                     None => return false
926                 }
927             } else {
928                 (line, 0)
929             };
930
931             for current_fragment in &check_fragments[first_fragment..] {
932                 match rest.find(current_fragment) {
933                     Some(pos) => {
934                         rest = &rest[pos + current_fragment.len() .. ];
935                     }
936                     None => return false
937                 }
938             }
939
940             if !can_end_anywhere && !rest.is_empty() {
941                 return false;
942             }
943
944             true
945         }
946     }
947
948     fn check_error_patterns(&self,
949                             output_to_check: &str,
950                             proc_res: &ProcRes) {
951         if self.props.error_patterns.is_empty() {
952             if self.props.must_compile_successfully {
953                 return
954             } else {
955                 self.fatal(&format!("no error pattern specified in {:?}",
956                                     self.testpaths.file.display()));
957             }
958         }
959         let mut next_err_idx = 0;
960         let mut next_err_pat = self.props.error_patterns[next_err_idx].trim();
961         let mut done = false;
962         for line in output_to_check.lines() {
963             if line.contains(next_err_pat) {
964                 debug!("found error pattern {}", next_err_pat);
965                 next_err_idx += 1;
966                 if next_err_idx == self.props.error_patterns.len() {
967                     debug!("found all error patterns");
968                     done = true;
969                     break;
970                 }
971                 next_err_pat = self.props.error_patterns[next_err_idx].trim();
972             }
973         }
974         if done { return; }
975
976         let missing_patterns = &self.props.error_patterns[next_err_idx..];
977         if missing_patterns.len() == 1 {
978             self.fatal_proc_rec(
979                 &format!("error pattern '{}' not found!", missing_patterns[0]),
980                 proc_res);
981         } else {
982             for pattern in missing_patterns {
983                 self.error(&format!("error pattern '{}' not found!", *pattern));
984             }
985             self.fatal_proc_rec("multiple error patterns not found", proc_res);
986         }
987     }
988
989     fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
990         for line in proc_res.stderr.lines() {
991             if line.contains("error: internal compiler error") {
992                 self.fatal_proc_rec("compiler encountered internal error", proc_res);
993             }
994         }
995     }
996
997     fn check_forbid_output(&self,
998                            output_to_check: &str,
999                            proc_res: &ProcRes) {
1000         for pat in &self.props.forbid_output {
1001             if output_to_check.contains(pat) {
1002                 self.fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
1003             }
1004         }
1005     }
1006
1007     fn check_expected_errors(&self,
1008                              expected_errors: Vec<errors::Error>,
1009                              proc_res: &ProcRes) {
1010         if proc_res.status.success() &&
1011             expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) {
1012             self.fatal_proc_rec("process did not return an error status", proc_res);
1013         }
1014
1015         let file_name =
1016             format!("{}", self.testpaths.file.display())
1017             .replace(r"\", "/"); // on windows, translate all '\' path separators to '/'
1018
1019         // If the testcase being checked contains at least one expected "help"
1020         // message, then we'll ensure that all "help" messages are expected.
1021         // Otherwise, all "help" messages reported by the compiler will be ignored.
1022         // This logic also applies to "note" messages.
1023         let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
1024         let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
1025
1026         // Parse the JSON output from the compiler and extract out the messages.
1027         let actual_errors = json::parse_output(&file_name, &proc_res.stderr, proc_res);
1028         let mut unexpected = Vec::new();
1029         let mut found = vec![false; expected_errors.len()];
1030         for actual_error in &actual_errors {
1031             let opt_index =
1032                 expected_errors
1033                 .iter()
1034                 .enumerate()
1035                 .position(|(index, expected_error)| {
1036                     !found[index] &&
1037                         actual_error.line_num == expected_error.line_num &&
1038                         (expected_error.kind.is_none() ||
1039                          actual_error.kind == expected_error.kind) &&
1040                         actual_error.msg.contains(&expected_error.msg)
1041                 });
1042
1043             match opt_index {
1044                 Some(index) => {
1045                     // found a match, everybody is happy
1046                     assert!(!found[index]);
1047                     found[index] = true;
1048                 }
1049
1050                 None => {
1051                     if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
1052                         self.error(
1053                             &format!("{}:{}: unexpected {:?}: '{}'",
1054                                      file_name,
1055                                      actual_error.line_num,
1056                                      actual_error.kind.as_ref()
1057                                      .map_or(String::from("message"),
1058                                              |k| k.to_string()),
1059                                      actual_error.msg));
1060                         unexpected.push(actual_error);
1061                     }
1062                 }
1063             }
1064         }
1065
1066         let mut not_found = Vec::new();
1067         // anything not yet found is a problem
1068         for (index, expected_error) in expected_errors.iter().enumerate() {
1069             if !found[index] {
1070                 self.error(
1071                     &format!("{}:{}: expected {} not found: {}",
1072                              file_name,
1073                              expected_error.line_num,
1074                              expected_error.kind.as_ref()
1075                              .map_or("message".into(),
1076                                      |k| k.to_string()),
1077                              expected_error.msg));
1078                 not_found.push(expected_error);
1079             }
1080         }
1081
1082         if !unexpected.is_empty() || !not_found.is_empty() {
1083             self.error(
1084                 &format!("{} unexpected errors found, {} expected errors not found",
1085                          unexpected.len(), not_found.len()));
1086             println!("status: {}\ncommand: {}",
1087                    proc_res.status, proc_res.cmdline);
1088             if !unexpected.is_empty() {
1089                 println!("unexpected errors (from JSON output): {:#?}\n", unexpected);
1090             }
1091             if !not_found.is_empty() {
1092                 println!("not found errors (from test file): {:#?}\n", not_found);
1093             }
1094             panic!();
1095         }
1096     }
1097
1098     /// Returns true if we should report an error about `actual_error`,
1099     /// which did not match any of the expected error. We always require
1100     /// errors/warnings to be explicitly listed, but only require
1101     /// helps/notes if there are explicit helps/notes given.
1102     fn is_unexpected_compiler_message(&self,
1103                                       actual_error: &Error,
1104                                       expect_help: bool,
1105                                       expect_note: bool)
1106                                       -> bool {
1107         match actual_error.kind {
1108             Some(ErrorKind::Help) => expect_help,
1109             Some(ErrorKind::Note) => expect_note,
1110             Some(ErrorKind::Error) |
1111             Some(ErrorKind::Warning) => true,
1112             Some(ErrorKind::Suggestion) |
1113             None => false
1114         }
1115     }
1116
1117     fn compile_test(&self) -> ProcRes {
1118         let mut rustc = self.make_compile_args(
1119             &self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name()));
1120
1121         rustc.arg("-L").arg(&self.aux_output_dir_name());
1122
1123         match self.config.mode {
1124             CompileFail | Ui => {
1125                 // compile-fail and ui tests tend to have tons of unused code as
1126                 // it's just testing various pieces of the compile, but we don't
1127                 // want to actually assert warnings about all this code. Instead
1128                 // let's just ignore unused code warnings by defaults and tests
1129                 // can turn it back on if needed.
1130                 rustc.args(&["-A", "unused"]);
1131             }
1132             _ => {}
1133         }
1134
1135         self.compose_and_run_compiler(rustc, None)
1136     }
1137
1138     fn document(&self, out_dir: &Path) -> ProcRes {
1139         if self.props.build_aux_docs {
1140             for rel_ab in &self.props.aux_builds {
1141                 let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1142                 let aux_props = self.props.from_aux_file(&aux_testpaths.file,
1143                                                          self.revision,
1144                                                          self.config);
1145                 let aux_cx = TestCx {
1146                     config: self.config,
1147                     props: &aux_props,
1148                     testpaths: &aux_testpaths,
1149                     revision: self.revision
1150                 };
1151                 let auxres = aux_cx.document(out_dir);
1152                 if !auxres.status.success() {
1153                     return auxres;
1154                 }
1155             }
1156         }
1157
1158         let aux_dir = self.aux_output_dir_name();
1159
1160         let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed");
1161         let mut rustdoc = Command::new(rustdoc_path);
1162
1163         rustdoc.arg("-L").arg(aux_dir)
1164             .arg("-o").arg(out_dir)
1165             .arg(&self.testpaths.file)
1166             .args(&self.props.compile_flags);
1167
1168         self.compose_and_run_compiler(rustdoc, None)
1169     }
1170
1171     fn exec_compiled_test(&self) -> ProcRes {
1172         let env = &self.props.exec_env;
1173
1174         match &*self.config.target {
1175             // This is pretty similar to below, we're transforming:
1176             //
1177             //      program arg1 arg2
1178             //
1179             // into
1180             //
1181             //      remote-test-client run program:support-lib.so arg1 arg2
1182             //
1183             // The test-client program will upload `program` to the emulator
1184             // along with all other support libraries listed (in this case
1185             // `support-lib.so`. It will then execute the program on the
1186             // emulator with the arguments specified (in the environment we give
1187             // the process) and then report back the same result.
1188             _ if self.config.remote_test_client.is_some() => {
1189                 let aux_dir = self.aux_output_dir_name();
1190                 let ProcArgs { mut prog, args } = self.make_run_args();
1191                 if let Ok(entries) = aux_dir.read_dir() {
1192                     for entry in entries {
1193                         let entry = entry.unwrap();
1194                         if !entry.path().is_file() {
1195                             continue
1196                         }
1197                         prog.push_str(":");
1198                         prog.push_str(entry.path().to_str().unwrap());
1199                     }
1200                 }
1201                 let mut test_client = Command::new(
1202                     self.config.remote_test_client.as_ref().unwrap());
1203                 test_client
1204                     .args(&["run", &prog])
1205                     .args(args)
1206                     .envs(env.clone());
1207                 self.compose_and_run(test_client,
1208                                      self.config.run_lib_path.to_str().unwrap(),
1209                                      Some(aux_dir.to_str().unwrap()),
1210                                      None)
1211             }
1212             _ => {
1213                 let aux_dir = self.aux_output_dir_name();
1214                 let ProcArgs { prog, args } = self.make_run_args();
1215                 let mut program = Command::new(&prog);
1216                 program.args(args)
1217                     .current_dir(&self.output_base_name().parent().unwrap())
1218                     .envs(env.clone());
1219                 self.compose_and_run(program,
1220                                      self.config.run_lib_path.to_str().unwrap(),
1221                                      Some(aux_dir.to_str().unwrap()),
1222                                      None)
1223             }
1224         }
1225     }
1226
1227     /// For each `aux-build: foo/bar` annotation, we check to find the
1228     /// file in a `aux` directory relative to the test itself.
1229     fn compute_aux_test_paths(&self, rel_ab: &str) -> TestPaths {
1230         let test_ab = self.testpaths.file
1231                                     .parent()
1232                                     .expect("test file path has no parent")
1233                                     .join("auxiliary")
1234                                     .join(rel_ab);
1235         if !test_ab.exists() {
1236             self.fatal(&format!("aux-build `{}` source not found", test_ab.display()))
1237         }
1238
1239         TestPaths {
1240             file: test_ab,
1241             base: self.testpaths.base.clone(),
1242             relative_dir: self.testpaths.relative_dir
1243                                         .join("auxiliary")
1244                                         .join(rel_ab)
1245                                         .parent()
1246                                         .expect("aux-build path has no parent")
1247                                         .to_path_buf()
1248         }
1249     }
1250
1251     fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
1252         if !self.props.aux_builds.is_empty() {
1253             create_dir_all(&self.aux_output_dir_name()).unwrap();
1254         }
1255
1256         let aux_dir = self.aux_output_dir_name();
1257
1258         for rel_ab in &self.props.aux_builds {
1259             let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1260             let aux_props = self.props.from_aux_file(&aux_testpaths.file,
1261                                                      self.revision,
1262                                                      self.config);
1263             let aux_output = {
1264                 let f = self.make_lib_name(&self.testpaths.file);
1265                 let parent = f.parent().unwrap();
1266                 TargetLocation::ThisDirectory(parent.to_path_buf())
1267             };
1268             let aux_cx = TestCx {
1269                 config: self.config,
1270                 props: &aux_props,
1271                 testpaths: &aux_testpaths,
1272                 revision: self.revision
1273             };
1274             let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
1275
1276             let crate_type = if aux_props.no_prefer_dynamic {
1277                 None
1278             } else if (self.config.target.contains("musl") && !aux_props.force_host) ||
1279                       self.config.target.contains("emscripten") {
1280                 // We primarily compile all auxiliary libraries as dynamic libraries
1281                 // to avoid code size bloat and large binaries as much as possible
1282                 // for the test suite (otherwise including libstd statically in all
1283                 // executables takes up quite a bit of space).
1284                 //
1285                 // For targets like MUSL or Emscripten, however, there is no support for
1286                 // dynamic libraries so we just go back to building a normal library. Note,
1287                 // however, that for MUSL if the library is built with `force_host` then
1288                 // it's ok to be a dylib as the host should always support dylibs.
1289                 Some("lib")
1290             } else {
1291                 Some("dylib")
1292             };
1293
1294             if let Some(crate_type) = crate_type {
1295                 aux_rustc.args(&["--crate-type", crate_type]);
1296             }
1297
1298             aux_rustc.arg("-L").arg(&aux_dir);
1299
1300             let auxres = aux_cx.compose_and_run(aux_rustc,
1301                                                 aux_cx.config.compile_lib_path.to_str().unwrap(),
1302                                                 Some(aux_dir.to_str().unwrap()),
1303                                                 None);
1304             if !auxres.status.success() {
1305                 self.fatal_proc_rec(
1306                     &format!("auxiliary build of {:?} failed to compile: ",
1307                              aux_testpaths.file.display()),
1308                     &auxres);
1309             }
1310         }
1311
1312         rustc.envs(self.props.rustc_env.clone());
1313         self.compose_and_run(rustc,
1314                              self.config.compile_lib_path.to_str().unwrap(),
1315                              Some(aux_dir.to_str().unwrap()),
1316                              input)
1317     }
1318
1319     fn compose_and_run(&self,
1320                        mut command: Command,
1321                        lib_path: &str,
1322                        aux_path: Option<&str>,
1323                        input: Option<String>) -> ProcRes {
1324         let cmdline =
1325         {
1326             let cmdline = self.make_cmdline(&command, lib_path);
1327             logv(self.config, format!("executing {}", cmdline));
1328             cmdline
1329         };
1330
1331         command
1332             .stdout(Stdio::piped())
1333             .stderr(Stdio::piped())
1334             .stdin(Stdio::piped());
1335
1336         // Need to be sure to put both the lib_path and the aux path in the dylib
1337         // search path for the child.
1338         let mut path = env::split_paths(&env::var_os(dylib_env_var()).unwrap_or(OsString::new()))
1339             .collect::<Vec<_>>();
1340         if let Some(p) = aux_path {
1341             path.insert(0, PathBuf::from(p))
1342         }
1343         path.insert(0, PathBuf::from(lib_path));
1344
1345         // Add the new dylib search path var
1346         let newpath = env::join_paths(&path).unwrap();
1347         command.env(dylib_env_var(), newpath);
1348
1349         let mut child = command.spawn().expect(&format!("failed to exec `{:?}`", &command));
1350         if let Some(input) = input {
1351             child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
1352         }
1353         let Output { status, stdout, stderr } = child.wait_with_output().unwrap();
1354
1355         let result = ProcRes {
1356             status,
1357             stdout: String::from_utf8(stdout).unwrap(),
1358             stderr: String::from_utf8(stderr).unwrap(),
1359             cmdline,
1360         };
1361
1362         self.dump_output(&result.stdout, &result.stderr);
1363
1364         result
1365     }
1366
1367     fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
1368         let mut rustc = Command::new(&self.config.rustc_path);
1369         rustc.arg(input_file)
1370             .arg("-L").arg(&self.config.build_base);
1371
1372         // Optionally prevent default --target if specified in test compile-flags.
1373         let custom_target = self.props.compile_flags
1374             .iter()
1375             .fold(false, |acc, x| acc || x.starts_with("--target"));
1376
1377         if !custom_target {
1378             let target = if self.props.force_host {
1379                 &*self.config.host
1380             } else {
1381                 &*self.config.target
1382             };
1383
1384             rustc.arg(&format!("--target={}", target));
1385         }
1386
1387         if let Some(revision) = self.revision {
1388             rustc.args(&["--cfg", revision]);
1389         }
1390
1391         if let Some(ref incremental_dir) = self.props.incremental_dir {
1392             rustc.args(&["-Z", &format!("incremental={}", incremental_dir.display())]);
1393         }
1394
1395         match self.config.mode {
1396             CompileFail |
1397             ParseFail |
1398             Incremental => {
1399                 // If we are extracting and matching errors in the new
1400                 // fashion, then you want JSON mode. Old-skool error
1401                 // patterns still match the raw compiler output.
1402                 if self.props.error_patterns.is_empty() {
1403                     rustc.args(&["--error-format", "json"]);
1404                 }
1405             }
1406             MirOpt => {
1407                 rustc.args(&[
1408                     "-Zdump-mir=all",
1409                     "-Zmir-opt-level=3",
1410                     "-Zdump-mir-exclude-pass-number"]);
1411
1412                 let mir_dump_dir = self.get_mir_dump_dir();
1413                 create_dir_all(mir_dump_dir.as_path()).unwrap();
1414                 let mut dir_opt = "-Zdump-mir-dir=".to_string();
1415                 dir_opt.push_str(mir_dump_dir.to_str().unwrap());
1416                 debug!("dir_opt: {:?}", dir_opt);
1417
1418                 rustc.arg(dir_opt);
1419             }
1420             RunPass |
1421             RunFail |
1422             RunPassValgrind |
1423             Pretty |
1424             DebugInfoGdb |
1425             DebugInfoLldb |
1426             Codegen |
1427             Rustdoc |
1428             RunMake |
1429             Ui |
1430             CodegenUnits => {
1431                 // do not use JSON output
1432             }
1433         }
1434
1435         if !self.props.no_prefer_dynamic {
1436             rustc.args(&["-C", "prefer-dynamic"]);
1437         }
1438
1439         match output_file {
1440             TargetLocation::ThisFile(path) => {
1441                 rustc.arg("-o").arg(path);
1442             }
1443             TargetLocation::ThisDirectory(path) => {
1444                 rustc.arg("--out-dir").arg(path);
1445             }
1446         }
1447
1448         if self.props.force_host {
1449             rustc.args(self.split_maybe_args(&self.config.host_rustcflags));
1450         } else {
1451             rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
1452         }
1453
1454         rustc.args(&self.props.compile_flags);
1455
1456         rustc
1457     }
1458
1459     fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
1460         // what we return here is not particularly important, as it
1461         // happens; rustc ignores everything except for the directory.
1462         let auxname = self.output_testname(auxfile);
1463         self.aux_output_dir_name().join(&auxname)
1464     }
1465
1466     fn make_exe_name(&self) -> PathBuf {
1467         let mut f = self.output_base_name();
1468         // FIXME: This is using the host architecture exe suffix, not target!
1469         if self.config.target.contains("emscripten") {
1470             let mut fname = f.file_name().unwrap().to_os_string();
1471             fname.push(".js");
1472             f.set_file_name(&fname);
1473         } else if !env::consts::EXE_SUFFIX.is_empty() {
1474             let mut fname = f.file_name().unwrap().to_os_string();
1475             fname.push(env::consts::EXE_SUFFIX);
1476             f.set_file_name(&fname);
1477         }
1478         f
1479     }
1480
1481     fn make_run_args(&self) -> ProcArgs {
1482         // If we've got another tool to run under (valgrind),
1483         // then split apart its command
1484         let mut args = self.split_maybe_args(&self.config.runtool);
1485
1486         // If this is emscripten, then run tests under nodejs
1487         if self.config.target.contains("emscripten") {
1488             if let Some(ref p) = self.config.nodejs {
1489                 args.push(p.clone());
1490             } else {
1491                 self.fatal("no NodeJS binary found (--nodejs)");
1492             }
1493         }
1494
1495         let exe_file = self.make_exe_name();
1496
1497         // FIXME (#9639): This needs to handle non-utf8 paths
1498         args.push(exe_file.to_str().unwrap().to_owned());
1499
1500         // Add the arguments in the run_flags directive
1501         args.extend(self.split_maybe_args(&self.props.run_flags));
1502
1503         let prog = args.remove(0);
1504          ProcArgs {
1505             prog,
1506             args,
1507         }
1508     }
1509
1510     fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<String> {
1511         match *argstr {
1512             Some(ref s) => {
1513                 s
1514                     .split(' ')
1515                     .filter_map(|s| {
1516                         if s.chars().all(|c| c.is_whitespace()) {
1517                             None
1518                         } else {
1519                             Some(s.to_owned())
1520                         }
1521                     }).collect()
1522             }
1523             None => Vec::new()
1524         }
1525     }
1526
1527     fn make_cmdline(&self, command: &Command, libpath: &str) -> String {
1528         use util;
1529
1530         // Linux and mac don't require adjusting the library search path
1531         if cfg!(unix) {
1532             format!("{:?}", command)
1533         } else {
1534             // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1535             // for diagnostic purposes
1536             fn lib_path_cmd_prefix(path: &str) -> String {
1537                 format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
1538             }
1539
1540             format!("{} {:?}", lib_path_cmd_prefix(libpath), command)
1541         }
1542     }
1543
1544     fn dump_output(&self, out: &str, err: &str) {
1545         let revision = if let Some(r) = self.revision {
1546             format!("{}.", r)
1547         } else {
1548             String::new()
1549         };
1550
1551         self.dump_output_file(out, &format!("{}out", revision));
1552         self.dump_output_file(err, &format!("{}err", revision));
1553         self.maybe_dump_to_stdout(out, err);
1554     }
1555
1556     fn dump_output_file(&self,
1557                         out: &str,
1558                         extension: &str) {
1559         let outfile = self.make_out_name(extension);
1560         File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1561     }
1562
1563     fn make_out_name(&self, extension: &str) -> PathBuf {
1564         self.output_base_name().with_extension(extension)
1565     }
1566
1567     fn aux_output_dir_name(&self) -> PathBuf {
1568         let f = self.output_base_name();
1569         let mut fname = f.file_name().unwrap().to_os_string();
1570         fname.push(&format!(".{}.libaux", self.config.mode));
1571         f.with_file_name(&fname)
1572     }
1573
1574     fn output_testname(&self, filepath: &Path) -> PathBuf {
1575         PathBuf::from(filepath.file_stem().unwrap())
1576     }
1577
1578     /// Given a test path like `compile-fail/foo/bar.rs` Returns a name like
1579     ///
1580     ///     <output>/foo/bar-stage1
1581     fn output_base_name(&self) -> PathBuf {
1582         let dir = self.config.build_base.join(&self.testpaths.relative_dir);
1583
1584         // Note: The directory `dir` is created during `collect_tests_from_dir`
1585         dir
1586             .join(&self.output_testname(&self.testpaths.file))
1587             .with_extension(&self.config.stage_id)
1588     }
1589
1590     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
1591         if self.config.verbose {
1592             println!("------{}------------------------------", "stdout");
1593             println!("{}", out);
1594             println!("------{}------------------------------", "stderr");
1595             println!("{}", err);
1596             println!("------------------------------------------");
1597         }
1598     }
1599
1600     fn error(&self, err: &str) {
1601         match self.revision {
1602             Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1603             None => println!("\nerror: {}", err)
1604         }
1605     }
1606
1607     fn fatal(&self, err: &str) -> ! {
1608         self.error(err); panic!();
1609     }
1610
1611     fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
1612         self.try_print_open_handles();
1613         self.error(err);
1614         proc_res.fatal(None);
1615     }
1616
1617     // This function is a poor man's attempt to debug rust-lang/rust#38620, if
1618     // that's closed then this should be deleted
1619     //
1620     // This is a very "opportunistic" debugging attempt, so we ignore all
1621     // errors here.
1622     fn try_print_open_handles(&self) {
1623         if !cfg!(windows) {
1624             return
1625         }
1626         if self.config.mode != Incremental {
1627             return
1628         }
1629
1630         let filename = match self.testpaths.file.file_stem() {
1631             Some(path) => path,
1632             None => return,
1633         };
1634
1635         let mut cmd = Command::new("handle.exe");
1636         cmd.arg("-a").arg("-u");
1637         cmd.arg(filename);
1638         cmd.arg("-nobanner");
1639         let output = match cmd.output() {
1640             Ok(output) => output,
1641             Err(_) => return,
1642         };
1643         println!("---------------------------------------------------");
1644         println!("ran extra command to debug rust-lang/rust#38620: ");
1645         println!("{:?}", cmd);
1646         println!("result: {}", output.status);
1647         println!("--- stdout ----------------------------------------");
1648         println!("{}", String::from_utf8_lossy(&output.stdout));
1649         println!("--- stderr ----------------------------------------");
1650         println!("{}", String::from_utf8_lossy(&output.stderr));
1651         println!("---------------------------------------------------");
1652     }
1653
1654     // codegen tests (using FileCheck)
1655
1656     fn compile_test_and_save_ir(&self) -> ProcRes {
1657         let aux_dir = self.aux_output_dir_name();
1658
1659         let output_file = TargetLocation::ThisDirectory(
1660             self.output_base_name().parent().unwrap().to_path_buf());
1661         let mut rustc = self.make_compile_args(&self.testpaths.file, output_file);
1662         rustc.arg("-L").arg(aux_dir)
1663             .arg("--emit=llvm-ir");
1664
1665         self.compose_and_run_compiler(rustc, None)
1666     }
1667
1668     fn check_ir_with_filecheck(&self) -> ProcRes {
1669         let irfile = self.output_base_name().with_extension("ll");
1670         let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
1671         filecheck.arg("--input-file").arg(irfile)
1672             .arg(&self.testpaths.file);
1673         self.compose_and_run(filecheck, "", None, None)
1674     }
1675
1676     fn run_codegen_test(&self) {
1677         assert!(self.revision.is_none(), "revisions not relevant here");
1678
1679         if self.config.llvm_filecheck.is_none() {
1680             self.fatal("missing --llvm-filecheck");
1681         }
1682
1683         let mut proc_res = self.compile_test_and_save_ir();
1684         if !proc_res.status.success() {
1685             self.fatal_proc_rec("compilation failed!", &proc_res);
1686         }
1687
1688         proc_res = self.check_ir_with_filecheck();
1689         if !proc_res.status.success() {
1690             self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
1691         }
1692     }
1693
1694     fn charset() -> &'static str {
1695         // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1696         if cfg!(target_os = "bitrig") {
1697             "auto"
1698         } else if cfg!(target_os = "freebsd") {
1699             "ISO-8859-1"
1700         } else {
1701             "UTF-8"
1702         }
1703     }
1704
1705     fn run_rustdoc_test(&self) {
1706         assert!(self.revision.is_none(), "revisions not relevant here");
1707
1708         let out_dir = self.output_base_name();
1709         let _ = fs::remove_dir_all(&out_dir);
1710         create_dir_all(&out_dir).unwrap();
1711
1712         let proc_res = self.document(&out_dir);
1713         if !proc_res.status.success() {
1714             self.fatal_proc_rec("rustdoc failed!", &proc_res);
1715         }
1716
1717         if self.props.check_test_line_numbers_match {
1718             self.check_rustdoc_test_option(proc_res);
1719         } else {
1720             let root = self.find_rust_src_root().unwrap();
1721             let res = self.cmd2procres(Command::new(&self.config.docck_python)
1722                                        .arg(root.join("src/etc/htmldocck.py"))
1723                                        .arg(out_dir)
1724                                        .arg(&self.testpaths.file));
1725             if !res.status.success() {
1726                 self.fatal_proc_rec("htmldocck failed!", &res);
1727             }
1728         }
1729     }
1730
1731     fn get_lines<P: AsRef<Path>>(&self, path: &P,
1732                                  mut other_files: Option<&mut Vec<String>>) -> Vec<usize> {
1733         let mut file = fs::File::open(path)
1734                                 .expect("markdown_test_output_check_entry File::open failed");
1735         let mut content = String::new();
1736         file.read_to_string(&mut content)
1737             .expect("markdown_test_output_check_entry read_to_string failed");
1738         let mut ignore = false;
1739         content.lines()
1740                .enumerate()
1741                .filter_map(|(line_nb, line)| {
1742                    if (line.trim_left().starts_with("pub mod ") ||
1743                        line.trim_left().starts_with("mod ")) &&
1744                       line.ends_with(';') {
1745                        if let Some(ref mut other_files) = other_files {
1746                            other_files.push(line.rsplit("mod ")
1747                                       .next()
1748                                       .unwrap()
1749                                       .replace(";", ""));
1750                        }
1751                        None
1752                    } else {
1753                        let sline = line.split("///").last().unwrap_or("");
1754                        let line = sline.trim_left();
1755                        if line.starts_with("```") {
1756                            if ignore {
1757                                ignore = false;
1758                                None
1759                            } else {
1760                                ignore = true;
1761                                Some(line_nb + 1)
1762                            }
1763                        } else {
1764                            None
1765                        }
1766                    }
1767                })
1768                .collect()
1769     }
1770
1771     fn check_rustdoc_test_option(&self, res: ProcRes) {
1772         let mut other_files = Vec::new();
1773         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
1774         let cwd = env::current_dir().unwrap();
1775         files.insert(self.testpaths.file.strip_prefix(&cwd)
1776                                         .unwrap_or(&self.testpaths.file)
1777                                         .to_str()
1778                                         .unwrap()
1779                                         .replace('\\', "/"),
1780                      self.get_lines(&self.testpaths.file, Some(&mut other_files)));
1781         for other_file in other_files {
1782             let mut path = self.testpaths.file.clone();
1783             path.set_file_name(&format!("{}.rs", other_file));
1784             files.insert(path.strip_prefix(&cwd)
1785                              .unwrap_or(&path)
1786                              .to_str()
1787                              .unwrap()
1788                              .replace('\\', "/"),
1789                          self.get_lines(&path, None));
1790         }
1791
1792         let mut tested = 0;
1793         for _ in res.stdout.split('\n')
1794                            .filter(|s| s.starts_with("test "))
1795                            .inspect(|s| {
1796                                let tmp: Vec<&str> = s.split(" - ").collect();
1797                                if tmp.len() == 2 {
1798                                    let path = tmp[0].rsplit("test ").next().unwrap();
1799                                    if let Some(ref mut v) = files.get_mut(
1800                                                                 &path.replace('\\', "/")) {
1801                                        tested += 1;
1802                                        let mut iter = tmp[1].split("(line ");
1803                                        iter.next();
1804                                        let line = iter.next()
1805                                                       .unwrap_or(")")
1806                                                       .split(')')
1807                                                       .next()
1808                                                       .unwrap_or("0")
1809                                                       .parse()
1810                                                       .unwrap_or(0);
1811                                        if let Ok(pos) = v.binary_search(&line) {
1812                                            v.remove(pos);
1813                                        } else {
1814                                            self.fatal_proc_rec(
1815                                                &format!("Not found doc test: \"{}\" in \"{}\":{:?}",
1816                                                         s, path, v),
1817                                                &res);
1818                                        }
1819                                    }
1820                                }
1821                            }) {}
1822         if tested == 0 {
1823             self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res);
1824         } else {
1825             for (entry, v) in &files {
1826                 if !v.is_empty() {
1827                     self.fatal_proc_rec(&format!("Not found test at line{} \"{}\":{:?}",
1828                                                  if v.len() > 1 { "s" } else { "" }, entry, v),
1829                                         &res);
1830                 }
1831             }
1832         }
1833     }
1834
1835     fn run_codegen_units_test(&self) {
1836         assert!(self.revision.is_none(), "revisions not relevant here");
1837
1838         let proc_res = self.compile_test();
1839
1840         if !proc_res.status.success() {
1841             self.fatal_proc_rec("compilation failed!", &proc_res);
1842         }
1843
1844         self.check_no_compiler_crash(&proc_res);
1845
1846         const PREFIX: &'static str = "TRANS_ITEM ";
1847         const CGU_MARKER: &'static str = "@@";
1848
1849         let actual: Vec<TransItem> = proc_res
1850             .stdout
1851             .lines()
1852             .filter(|line| line.starts_with(PREFIX))
1853             .map(str_to_trans_item)
1854             .collect();
1855
1856         let expected: Vec<TransItem> = errors::load_errors(&self.testpaths.file, None)
1857             .iter()
1858             .map(|e| str_to_trans_item(&e.msg[..]))
1859             .collect();
1860
1861         let mut missing = Vec::new();
1862         let mut wrong_cgus = Vec::new();
1863
1864         for expected_item in &expected {
1865             let actual_item_with_same_name = actual.iter()
1866                                                    .find(|ti| ti.name == expected_item.name);
1867
1868             if let Some(actual_item) = actual_item_with_same_name {
1869                 if !expected_item.codegen_units.is_empty() &&
1870                    // Also check for codegen units
1871                    expected_item.codegen_units != actual_item.codegen_units {
1872                     wrong_cgus.push((expected_item.clone(), actual_item.clone()));
1873                 }
1874             } else {
1875                 missing.push(expected_item.string.clone());
1876             }
1877         }
1878
1879         let unexpected: Vec<_> =
1880             actual.iter()
1881                   .filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
1882                   .map(|acgu| acgu.string.clone())
1883                   .collect();
1884
1885         if !missing.is_empty() {
1886             missing.sort();
1887
1888             println!("\nThese items should have been contained but were not:\n");
1889
1890             for item in &missing {
1891                 println!("{}", item);
1892             }
1893
1894             println!("\n");
1895         }
1896
1897         if !unexpected.is_empty() {
1898             let sorted = {
1899                 let mut sorted = unexpected.clone();
1900                 sorted.sort();
1901                 sorted
1902             };
1903
1904             println!("\nThese items were contained but should not have been:\n");
1905
1906             for item in sorted {
1907                 println!("{}", item);
1908             }
1909
1910             println!("\n");
1911         }
1912
1913         if !wrong_cgus.is_empty() {
1914             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
1915             println!("\nThe following items were assigned to wrong codegen units:\n");
1916
1917             for &(ref expected_item, ref actual_item) in &wrong_cgus {
1918                 println!("{}", expected_item.name);
1919                 println!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
1920                 println!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
1921                 println!("");
1922             }
1923         }
1924
1925         if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())
1926         {
1927             panic!();
1928         }
1929
1930         #[derive(Clone, Eq, PartialEq)]
1931         struct TransItem {
1932             name: String,
1933             codegen_units: HashSet<String>,
1934             string: String,
1935         }
1936
1937         // [TRANS_ITEM] name [@@ (cgu)+]
1938         fn str_to_trans_item(s: &str) -> TransItem {
1939             let s = if s.starts_with(PREFIX) {
1940                 (&s[PREFIX.len()..]).trim()
1941             } else {
1942                 s.trim()
1943             };
1944
1945             let full_string = format!("{}{}", PREFIX, s.trim().to_owned());
1946
1947             let parts: Vec<&str> = s.split(CGU_MARKER)
1948                                     .map(str::trim)
1949                                     .filter(|s| !s.is_empty())
1950                                     .collect();
1951
1952             let name = parts[0].trim();
1953
1954             let cgus = if parts.len() > 1 {
1955                 let cgus_str = parts[1];
1956
1957                 cgus_str.split(' ')
1958                         .map(str::trim)
1959                         .filter(|s| !s.is_empty())
1960                         .map(str::to_owned)
1961                         .collect()
1962             }
1963             else {
1964                 HashSet::new()
1965             };
1966
1967             TransItem {
1968                 name: name.to_owned(),
1969                 codegen_units: cgus,
1970                 string: full_string,
1971             }
1972         }
1973
1974         fn codegen_units_to_str(cgus: &HashSet<String>) -> String
1975         {
1976             let mut cgus: Vec<_> = cgus.iter().collect();
1977             cgus.sort();
1978
1979             let mut string = String::new();
1980             for cgu in cgus {
1981                 string.push_str(&cgu[..]);
1982                 string.push_str(" ");
1983             }
1984
1985             string
1986         }
1987     }
1988
1989     fn init_incremental_test(&self) {
1990         // (See `run_incremental_test` for an overview of how incremental tests work.)
1991
1992         // Before any of the revisions have executed, create the
1993         // incremental workproduct directory.  Delete any old
1994         // incremental work products that may be there from prior
1995         // runs.
1996         let incremental_dir = self.incremental_dir();
1997         if incremental_dir.exists() {
1998             // Canonicalizing the path will convert it to the //?/ format
1999             // on Windows, which enables paths longer than 260 character
2000             let canonicalized = incremental_dir.canonicalize().unwrap();
2001             fs::remove_dir_all(canonicalized).unwrap();
2002         }
2003         fs::create_dir_all(&incremental_dir).unwrap();
2004
2005         if self.config.verbose {
2006             print!("init_incremental_test: incremental_dir={}", incremental_dir.display());
2007         }
2008     }
2009
2010     fn run_incremental_test(&self) {
2011         // Basic plan for a test incremental/foo/bar.rs:
2012         // - load list of revisions rpass1, cfail2, rpass3
2013         //   - each should begin with `rpass`, `cfail`, or `cfail`
2014         //   - if `rpass`, expect compile and execution to succeed
2015         //   - if `cfail`, expect compilation to fail
2016         //   - if `rfail`, expect execution to fail
2017         // - create a directory build/foo/bar.incremental
2018         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass1
2019         //   - because name of revision starts with "rpass", expect success
2020         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C cfail2
2021         //   - because name of revision starts with "cfail", expect an error
2022         //   - load expected errors as usual, but filter for those that end in `[rfail2]`
2023         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass3
2024         //   - because name of revision starts with "rpass", expect success
2025         // - execute build/foo/bar.exe and save output
2026         //
2027         // FIXME -- use non-incremental mode as an oracle? That doesn't apply
2028         // to #[rustc_dirty] and clean tests I guess
2029
2030         let revision = self.revision.expect("incremental tests require a list of revisions");
2031
2032         // Incremental workproduct directory should have already been created.
2033         let incremental_dir = self.incremental_dir();
2034         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
2035
2036         // Add an extra flag pointing at the incremental directory.
2037         let mut revision_props = self.props.clone();
2038         revision_props.incremental_dir = Some(incremental_dir);
2039         revision_props.compile_flags.push(String::from("-Zincremental-info"));
2040
2041         let revision_cx = TestCx {
2042             config: self.config,
2043             props: &revision_props,
2044             testpaths: self.testpaths,
2045             revision: self.revision,
2046         };
2047
2048         if self.config.verbose {
2049             print!("revision={:?} revision_props={:#?}", revision, revision_props);
2050         }
2051
2052         if revision.starts_with("rpass") {
2053             revision_cx.run_rpass_test();
2054         } else if revision.starts_with("rfail") {
2055             revision_cx.run_rfail_test();
2056         } else if revision.starts_with("cfail") {
2057             revision_cx.run_cfail_test();
2058         } else {
2059             revision_cx.fatal(
2060                 "revision name must begin with rpass, rfail, or cfail");
2061         }
2062     }
2063
2064     /// Directory where incremental work products are stored.
2065     fn incremental_dir(&self) -> PathBuf {
2066         self.output_base_name().with_extension("inc")
2067     }
2068
2069     fn run_rmake_test(&self) {
2070         // FIXME(#11094): we should fix these tests
2071         if self.config.host != self.config.target {
2072             return
2073         }
2074
2075         let cwd = env::current_dir().unwrap();
2076         let src_root = self.config.src_base.parent().unwrap()
2077                                            .parent().unwrap()
2078                                            .parent().unwrap();
2079         let src_root = cwd.join(&src_root);
2080
2081         let tmpdir = cwd.join(self.output_base_name());
2082         if tmpdir.exists() {
2083             self.aggressive_rm_rf(&tmpdir).unwrap();
2084         }
2085         create_dir_all(&tmpdir).unwrap();
2086
2087         let host = &self.config.host;
2088         let make = if host.contains("bitrig") || host.contains("dragonfly") ||
2089             host.contains("freebsd") || host.contains("netbsd") ||
2090             host.contains("openbsd") {
2091             "gmake"
2092         } else {
2093             "make"
2094         };
2095
2096         let mut cmd = Command::new(make);
2097         cmd.current_dir(&self.testpaths.file)
2098            .env("TARGET", &self.config.target)
2099            .env("PYTHON", &self.config.docck_python)
2100            .env("S", src_root)
2101            .env("RUST_BUILD_STAGE", &self.config.stage_id)
2102            .env("RUSTC", cwd.join(&self.config.rustc_path))
2103            .env("RUSTDOC",
2104                cwd.join(&self.config.rustdoc_path.as_ref().expect("--rustdoc-path passed")))
2105            .env("TMPDIR", &tmpdir)
2106            .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
2107            .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
2108            .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
2109            .env("LLVM_COMPONENTS", &self.config.llvm_components)
2110            .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags);
2111
2112         // We don't want RUSTFLAGS set from the outside to interfere with
2113         // compiler flags set in the test cases:
2114         cmd.env_remove("RUSTFLAGS");
2115
2116         if self.config.target.contains("msvc") {
2117             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
2118             // and that `lib.exe` lives next to it.
2119             let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
2120
2121             // MSYS doesn't like passing flags of the form `/foo` as it thinks it's
2122             // a path and instead passes `C:\msys64\foo`, so convert all
2123             // `/`-arguments to MSVC here to `-` arguments.
2124             let cflags = self.config.cflags.split(' ').map(|s| s.replace("/", "-"))
2125                                                  .collect::<Vec<_>>().join(" ");
2126
2127             cmd.env("IS_MSVC", "1")
2128                .env("IS_WINDOWS", "1")
2129                .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
2130                .env("CC", format!("'{}' {}", self.config.cc, cflags))
2131                .env("CXX", &self.config.cxx);
2132         } else {
2133             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
2134                .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags));
2135
2136             if self.config.target.contains("windows") {
2137                 cmd.env("IS_WINDOWS", "1");
2138             }
2139         }
2140
2141         let output = cmd.output().expect("failed to spawn `make`");
2142         if !output.status.success() {
2143             let res = ProcRes {
2144                 status: output.status,
2145                 stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
2146                 stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
2147                 cmdline: format!("{:?}", cmd),
2148             };
2149             self.fatal_proc_rec("make failed", &res);
2150         }
2151     }
2152
2153     fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
2154         for e in path.read_dir()? {
2155             let entry = e?;
2156             let path = entry.path();
2157             if entry.file_type()?.is_dir() {
2158                 self.aggressive_rm_rf(&path)?;
2159             } else {
2160                 // Remove readonly files as well on windows (by default we can't)
2161                 fs::remove_file(&path).or_else(|e| {
2162                     if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied {
2163                         let mut meta = entry.metadata()?.permissions();
2164                         meta.set_readonly(false);
2165                         fs::set_permissions(&path, meta)?;
2166                         fs::remove_file(&path)
2167                     } else {
2168                         Err(e)
2169                     }
2170                 })?;
2171             }
2172         }
2173         fs::remove_dir(path)
2174     }
2175
2176     fn run_ui_test(&self) {
2177         println!("ui: {}", self.testpaths.file.display());
2178
2179         let proc_res = self.compile_test();
2180
2181         let expected_stderr_path = self.expected_output_path("stderr");
2182         let expected_stderr = self.load_expected_output(&expected_stderr_path);
2183
2184         let expected_stdout_path = self.expected_output_path("stdout");
2185         let expected_stdout = self.load_expected_output(&expected_stdout_path);
2186
2187         let normalized_stdout =
2188             self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
2189         let normalized_stderr =
2190             self.normalize_output(&proc_res.stderr, &self.props.normalize_stderr);
2191
2192         let mut errors = 0;
2193         errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2194         errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
2195
2196         if errors > 0 {
2197             println!("To update references, run this command from build directory:");
2198             let relative_path_to_file =
2199                 self.testpaths.relative_dir
2200                               .join(self.testpaths.file.file_name().unwrap());
2201             println!("{}/update-references.sh '{}' '{}'",
2202                      self.config.src_base.display(),
2203                      self.config.build_base.display(),
2204                      relative_path_to_file.display());
2205             self.fatal_proc_rec(&format!("{} errors occurred comparing output.", errors),
2206                                 &proc_res);
2207         }
2208
2209         if self.props.run_pass {
2210             let proc_res = self.exec_compiled_test();
2211
2212             if !proc_res.status.success() {
2213                 self.fatal_proc_rec("test run failed!", &proc_res);
2214             }
2215         }
2216     }
2217
2218     fn run_mir_opt_test(&self) {
2219         let proc_res = self.compile_test();
2220
2221         if !proc_res.status.success() {
2222             self.fatal_proc_rec("compilation failed!", &proc_res);
2223         }
2224
2225         let proc_res = self.exec_compiled_test();
2226
2227         if !proc_res.status.success() {
2228             self.fatal_proc_rec("test run failed!", &proc_res);
2229         }
2230         self.check_mir_dump();
2231     }
2232
2233     fn check_mir_dump(&self) {
2234         let mut test_file_contents = String::new();
2235         fs::File::open(self.testpaths.file.clone()).unwrap()
2236                                                    .read_to_string(&mut test_file_contents)
2237                                                    .unwrap();
2238         if let Some(idx) =  test_file_contents.find("// END RUST SOURCE") {
2239             let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
2240             let tests_text_str = String::from(tests_text);
2241             let mut curr_test : Option<&str> = None;
2242             let mut curr_test_contents = Vec::new();
2243             for l in tests_text_str.lines() {
2244                 debug!("line: {:?}", l);
2245                 if l.starts_with("// START ") {
2246                     let (_, t) = l.split_at("// START ".len());
2247                     curr_test = Some(t);
2248                 } else if l.starts_with("// END") {
2249                     let (_, t) = l.split_at("// END ".len());
2250                     if Some(t) != curr_test {
2251                         panic!("mismatched START END test name");
2252                     }
2253                     self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
2254                     curr_test = None;
2255                     curr_test_contents.clear();
2256                 } else if l.is_empty() {
2257                     // ignore
2258                 } else if l.starts_with("// ") {
2259                     let (_, test_content) = l.split_at("// ".len());
2260                     curr_test_contents.push(test_content);
2261                 }
2262             }
2263         }
2264     }
2265
2266     fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
2267         let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap());
2268         let source_file = &self.testpaths.file;
2269         let output_time = t(output_file);
2270         let source_time = t(source_file);
2271         if source_time > output_time {
2272             debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
2273             panic!("test source file `{}` is newer than potentially stale output file `{}`.",
2274                    source_file.display(), test_name);
2275         }
2276     }
2277
2278     fn compare_mir_test_output(&self, test_name: &str, expected_content: &[&str]) {
2279         let mut output_file = PathBuf::new();
2280         output_file.push(self.get_mir_dump_dir());
2281         output_file.push(test_name);
2282         debug!("comparing the contests of: {:?}", output_file);
2283         debug!("with: {:?}", expected_content);
2284         self.check_mir_test_timestamp(test_name, &output_file);
2285
2286         let mut dumped_file = fs::File::open(output_file.clone()).unwrap();
2287         let mut dumped_string = String::new();
2288         dumped_file.read_to_string(&mut dumped_string).unwrap();
2289         let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty());
2290         let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty());
2291
2292         // We expect each non-empty line from expected_content to appear
2293         // in the dump in order, but there may be extra lines interleaved
2294         while let Some(expected_line) = expected_lines.next() {
2295             let e_norm = normalize_mir_line(expected_line);
2296             if e_norm.is_empty() {
2297                 continue;
2298             };
2299             let mut found = false;
2300             while let Some(dumped_line) = dumped_lines.next() {
2301                 let d_norm = normalize_mir_line(dumped_line);
2302                 debug!("found: {:?}", d_norm);
2303                 debug!("expected: {:?}", e_norm);
2304                 if e_norm == d_norm {
2305                     found = true;
2306                     break;
2307                 };
2308             }
2309             if !found {
2310                 let normalize_all = dumped_string.lines()
2311                                                  .map(nocomment_mir_line)
2312                                                  .filter(|l| !l.is_empty())
2313                                                  .collect::<Vec<_>>()
2314                                                  .join("\n");
2315                 panic!("ran out of mir dump output to match against.\n\
2316                         Did not find expected line: {:?}\n\
2317                         Expected:\n{}\n\
2318                         Actual:\n{}",
2319                         expected_line,
2320                         expected_content.join("\n"),
2321                         normalize_all);
2322             }
2323         }
2324     }
2325
2326     fn get_mir_dump_dir(&self) -> PathBuf {
2327         let mut mir_dump_dir = PathBuf::from(self.config.build_base
2328                                                     .as_path()
2329                                                     .to_str()
2330                                                     .unwrap());
2331         debug!("input_file: {:?}", self.testpaths.file);
2332         mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap());
2333         mir_dump_dir
2334     }
2335
2336     fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
2337         let parent_dir = self.testpaths.file.parent().unwrap();
2338         let parent_dir_str = parent_dir.display().to_string();
2339         let mut normalized = output.replace(&parent_dir_str, "$DIR")
2340               .replace("\\", "/") // normalize for paths on windows
2341               .replace("\r\n", "\n") // normalize for linebreaks on windows
2342               .replace("\t", "\\t"); // makes tabs visible
2343         for rule in custom_rules {
2344             normalized = normalized.replace(&rule.0, &rule.1);
2345         }
2346         normalized
2347     }
2348
2349     fn expected_output_path(&self, kind: &str) -> PathBuf {
2350         let extension = match self.revision {
2351             Some(r) => format!("{}.{}", r, kind),
2352             None => kind.to_string(),
2353         };
2354         self.testpaths.file.with_extension(extension)
2355     }
2356
2357     fn load_expected_output(&self, path: &Path) -> String {
2358         if !path.exists() {
2359             return String::new();
2360         }
2361
2362         let mut result = String::new();
2363         match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) {
2364             Ok(_) => result,
2365             Err(e) => {
2366                 self.fatal(&format!("failed to load expected output from `{}`: {}",
2367                                     path.display(), e))
2368             }
2369         }
2370     }
2371
2372     fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
2373         if actual == expected {
2374             return 0;
2375         }
2376
2377         println!("normalized {}:\n{}\n", kind, actual);
2378         println!("expected {}:\n{}\n", kind, expected);
2379         println!("diff of {}:\n", kind);
2380
2381         for diff in diff::lines(expected, actual) {
2382             match diff {
2383                 diff::Result::Left(l)    => println!("-{}", l),
2384                 diff::Result::Both(l, _) => println!(" {}", l),
2385                 diff::Result::Right(r)   => println!("+{}", r),
2386             }
2387         }
2388
2389         let output_file = self.output_base_name().with_extension(kind);
2390         match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
2391             Ok(()) => { }
2392             Err(e) => {
2393                 self.fatal(&format!("failed to write {} to `{}`: {}",
2394                                     kind, output_file.display(), e))
2395             }
2396         }
2397
2398         println!("\nThe actual {0} differed from the expected {0}.", kind);
2399         println!("Actual {} saved to {}", kind, output_file.display());
2400         1
2401     }
2402 }
2403
2404 struct ProcArgs {
2405     prog: String,
2406     args: Vec<String>,
2407 }
2408
2409 pub struct ProcRes {
2410     status: ExitStatus,
2411     stdout: String,
2412     stderr: String,
2413     cmdline: String,
2414 }
2415
2416 impl ProcRes {
2417     pub fn fatal(&self, err: Option<&str>) -> ! {
2418         if let Some(e) = err {
2419             println!("\nerror: {}", e);
2420         }
2421         print!("\
2422             status: {}\n\
2423             command: {}\n\
2424             stdout:\n\
2425             ------------------------------------------\n\
2426             {}\n\
2427             ------------------------------------------\n\
2428             stderr:\n\
2429             ------------------------------------------\n\
2430             {}\n\
2431             ------------------------------------------\n\
2432             \n",
2433                self.status, self.cmdline, self.stdout,
2434                self.stderr);
2435         panic!();
2436     }
2437 }
2438
2439 enum TargetLocation {
2440     ThisFile(PathBuf),
2441     ThisDirectory(PathBuf),
2442 }
2443
2444 fn normalize_mir_line(line: &str) -> String {
2445     nocomment_mir_line(line).replace(char::is_whitespace, "")
2446 }
2447
2448 fn nocomment_mir_line(line: &str) -> &str {
2449     if let Some(idx) = line.find("//") {
2450         let (l, _) = line.split_at(idx);
2451         l.trim_right()
2452     } else {
2453         line
2454     }
2455 }