]> git.lizzy.rs Git - rust.git/blob - src/tools/compiletest/src/runtest.rs
8c3b1bb4df333a6fbbddf38e563cd648b48dc309
[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::CompareMode;
12 use common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
13 use common::{output_base_dir, output_base_name, output_testname_unique};
14 use common::{Codegen, CodegenUnits, DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Rustdoc};
15 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
16 use common::{Config, TestPaths};
17 use common::{Incremental, MirOpt, RunMake, Ui};
18 use diff;
19 use errors::{self, Error, ErrorKind};
20 use filetime::FileTime;
21 use header::TestProps;
22 use json;
23 use regex::Regex;
24 use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
25 use util::{logv, PathBufExt};
26
27 use std::collections::hash_map::DefaultHasher;
28 use std::collections::{HashMap, HashSet, VecDeque};
29 use std::env;
30 use std::ffi::OsString;
31 use std::fmt;
32 use std::fs::{self, create_dir_all, File};
33 use std::hash::{Hash, Hasher};
34 use std::io::prelude::*;
35 use std::io::{self, BufReader};
36 use std::path::{Path, PathBuf};
37 use std::process::{Child, Command, ExitStatus, Output, Stdio};
38 use std::str;
39
40 use extract_gdb_version;
41 use is_android_gdb_target;
42
43 #[cfg(windows)]
44 fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
45     use std::sync::Mutex;
46     const SEM_NOGPFAULTERRORBOX: u32 = 0x0002;
47     extern "system" {
48         fn SetErrorMode(mode: u32) -> u32;
49     }
50
51     lazy_static! {
52         static ref LOCK: Mutex<()> = { Mutex::new(()) };
53     }
54     // Error mode is a global variable, so lock it so only one thread will change it
55     let _lock = LOCK.lock().unwrap();
56
57     // Tell Windows to not show any UI on errors (such as terminating abnormally).
58     // This is important for running tests, since some of them use abnormal
59     // termination by design. This mode is inherited by all child processes.
60     unsafe {
61         let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
62         SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
63         let r = f();
64         SetErrorMode(old_mode);
65         r
66     }
67 }
68
69 #[cfg(not(windows))]
70 fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
71     f()
72 }
73
74 /// The name of the environment variable that holds dynamic library locations.
75 pub fn dylib_env_var() -> &'static str {
76     if cfg!(windows) {
77         "PATH"
78     } else if cfg!(target_os = "macos") {
79         "DYLD_LIBRARY_PATH"
80     } else if cfg!(target_os = "haiku") {
81         "LIBRARY_PATH"
82     } else {
83         "LD_LIBRARY_PATH"
84     }
85 }
86
87 #[derive(Debug, PartialEq)]
88 pub enum DiffLine {
89     Context(String),
90     Expected(String),
91     Resulting(String),
92 }
93
94 #[derive(Debug, PartialEq)]
95 pub struct Mismatch {
96     pub line_number: u32,
97     pub lines: Vec<DiffLine>,
98 }
99
100 impl Mismatch {
101     fn new(line_number: u32) -> Mismatch {
102         Mismatch {
103             line_number: line_number,
104             lines: Vec::new(),
105         }
106     }
107 }
108
109 // Produces a diff between the expected output and actual output.
110 pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
111     let mut line_number = 1;
112     let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
113     let mut lines_since_mismatch = context_size + 1;
114     let mut results = Vec::new();
115     let mut mismatch = Mismatch::new(0);
116
117     for result in diff::lines(expected, actual) {
118         match result {
119             diff::Result::Left(str) => {
120                 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
121                     results.push(mismatch);
122                     mismatch = Mismatch::new(line_number - context_queue.len() as u32);
123                 }
124
125                 while let Some(line) = context_queue.pop_front() {
126                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
127                 }
128
129                 mismatch.lines.push(DiffLine::Expected(str.to_owned()));
130                 line_number += 1;
131                 lines_since_mismatch = 0;
132             }
133             diff::Result::Right(str) => {
134                 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
135                     results.push(mismatch);
136                     mismatch = Mismatch::new(line_number - context_queue.len() as u32);
137                 }
138
139                 while let Some(line) = context_queue.pop_front() {
140                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
141                 }
142
143                 mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
144                 lines_since_mismatch = 0;
145             }
146             diff::Result::Both(str, _) => {
147                 if context_queue.len() >= context_size {
148                     let _ = context_queue.pop_front();
149                 }
150
151                 if lines_since_mismatch < context_size {
152                     mismatch.lines.push(DiffLine::Context(str.to_owned()));
153                 } else if context_size > 0 {
154                     context_queue.push_back(str);
155                 }
156
157                 line_number += 1;
158                 lines_since_mismatch += 1;
159             }
160         }
161     }
162
163     results.push(mismatch);
164     results.remove(0);
165
166     results
167 }
168
169 pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
170     match &*config.target {
171         "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
172             if !config.adb_device_status {
173                 panic!("android device not available");
174             }
175         }
176
177         _ => {
178             // android has its own gdb handling
179             if config.mode == DebugInfoGdb && config.gdb.is_none() {
180                 panic!("gdb not available but debuginfo gdb debuginfo test requested");
181             }
182         }
183     }
184
185     if config.verbose {
186         // We're going to be dumping a lot of info. Start on a new line.
187         print!("\n\n");
188     }
189     debug!("running {:?}", testpaths.file.display());
190     let props = TestProps::from_file(&testpaths.file, revision, &config);
191
192     let cx = TestCx {
193         config: &config,
194         props: &props,
195         testpaths,
196         revision: revision,
197     };
198     create_dir_all(&cx.output_base_dir()).unwrap();
199
200     if config.mode == Incremental {
201         // Incremental tests are special because they cannot be run in
202         // parallel.
203         assert!(
204             !props.revisions.is_empty(),
205             "Incremental tests require revisions."
206         );
207         cx.init_incremental_test();
208         for revision in &props.revisions {
209             let revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config);
210             let rev_cx = TestCx {
211                 config: &config,
212                 props: &revision_props,
213                 testpaths,
214                 revision: Some(revision),
215             };
216             rev_cx.run_revision();
217         }
218     } else {
219         cx.run_revision();
220     }
221
222     cx.create_stamp();
223 }
224
225 pub fn compute_stamp_hash(config: &Config) -> String {
226     let mut hash = DefaultHasher::new();
227     config.stage_id.hash(&mut hash);
228
229     if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth {
230         match config.gdb {
231             None => env::var_os("PATH").hash(&mut hash),
232             Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash),
233             Some(ref s) => s.hash(&mut hash),
234         };
235     }
236
237     if config.mode == DebugInfoLldb || config.mode == DebugInfoBoth {
238         env::var_os("PATH").hash(&mut hash);
239         env::var_os("PYTHONPATH").hash(&mut hash);
240     }
241
242     format!("{:x}", hash.finish())
243 }
244
245 struct TestCx<'test> {
246     config: &'test Config,
247     props: &'test TestProps,
248     testpaths: &'test TestPaths,
249     revision: Option<&'test str>,
250 }
251
252 struct DebuggerCommands {
253     commands: Vec<String>,
254     check_lines: Vec<String>,
255     breakpoint_lines: Vec<usize>,
256 }
257
258 enum ReadFrom {
259     Path,
260     Stdin(String),
261 }
262
263 impl<'test> TestCx<'test> {
264     /// Code executed for each revision in turn (or, if there are no
265     /// revisions, exactly once, with revision == None).
266     fn run_revision(&self) {
267         match self.config.mode {
268             CompileFail | ParseFail => self.run_cfail_test(),
269             RunFail => self.run_rfail_test(),
270             RunPassValgrind => self.run_valgrind_test(),
271             Pretty => self.run_pretty_test(),
272             DebugInfoBoth => {
273                 self.run_debuginfo_gdb_test();
274                 self.run_debuginfo_lldb_test();
275             },
276             DebugInfoGdb => self.run_debuginfo_gdb_test(),
277             DebugInfoLldb => self.run_debuginfo_lldb_test(),
278             Codegen => self.run_codegen_test(),
279             Rustdoc => self.run_rustdoc_test(),
280             CodegenUnits => self.run_codegen_units_test(),
281             Incremental => self.run_incremental_test(),
282             RunMake => self.run_rmake_test(),
283             RunPass | Ui => self.run_ui_test(),
284             MirOpt => self.run_mir_opt_test(),
285         }
286     }
287
288     fn should_run_successfully(&self) -> bool {
289         let run_pass = match self.config.mode {
290             RunPass => true,
291             Ui => self.props.run_pass,
292             _ => unimplemented!(),
293         };
294         return run_pass && !self.props.skip_codegen;
295     }
296
297     fn should_compile_successfully(&self) -> bool {
298         match self.config.mode {
299             ParseFail | CompileFail => self.props.compile_pass,
300             RunPass => true,
301             Ui => self.props.compile_pass,
302             Incremental => {
303                 let revision = self.revision
304                     .expect("incremental tests require a list of revisions");
305                 if revision.starts_with("rpass") || revision.starts_with("rfail") {
306                     true
307                 } else if revision.starts_with("cfail") {
308                     // FIXME: would be nice if incremental revs could start with "cpass"
309                     self.props.compile_pass
310                 } else {
311                     panic!("revision name must begin with rpass, rfail, or cfail");
312                 }
313             }
314             mode => panic!("unimplemented for mode {:?}", mode),
315         }
316     }
317
318     fn check_if_test_should_compile(&self, proc_res: &ProcRes) {
319         if self.should_compile_successfully() {
320             if !proc_res.status.success() {
321                 self.fatal_proc_rec("test compilation failed although it shouldn't!", proc_res);
322             }
323         } else {
324             if proc_res.status.success() {
325                 self.fatal_proc_rec(
326                     &format!("{} test compiled successfully!", self.config.mode)[..],
327                     proc_res,
328                 );
329             }
330
331             self.check_correct_failure_status(proc_res);
332         }
333     }
334
335     fn run_cfail_test(&self) {
336         let proc_res = self.compile_test();
337         self.check_if_test_should_compile(&proc_res);
338         self.check_no_compiler_crash(&proc_res);
339
340         let output_to_check = self.get_output(&proc_res);
341         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
342         if !expected_errors.is_empty() {
343             if !self.props.error_patterns.is_empty() {
344                 self.fatal("both error pattern and expected errors specified");
345             }
346             self.check_expected_errors(expected_errors, &proc_res);
347         } else {
348             self.check_error_patterns(&output_to_check, &proc_res);
349         }
350
351         self.check_forbid_output(&output_to_check, &proc_res);
352     }
353
354     fn run_rfail_test(&self) {
355         let proc_res = self.compile_test();
356
357         if !proc_res.status.success() {
358             self.fatal_proc_rec("compilation failed!", &proc_res);
359         }
360
361         let proc_res = self.exec_compiled_test();
362
363         // The value our Makefile configures valgrind to return on failure
364         const VALGRIND_ERR: i32 = 100;
365         if proc_res.status.code() == Some(VALGRIND_ERR) {
366             self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
367         }
368
369         let output_to_check = self.get_output(&proc_res);
370         self.check_correct_failure_status(&proc_res);
371         self.check_error_patterns(&output_to_check, &proc_res);
372     }
373
374     fn get_output(&self, proc_res: &ProcRes) -> String {
375         if self.props.check_stdout {
376             format!("{}{}", proc_res.stdout, proc_res.stderr)
377         } else {
378             proc_res.stderr.clone()
379         }
380     }
381
382     fn check_correct_failure_status(&self, proc_res: &ProcRes) {
383         let expected_status = Some(self.props.failure_status);
384         let received_status = proc_res.status.code();
385
386         if expected_status != received_status {
387             self.fatal_proc_rec(
388                 &format!(
389                     "Error: expected failure status ({:?}) but received status {:?}.",
390                     expected_status, received_status
391                 ),
392                 proc_res,
393             );
394         }
395     }
396
397     fn run_rpass_test(&self) {
398         let proc_res = self.compile_test();
399
400         if !proc_res.status.success() {
401             self.fatal_proc_rec("compilation failed!", &proc_res);
402         }
403
404         // FIXME(#41968): Move this check to tidy?
405         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
406         assert!(
407             expected_errors.is_empty(),
408             "run-pass tests with expected warnings should be moved to ui/"
409         );
410
411         if !self.props.skip_codegen {
412             let proc_res = self.exec_compiled_test();
413             if !proc_res.status.success() {
414                 self.fatal_proc_rec("test run failed!", &proc_res);
415             }
416         }
417     }
418
419     fn run_valgrind_test(&self) {
420         assert!(self.revision.is_none(), "revisions not relevant here");
421
422         if self.config.valgrind_path.is_none() {
423             assert!(!self.config.force_valgrind);
424             return self.run_rpass_test();
425         }
426
427         let mut proc_res = self.compile_test();
428
429         if !proc_res.status.success() {
430             self.fatal_proc_rec("compilation failed!", &proc_res);
431         }
432
433         let mut new_config = self.config.clone();
434         new_config.runtool = new_config.valgrind_path.clone();
435         let new_cx = TestCx {
436             config: &new_config,
437             ..*self
438         };
439         proc_res = new_cx.exec_compiled_test();
440
441         if !proc_res.status.success() {
442             self.fatal_proc_rec("test run failed!", &proc_res);
443         }
444     }
445
446     fn run_pretty_test(&self) {
447         if self.props.pp_exact.is_some() {
448             logv(self.config, "testing for exact pretty-printing".to_owned());
449         } else {
450             logv(
451                 self.config,
452                 "testing for converging pretty-printing".to_owned(),
453             );
454         }
455
456         let rounds = match self.props.pp_exact {
457             Some(_) => 1,
458             None => 2,
459         };
460
461         let mut src = String::new();
462         File::open(&self.testpaths.file)
463             .unwrap()
464             .read_to_string(&mut src)
465             .unwrap();
466         let mut srcs = vec![src];
467
468         let mut round = 0;
469         while round < rounds {
470             logv(
471                 self.config,
472                 format!(
473                     "pretty-printing round {} revision {:?}",
474                     round, self.revision
475                 ),
476             );
477             let read_from = if round == 0 {
478                 ReadFrom::Path
479             } else {
480                 ReadFrom::Stdin(srcs[round].to_owned())
481             };
482
483             let proc_res = self.print_source(read_from,
484                                              &self.props.pretty_mode);
485             if !proc_res.status.success() {
486                 self.fatal_proc_rec(
487                     &format!(
488                         "pretty-printing failed in round {} revision {:?}",
489                         round, self.revision
490                     ),
491                     &proc_res,
492                 );
493             }
494
495             let ProcRes { stdout, .. } = proc_res;
496             srcs.push(stdout);
497             round += 1;
498         }
499
500         let mut expected = match self.props.pp_exact {
501             Some(ref file) => {
502                 let filepath = self.testpaths.file.parent().unwrap().join(file);
503                 let mut s = String::new();
504                 File::open(&filepath)
505                     .unwrap()
506                     .read_to_string(&mut s)
507                     .unwrap();
508                 s
509             }
510             None => srcs[srcs.len() - 2].clone(),
511         };
512         let mut actual = srcs[srcs.len() - 1].clone();
513
514         if self.props.pp_exact.is_some() {
515             // Now we have to care about line endings
516             let cr = "\r".to_owned();
517             actual = actual.replace(&cr, "").to_owned();
518             expected = expected.replace(&cr, "").to_owned();
519         }
520
521         self.compare_source(&expected, &actual);
522
523         // If we're only making sure that the output matches then just stop here
524         if self.props.pretty_compare_only {
525             return;
526         }
527
528         // Finally, let's make sure it actually appears to remain valid code
529         let proc_res = self.typecheck_source(actual);
530         if !proc_res.status.success() {
531             self.fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
532         }
533
534         if !self.props.pretty_expanded {
535             return;
536         }
537
538         // additionally, run `--pretty expanded` and try to build it.
539         let proc_res = self.print_source(ReadFrom::Path, "expanded");
540         if !proc_res.status.success() {
541             self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
542         }
543
544         let ProcRes {
545             stdout: expanded_src,
546             ..
547         } = proc_res;
548         let proc_res = self.typecheck_source(expanded_src);
549         if !proc_res.status.success() {
550             self.fatal_proc_rec(
551                 "pretty-printed source (expanded) does not typecheck",
552                 &proc_res,
553             );
554         }
555     }
556
557     fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes {
558         let aux_dir = self.aux_output_dir_name();
559         let input: &str = match read_from {
560             ReadFrom::Stdin(_) => "-",
561             ReadFrom::Path => self.testpaths.file.to_str().unwrap(),
562         };
563
564         let mut rustc = Command::new(&self.config.rustc_path);
565         rustc
566             .arg(input)
567             .args(&["-Z", &format!("unpretty={}", pretty_type)])
568             .args(&["--target", &self.config.target])
569             .arg("-L")
570             .arg(&aux_dir)
571             .args(self.split_maybe_args(&self.config.target_rustcflags))
572             .args(&self.props.compile_flags)
573             .envs(self.props.exec_env.clone());
574
575         let src = match read_from {
576             ReadFrom::Stdin(src) => Some(src),
577             ReadFrom::Path => None
578         };
579
580         self.compose_and_run(
581             rustc,
582             self.config.compile_lib_path.to_str().unwrap(),
583             Some(aux_dir.to_str().unwrap()),
584             src,
585         )
586     }
587
588     fn compare_source(&self, expected: &str, actual: &str) {
589         if expected != actual {
590             self.fatal(&format!(
591                 "pretty-printed source does not match expected source\n\
592                  expected:\n\
593                  ------------------------------------------\n\
594                  {}\n\
595                  ------------------------------------------\n\
596                  actual:\n\
597                  ------------------------------------------\n\
598                  {}\n\
599                  ------------------------------------------\n\
600                  \n",
601                 expected, actual)
602             );
603         }
604     }
605
606     fn typecheck_source(&self, src: String) -> ProcRes {
607         let mut rustc = Command::new(&self.config.rustc_path);
608
609         let out_dir = self.output_base_name().with_extension("pretty-out");
610         let _ = fs::remove_dir_all(&out_dir);
611         create_dir_all(&out_dir).unwrap();
612
613         let target = if self.props.force_host {
614             &*self.config.host
615         } else {
616             &*self.config.target
617         };
618
619         let aux_dir = self.aux_output_dir_name();
620
621         rustc
622             .arg("-")
623             .arg("-Zno-codegen")
624             .arg("--out-dir")
625             .arg(&out_dir)
626             .arg(&format!("--target={}", target))
627             .arg("-L")
628             .arg(&self.config.build_base)
629             .arg("-L")
630             .arg(aux_dir);
631
632         if let Some(revision) = self.revision {
633             rustc.args(&["--cfg", revision]);
634         }
635
636         rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
637         rustc.args(&self.props.compile_flags);
638
639         self.compose_and_run_compiler(rustc, Some(src))
640     }
641
642     fn run_debuginfo_gdb_test(&self) {
643         assert!(self.revision.is_none(), "revisions not relevant here");
644
645         let config = Config {
646             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
647             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
648             mode: DebugInfoGdb,
649             ..self.config.clone()
650         };
651
652         let test_cx = TestCx {
653             config: &config,
654             ..*self
655         };
656
657         test_cx.run_debuginfo_gdb_test_no_opt();
658     }
659
660     fn run_debuginfo_gdb_test_no_opt(&self) {
661         let prefixes = if self.config.gdb_native_rust {
662             // GDB with Rust
663             static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"];
664             println!("NOTE: compiletest thinks it is using GDB with native rust support");
665             PREFIXES
666         } else {
667             // Generic GDB
668             static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"];
669             println!("NOTE: compiletest thinks it is using GDB without native rust support");
670             PREFIXES
671         };
672
673         let DebuggerCommands {
674             commands,
675             check_lines,
676             breakpoint_lines,
677         } = self.parse_debugger_commands(prefixes);
678         let mut cmds = commands.join("\n");
679
680         // compile test file (it should have 'compile-flags:-g' in the header)
681         let compiler_run_result = self.compile_test();
682         if !compiler_run_result.status.success() {
683             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
684         }
685
686         let exe_file = self.make_exe_name();
687
688         let debugger_run_result;
689         if is_android_gdb_target(&self.config.target) {
690             cmds = cmds.replace("run", "continue");
691
692             let tool_path = match self.config.android_cross_path.to_str() {
693                 Some(x) => x.to_owned(),
694                 None => self.fatal("cannot find android cross path"),
695             };
696
697             // write debugger script
698             let mut script_str = String::with_capacity(2048);
699             script_str.push_str(&format!("set charset {}\n", Self::charset()));
700             script_str.push_str(&format!("set sysroot {}\n", tool_path));
701             script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
702             script_str.push_str("target remote :5039\n");
703             script_str.push_str(&format!(
704                 "set solib-search-path \
705                  ./{}/stage2/lib/rustlib/{}/lib/\n",
706                 self.config.host, self.config.target
707             ));
708             for line in &breakpoint_lines {
709                 script_str.push_str(
710                     &format!(
711                         "break {:?}:{}\n",
712                         self.testpaths.file.file_name().unwrap().to_string_lossy(),
713                         *line
714                     )[..],
715                 );
716             }
717             script_str.push_str(&cmds);
718             script_str.push_str("\nquit\n");
719
720             debug!("script_str = {}", script_str);
721             self.dump_output_file(&script_str, "debugger.script");
722
723             let adb_path = &self.config.adb_path;
724
725             Command::new(adb_path)
726                 .arg("push")
727                 .arg(&exe_file)
728                 .arg(&self.config.adb_test_dir)
729                 .status()
730                 .expect(&format!("failed to exec `{:?}`", adb_path));
731
732             Command::new(adb_path)
733                 .args(&["forward", "tcp:5039", "tcp:5039"])
734                 .status()
735                 .expect(&format!("failed to exec `{:?}`", adb_path));
736
737             let adb_arg = format!(
738                 "export LD_LIBRARY_PATH={}; \
739                  gdbserver{} :5039 {}/{}",
740                 self.config.adb_test_dir.clone(),
741                 if self.config.target.contains("aarch64") {
742                     "64"
743                 } else {
744                     ""
745                 },
746                 self.config.adb_test_dir.clone(),
747                 exe_file.file_name().unwrap().to_str().unwrap()
748             );
749
750             debug!("adb arg: {}", adb_arg);
751             let mut adb = Command::new(adb_path)
752                 .args(&["shell", &adb_arg])
753                 .stdout(Stdio::piped())
754                 .stderr(Stdio::inherit())
755                 .spawn()
756                 .expect(&format!("failed to exec `{:?}`", adb_path));
757
758             // Wait for the gdbserver to print out "Listening on port ..."
759             // at which point we know that it's started and then we can
760             // execute the debugger below.
761             let mut stdout = BufReader::new(adb.stdout.take().unwrap());
762             let mut line = String::new();
763             loop {
764                 line.truncate(0);
765                 stdout.read_line(&mut line).unwrap();
766                 if line.starts_with("Listening on port 5039") {
767                     break;
768                 }
769             }
770             drop(stdout);
771
772             let debugger_script = self.make_out_name("debugger.script");
773             // FIXME (#9639): This needs to handle non-utf8 paths
774             let debugger_opts = vec![
775                 "-quiet".to_owned(),
776                 "-batch".to_owned(),
777                 "-nx".to_owned(),
778                 format!("-command={}", debugger_script.to_str().unwrap()),
779             ];
780
781             let gdb_path = self.config.gdb.as_ref().unwrap();
782             let Output {
783                 status,
784                 stdout,
785                 stderr,
786             } = Command::new(&gdb_path)
787                 .args(&debugger_opts)
788                 .output()
789                 .expect(&format!("failed to exec `{:?}`", gdb_path));
790             let cmdline = {
791                 let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
792                 gdb.args(&debugger_opts);
793                 let cmdline = self.make_cmdline(&gdb, "");
794                 logv(self.config, format!("executing {}", cmdline));
795                 cmdline
796             };
797
798             debugger_run_result = ProcRes {
799                 status,
800                 stdout: String::from_utf8(stdout).unwrap(),
801                 stderr: String::from_utf8(stderr).unwrap(),
802                 cmdline,
803             };
804             if adb.kill().is_err() {
805                 println!("Adb process is already finished.");
806             }
807         } else {
808             let rust_src_root = self
809                 .config
810                 .find_rust_src_root()
811                 .expect("Could not find Rust source root");
812             let rust_pp_module_rel_path = Path::new("./src/etc");
813             let rust_pp_module_abs_path = rust_src_root
814                 .join(rust_pp_module_rel_path)
815                 .to_str()
816                 .unwrap()
817                 .to_owned();
818             // write debugger script
819             let mut script_str = String::with_capacity(2048);
820             script_str.push_str(&format!("set charset {}\n", Self::charset()));
821             script_str.push_str("show version\n");
822
823             match self.config.gdb_version {
824                 Some(version) => {
825                     println!(
826                         "NOTE: compiletest thinks it is using GDB version {}",
827                         version
828                     );
829
830                     if version > extract_gdb_version("7.4").unwrap() {
831                         // Add the directory containing the pretty printers to
832                         // GDB's script auto loading safe path
833                         script_str.push_str(&format!(
834                             "add-auto-load-safe-path {}\n",
835                             rust_pp_module_abs_path.replace(r"\", r"\\")
836                         ));
837                     }
838                 }
839                 _ => {
840                     println!(
841                         "NOTE: compiletest does not know which version of \
842                          GDB it is using"
843                     );
844                 }
845             }
846
847             // The following line actually doesn't have to do anything with
848             // pretty printing, it just tells GDB to print values on one line:
849             script_str.push_str("set print pretty off\n");
850
851             // Add the pretty printer directory to GDB's source-file search path
852             script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path));
853
854             // Load the target executable
855             script_str.push_str(&format!(
856                 "file {}\n",
857                 exe_file.to_str().unwrap().replace(r"\", r"\\")
858             ));
859
860             // Force GDB to print values in the Rust format.
861             if self.config.gdb_native_rust {
862                 script_str.push_str("set language rust\n");
863             }
864
865             // Add line breakpoints
866             for line in &breakpoint_lines {
867                 script_str.push_str(&format!(
868                     "break '{}':{}\n",
869                     self.testpaths.file.file_name().unwrap().to_string_lossy(),
870                     *line
871                 ));
872             }
873
874             script_str.push_str(&cmds);
875             script_str.push_str("\nquit\n");
876
877             debug!("script_str = {}", script_str);
878             self.dump_output_file(&script_str, "debugger.script");
879
880             let debugger_script = self.make_out_name("debugger.script");
881
882             // FIXME (#9639): This needs to handle non-utf8 paths
883             let debugger_opts = vec![
884                 "-quiet".to_owned(),
885                 "-batch".to_owned(),
886                 "-nx".to_owned(),
887                 format!("-command={}", debugger_script.to_str().unwrap()),
888             ];
889
890             let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
891             gdb.args(&debugger_opts)
892                 .env("PYTHONPATH", rust_pp_module_abs_path);
893
894             debugger_run_result = self.compose_and_run(
895                 gdb,
896                 self.config.run_lib_path.to_str().unwrap(),
897                 None,
898                 None,
899             );
900         }
901
902         if !debugger_run_result.status.success() {
903             self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
904         }
905
906         self.check_debugger_output(&debugger_run_result, &check_lines);
907     }
908
909     fn run_debuginfo_lldb_test(&self) {
910         assert!(self.revision.is_none(), "revisions not relevant here");
911
912         if self.config.lldb_python_dir.is_none() {
913             self.fatal("Can't run LLDB test because LLDB's python path is not set.");
914         }
915
916         let config = Config {
917             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
918             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
919             mode: DebugInfoLldb,
920             ..self.config.clone()
921         };
922
923         let test_cx = TestCx {
924             config: &config,
925             ..*self
926         };
927
928         test_cx.run_debuginfo_lldb_test_no_opt();
929     }
930
931     fn run_debuginfo_lldb_test_no_opt(&self) {
932         // compile test file (it should have 'compile-flags:-g' in the header)
933         let compile_result = self.compile_test();
934         if !compile_result.status.success() {
935             self.fatal_proc_rec("compilation failed!", &compile_result);
936         }
937
938         let exe_file = self.make_exe_name();
939
940         match self.config.lldb_version {
941             Some(ref version) => {
942                 println!(
943                     "NOTE: compiletest thinks it is using LLDB version {}",
944                     version
945                 );
946             }
947             _ => {
948                 println!(
949                     "NOTE: compiletest does not know which version of \
950                      LLDB it is using"
951                 );
952             }
953         }
954
955         let prefixes = if self.config.lldb_native_rust {
956             static PREFIXES: &'static [&'static str] = &["lldb", "lldbr"];
957             println!("NOTE: compiletest thinks it is using LLDB with native rust support");
958             PREFIXES
959         } else {
960             static PREFIXES: &'static [&'static str] = &["lldb", "lldbg"];
961             println!("NOTE: compiletest thinks it is using LLDB without native rust support");
962             PREFIXES
963         };
964
965         // Parse debugger commands etc from test files
966         let DebuggerCommands {
967             commands,
968             check_lines,
969             breakpoint_lines,
970             ..
971         } = self.parse_debugger_commands(prefixes);
972
973         // Write debugger script:
974         // We don't want to hang when calling `quit` while the process is still running
975         let mut script_str = String::from("settings set auto-confirm true\n");
976
977         // Make LLDB emit its version, so we have it documented in the test output
978         script_str.push_str("version\n");
979
980         // Switch LLDB into "Rust mode"
981         let rust_src_root = self
982             .config
983             .find_rust_src_root()
984             .expect("Could not find Rust source root");
985         let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
986         let rust_pp_module_abs_path = rust_src_root
987             .join(rust_pp_module_rel_path)
988             .to_str()
989             .unwrap()
990             .to_owned();
991
992         script_str
993             .push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]);
994         script_str.push_str("type summary add --no-value ");
995         script_str.push_str("--python-function lldb_rust_formatters.print_val ");
996         script_str.push_str("-x \".*\" --category Rust\n");
997         script_str.push_str("type category enable Rust\n");
998
999         // Set breakpoints on every line that contains the string "#break"
1000         let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
1001         for line in &breakpoint_lines {
1002             script_str.push_str(&format!(
1003                 "breakpoint set --file '{}' --line {}\n",
1004                 source_file_name, line
1005             ));
1006         }
1007
1008         // Append the other commands
1009         for line in &commands {
1010             script_str.push_str(line);
1011             script_str.push_str("\n");
1012         }
1013
1014         // Finally, quit the debugger
1015         script_str.push_str("\nquit\n");
1016
1017         // Write the script into a file
1018         debug!("script_str = {}", script_str);
1019         self.dump_output_file(&script_str, "debugger.script");
1020         let debugger_script = self.make_out_name("debugger.script");
1021
1022         // Let LLDB execute the script via lldb_batchmode.py
1023         let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root);
1024
1025         if !debugger_run_result.status.success() {
1026             self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
1027         }
1028
1029         self.check_debugger_output(&debugger_run_result, &check_lines);
1030     }
1031
1032     fn run_lldb(
1033         &self,
1034         test_executable: &Path,
1035         debugger_script: &Path,
1036         rust_src_root: &Path,
1037     ) -> ProcRes {
1038         // Prepare the lldb_batchmode which executes the debugger script
1039         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
1040         self.cmd2procres(
1041             Command::new(&self.config.lldb_python)
1042                 .arg(&lldb_script_path)
1043                 .arg(test_executable)
1044                 .arg(debugger_script)
1045                 .env("PYTHONPATH", self.config.lldb_python_dir.as_ref().unwrap()),
1046         )
1047     }
1048
1049     fn cmd2procres(&self, cmd: &mut Command) -> ProcRes {
1050         let (status, out, err) = match cmd.output() {
1051             Ok(Output {
1052                 status,
1053                 stdout,
1054                 stderr,
1055             }) => (
1056                 status,
1057                 String::from_utf8(stdout).unwrap(),
1058                 String::from_utf8(stderr).unwrap(),
1059             ),
1060             Err(e) => self.fatal(&format!(
1061                 "Failed to setup Python process for \
1062                  LLDB script: {}",
1063                 e
1064             )),
1065         };
1066
1067         self.dump_output(&out, &err);
1068         ProcRes {
1069             status,
1070             stdout: out,
1071             stderr: err,
1072             cmdline: format!("{:?}", cmd),
1073         }
1074     }
1075
1076     fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
1077         let directives = debugger_prefixes
1078             .iter()
1079             .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
1080             .collect::<Vec<_>>();
1081
1082         let mut breakpoint_lines = vec![];
1083         let mut commands = vec![];
1084         let mut check_lines = vec![];
1085         let mut counter = 1;
1086         let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
1087         for line in reader.lines() {
1088             match line {
1089                 Ok(line) => {
1090                     let line = if line.starts_with("//") {
1091                         line[2..].trim_left()
1092                     } else {
1093                         line.as_str()
1094                     };
1095
1096                     if line.contains("#break") {
1097                         breakpoint_lines.push(counter);
1098                     }
1099
1100                     for &(ref command_directive, ref check_directive) in &directives {
1101                         self.config
1102                             .parse_name_value_directive(&line, command_directive)
1103                             .map(|cmd| commands.push(cmd));
1104
1105                         self.config
1106                             .parse_name_value_directive(&line, check_directive)
1107                             .map(|cmd| check_lines.push(cmd));
1108                     }
1109                 }
1110                 Err(e) => self.fatal(&format!("Error while parsing debugger commands: {}", e)),
1111             }
1112             counter += 1;
1113         }
1114
1115         DebuggerCommands {
1116             commands,
1117             check_lines,
1118             breakpoint_lines,
1119         }
1120     }
1121
1122     fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
1123         if options.is_none() {
1124             return None;
1125         }
1126
1127         // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
1128         let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
1129         let new_options = self
1130             .split_maybe_args(options)
1131             .into_iter()
1132             .filter(|x| !options_to_remove.contains(x))
1133             .collect::<Vec<String>>();
1134
1135         Some(new_options.join(" "))
1136     }
1137
1138     fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[String]) {
1139         let num_check_lines = check_lines.len();
1140
1141         let mut check_line_index = 0;
1142         for line in debugger_run_result.stdout.lines() {
1143             if check_line_index >= num_check_lines {
1144                 break;
1145             }
1146
1147             if check_single_line(line, &(check_lines[check_line_index])[..]) {
1148                 check_line_index += 1;
1149             }
1150         }
1151         if check_line_index != num_check_lines && num_check_lines > 0 {
1152             self.fatal_proc_rec(
1153                 &format!(
1154                     "line not found in debugger output: {}",
1155                     check_lines[check_line_index]
1156                 ),
1157                 debugger_run_result,
1158             );
1159         }
1160
1161         fn check_single_line(line: &str, check_line: &str) -> bool {
1162             // Allow check lines to leave parts unspecified (e.g., uninitialized
1163             // bits in the  wrong case of an enum) with the notation "[...]".
1164             let line = line.trim();
1165             let check_line = check_line.trim();
1166             let can_start_anywhere = check_line.starts_with("[...]");
1167             let can_end_anywhere = check_line.ends_with("[...]");
1168
1169             let check_fragments: Vec<&str> = check_line
1170                 .split("[...]")
1171                 .filter(|frag| !frag.is_empty())
1172                 .collect();
1173             if check_fragments.is_empty() {
1174                 return true;
1175             }
1176
1177             let (mut rest, first_fragment) = if can_start_anywhere {
1178                 match line.find(check_fragments[0]) {
1179                     Some(pos) => (&line[pos + check_fragments[0].len()..], 1),
1180                     None => return false,
1181                 }
1182             } else {
1183                 (line, 0)
1184             };
1185
1186             for current_fragment in &check_fragments[first_fragment..] {
1187                 match rest.find(current_fragment) {
1188                     Some(pos) => {
1189                         rest = &rest[pos + current_fragment.len()..];
1190                     }
1191                     None => return false,
1192                 }
1193             }
1194
1195             if !can_end_anywhere && !rest.is_empty() {
1196                 return false;
1197             }
1198
1199             true
1200         }
1201     }
1202
1203     fn check_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) {
1204         debug!("check_error_patterns");
1205         if self.props.error_patterns.is_empty() {
1206             if self.props.compile_pass {
1207                 return;
1208             } else {
1209                 self.fatal(&format!(
1210                     "no error pattern specified in {:?}",
1211                     self.testpaths.file.display()
1212                 ));
1213             }
1214         }
1215
1216         let mut missing_patterns: Vec<String> = Vec::new();
1217
1218         for pattern in &self.props.error_patterns {
1219             if output_to_check.contains(pattern.trim()) {
1220                 debug!("found error pattern {}", pattern);
1221             } else {
1222                 missing_patterns.push(pattern.to_string());
1223             }
1224         }
1225
1226         if missing_patterns.is_empty() {
1227             return;
1228         }
1229
1230         if missing_patterns.len() == 1 {
1231             self.fatal_proc_rec(
1232                 &format!("error pattern '{}' not found!", missing_patterns[0]),
1233                 proc_res,
1234             );
1235         } else {
1236             for pattern in missing_patterns {
1237                 self.error(&format!("error pattern '{}' not found!", pattern));
1238             }
1239             self.fatal_proc_rec("multiple error patterns not found", proc_res);
1240         }
1241     }
1242
1243     fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
1244         match proc_res.status.code() {
1245             Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
1246             None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
1247             _ => (),
1248         }
1249     }
1250
1251     fn check_forbid_output(&self, output_to_check: &str, proc_res: &ProcRes) {
1252         for pat in &self.props.forbid_output {
1253             if output_to_check.contains(pat) {
1254                 self.fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
1255             }
1256         }
1257     }
1258
1259     fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &ProcRes) {
1260         debug!("check_expected_errors: expected_errors={:?} proc_res.status={:?}",
1261                expected_errors, proc_res.status);
1262         if proc_res.status.success()
1263             && expected_errors
1264                 .iter()
1265                 .any(|x| x.kind == Some(ErrorKind::Error))
1266         {
1267             self.fatal_proc_rec("process did not return an error status", proc_res);
1268         }
1269
1270         // On Windows, keep all '\' path separators to match the paths reported in the JSON output
1271         // from the compiler
1272         let os_file_name = self.testpaths.file.display().to_string();
1273
1274         // on windows, translate all '\' path separators to '/'
1275         let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
1276
1277         // If the testcase being checked contains at least one expected "help"
1278         // message, then we'll ensure that all "help" messages are expected.
1279         // Otherwise, all "help" messages reported by the compiler will be ignored.
1280         // This logic also applies to "note" messages.
1281         let expect_help = expected_errors
1282             .iter()
1283             .any(|ee| ee.kind == Some(ErrorKind::Help));
1284         let expect_note = expected_errors
1285             .iter()
1286             .any(|ee| ee.kind == Some(ErrorKind::Note));
1287
1288         // Parse the JSON output from the compiler and extract out the messages.
1289         let actual_errors = json::parse_output(&os_file_name, &proc_res.stderr, proc_res);
1290         let mut unexpected = Vec::new();
1291         let mut found = vec![false; expected_errors.len()];
1292         for actual_error in &actual_errors {
1293             let opt_index = expected_errors.iter().enumerate().position(
1294                 |(index, expected_error)| {
1295                     !found[index] && actual_error.line_num == expected_error.line_num
1296                         && (expected_error.kind.is_none()
1297                             || actual_error.kind == expected_error.kind)
1298                         && actual_error.msg.contains(&expected_error.msg)
1299                 },
1300             );
1301
1302             match opt_index {
1303                 Some(index) => {
1304                     // found a match, everybody is happy
1305                     assert!(!found[index]);
1306                     found[index] = true;
1307                 }
1308
1309                 None => {
1310                     if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
1311                         self.error(&format!(
1312                             "{}:{}: unexpected {}: '{}'",
1313                             file_name,
1314                             actual_error.line_num,
1315                             actual_error
1316                                 .kind
1317                                 .as_ref()
1318                                 .map_or(String::from("message"), |k| k.to_string()),
1319                             actual_error.msg
1320                         ));
1321                         unexpected.push(actual_error);
1322                     }
1323                 }
1324             }
1325         }
1326
1327         let mut not_found = Vec::new();
1328         // anything not yet found is a problem
1329         for (index, expected_error) in expected_errors.iter().enumerate() {
1330             if !found[index] {
1331                 self.error(&format!(
1332                     "{}:{}: expected {} not found: {}",
1333                     file_name,
1334                     expected_error.line_num,
1335                     expected_error
1336                         .kind
1337                         .as_ref()
1338                         .map_or("message".into(), |k| k.to_string()),
1339                     expected_error.msg
1340                 ));
1341                 not_found.push(expected_error);
1342             }
1343         }
1344
1345         if !unexpected.is_empty() || !not_found.is_empty() {
1346             self.error(&format!(
1347                 "{} unexpected errors found, {} expected errors not found",
1348                 unexpected.len(),
1349                 not_found.len()
1350             ));
1351             println!("status: {}\ncommand: {}", proc_res.status, proc_res.cmdline);
1352             if !unexpected.is_empty() {
1353                 println!("unexpected errors (from JSON output): {:#?}\n", unexpected);
1354             }
1355             if !not_found.is_empty() {
1356                 println!("not found errors (from test file): {:#?}\n", not_found);
1357             }
1358             panic!();
1359         }
1360     }
1361
1362     /// Returns true if we should report an error about `actual_error`,
1363     /// which did not match any of the expected error. We always require
1364     /// errors/warnings to be explicitly listed, but only require
1365     /// helps/notes if there are explicit helps/notes given.
1366     fn is_unexpected_compiler_message(
1367         &self,
1368         actual_error: &Error,
1369         expect_help: bool,
1370         expect_note: bool,
1371     ) -> bool {
1372         match actual_error.kind {
1373             Some(ErrorKind::Help) => expect_help,
1374             Some(ErrorKind::Note) => expect_note,
1375             Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true,
1376             Some(ErrorKind::Suggestion) | None => false,
1377         }
1378     }
1379
1380     fn compile_test(&self) -> ProcRes {
1381         let mut rustc = self.make_compile_args(
1382             &self.testpaths.file,
1383             TargetLocation::ThisFile(self.make_exe_name()),
1384         );
1385
1386         rustc.arg("-L").arg(&self.aux_output_dir_name());
1387
1388         match self.config.mode {
1389             CompileFail | Ui => {
1390                 // compile-fail and ui tests tend to have tons of unused code as
1391                 // it's just testing various pieces of the compile, but we don't
1392                 // want to actually assert warnings about all this code. Instead
1393                 // let's just ignore unused code warnings by defaults and tests
1394                 // can turn it back on if needed.
1395                 if !self.config.src_base.ends_with("rustdoc-ui") {
1396                     rustc.args(&["-A", "unused"]);
1397                 }
1398             }
1399             _ => {}
1400         }
1401
1402         self.compose_and_run_compiler(rustc, None)
1403     }
1404
1405     fn document(&self, out_dir: &Path) -> ProcRes {
1406         if self.props.build_aux_docs {
1407             for rel_ab in &self.props.aux_builds {
1408                 let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1409                 let aux_props =
1410                     self.props
1411                         .from_aux_file(&aux_testpaths.file, self.revision, self.config);
1412                 let aux_cx = TestCx {
1413                     config: self.config,
1414                     props: &aux_props,
1415                     testpaths: &aux_testpaths,
1416                     revision: self.revision,
1417                 };
1418                 // Create the directory for the stdout/stderr files.
1419                 create_dir_all(aux_cx.output_base_dir()).unwrap();
1420                 let auxres = aux_cx.document(out_dir);
1421                 if !auxres.status.success() {
1422                     return auxres;
1423                 }
1424             }
1425         }
1426
1427         let aux_dir = self.aux_output_dir_name();
1428
1429         let rustdoc_path = self
1430             .config
1431             .rustdoc_path
1432             .as_ref()
1433             .expect("--rustdoc-path passed");
1434         let mut rustdoc = Command::new(rustdoc_path);
1435
1436         rustdoc
1437             .arg("-L")
1438             .arg(self.config.run_lib_path.to_str().unwrap())
1439             .arg("-L")
1440             .arg(aux_dir)
1441             .arg("-o")
1442             .arg(out_dir)
1443             .arg(&self.testpaths.file)
1444             .args(&self.props.compile_flags);
1445
1446         if let Some(ref linker) = self.config.linker {
1447             rustdoc
1448                 .arg("--linker")
1449                 .arg(linker)
1450                 .arg("-Z")
1451                 .arg("unstable-options");
1452         }
1453
1454         self.compose_and_run_compiler(rustdoc, None)
1455     }
1456
1457     fn exec_compiled_test(&self) -> ProcRes {
1458         let env = &self.props.exec_env;
1459
1460         let proc_res = match &*self.config.target {
1461             // This is pretty similar to below, we're transforming:
1462             //
1463             //      program arg1 arg2
1464             //
1465             // into
1466             //
1467             //      remote-test-client run program:support-lib.so arg1 arg2
1468             //
1469             // The test-client program will upload `program` to the emulator
1470             // along with all other support libraries listed (in this case
1471             // `support-lib.so`. It will then execute the program on the
1472             // emulator with the arguments specified (in the environment we give
1473             // the process) and then report back the same result.
1474             _ if self.config.remote_test_client.is_some() => {
1475                 let aux_dir = self.aux_output_dir_name();
1476                 let ProcArgs { mut prog, args } = self.make_run_args();
1477                 if let Ok(entries) = aux_dir.read_dir() {
1478                     for entry in entries {
1479                         let entry = entry.unwrap();
1480                         if !entry.path().is_file() {
1481                             continue;
1482                         }
1483                         prog.push_str(":");
1484                         prog.push_str(entry.path().to_str().unwrap());
1485                     }
1486                 }
1487                 let mut test_client =
1488                     Command::new(self.config.remote_test_client.as_ref().unwrap());
1489                 test_client
1490                     .args(&["run", &prog])
1491                     .args(args)
1492                     .envs(env.clone());
1493                 self.compose_and_run(
1494                     test_client,
1495                     self.config.run_lib_path.to_str().unwrap(),
1496                     Some(aux_dir.to_str().unwrap()),
1497                     None,
1498                 )
1499             }
1500             _ => {
1501                 let aux_dir = self.aux_output_dir_name();
1502                 let ProcArgs { prog, args } = self.make_run_args();
1503                 let mut program = Command::new(&prog);
1504                 program
1505                     .args(args)
1506                     .current_dir(&self.output_base_dir())
1507                     .envs(env.clone());
1508                 self.compose_and_run(
1509                     program,
1510                     self.config.run_lib_path.to_str().unwrap(),
1511                     Some(aux_dir.to_str().unwrap()),
1512                     None,
1513                 )
1514             }
1515         };
1516
1517         if proc_res.status.success() {
1518             // delete the executable after running it to save space.
1519             // it is ok if the deletion failed.
1520             let _ = fs::remove_file(self.make_exe_name());
1521         }
1522
1523         proc_res
1524     }
1525
1526     /// For each `aux-build: foo/bar` annotation, we check to find the
1527     /// file in a `auxiliary` directory relative to the test itself.
1528     fn compute_aux_test_paths(&self, rel_ab: &str) -> TestPaths {
1529         let test_ab = self
1530             .testpaths
1531             .file
1532             .parent()
1533             .expect("test file path has no parent")
1534             .join("auxiliary")
1535             .join(rel_ab);
1536         if !test_ab.exists() {
1537             self.fatal(&format!(
1538                 "aux-build `{}` source not found",
1539                 test_ab.display()
1540             ))
1541         }
1542
1543         TestPaths {
1544             file: test_ab,
1545             relative_dir: self
1546                 .testpaths
1547                 .relative_dir
1548                 .join(self.output_testname_unique())
1549                 .join("auxiliary")
1550                 .join(rel_ab)
1551                 .parent()
1552                 .expect("aux-build path has no parent")
1553                 .to_path_buf(),
1554         }
1555     }
1556
1557     fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
1558         let aux_dir = self.aux_output_dir_name();
1559
1560         if !self.props.aux_builds.is_empty() {
1561             let _ = fs::remove_dir_all(&aux_dir);
1562             create_dir_all(&aux_dir).unwrap();
1563         }
1564
1565         for rel_ab in &self.props.aux_builds {
1566             let aux_testpaths = self.compute_aux_test_paths(rel_ab);
1567             let aux_props =
1568                 self.props
1569                     .from_aux_file(&aux_testpaths.file, self.revision, self.config);
1570             let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name());
1571             let aux_cx = TestCx {
1572                 config: self.config,
1573                 props: &aux_props,
1574                 testpaths: &aux_testpaths,
1575                 revision: self.revision,
1576             };
1577             // Create the directory for the stdout/stderr files.
1578             create_dir_all(aux_cx.output_base_dir()).unwrap();
1579             let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
1580
1581             let crate_type = if aux_props.no_prefer_dynamic {
1582                 None
1583             } else if self.config.target.contains("cloudabi")
1584                 || self.config.target.contains("emscripten")
1585                 || (self.config.target.contains("musl") && !aux_props.force_host)
1586                 || self.config.target.contains("wasm32")
1587             {
1588                 // We primarily compile all auxiliary libraries as dynamic libraries
1589                 // to avoid code size bloat and large binaries as much as possible
1590                 // for the test suite (otherwise including libstd statically in all
1591                 // executables takes up quite a bit of space).
1592                 //
1593                 // For targets like MUSL or Emscripten, however, there is no support for
1594                 // dynamic libraries so we just go back to building a normal library. Note,
1595                 // however, that for MUSL if the library is built with `force_host` then
1596                 // it's ok to be a dylib as the host should always support dylibs.
1597                 Some("lib")
1598             } else {
1599                 Some("dylib")
1600             };
1601
1602             if let Some(crate_type) = crate_type {
1603                 aux_rustc.args(&["--crate-type", crate_type]);
1604             }
1605
1606             aux_rustc.arg("-L").arg(&aux_dir);
1607
1608             let auxres = aux_cx.compose_and_run(
1609                 aux_rustc,
1610                 aux_cx.config.compile_lib_path.to_str().unwrap(),
1611                 Some(aux_dir.to_str().unwrap()),
1612                 None,
1613             );
1614             if !auxres.status.success() {
1615                 self.fatal_proc_rec(
1616                     &format!(
1617                         "auxiliary build of {:?} failed to compile: ",
1618                         aux_testpaths.file.display()
1619                     ),
1620                     &auxres,
1621                 );
1622             }
1623         }
1624
1625         rustc.envs(self.props.rustc_env.clone());
1626         self.compose_and_run(
1627             rustc,
1628             self.config.compile_lib_path.to_str().unwrap(),
1629             Some(aux_dir.to_str().unwrap()),
1630             input,
1631         )
1632     }
1633
1634     fn compose_and_run(
1635         &self,
1636         mut command: Command,
1637         lib_path: &str,
1638         aux_path: Option<&str>,
1639         input: Option<String>,
1640     ) -> ProcRes {
1641         let cmdline = {
1642             let cmdline = self.make_cmdline(&command, lib_path);
1643             logv(self.config, format!("executing {}", cmdline));
1644             cmdline
1645         };
1646
1647         command
1648             .stdout(Stdio::piped())
1649             .stderr(Stdio::piped())
1650             .stdin(Stdio::piped());
1651
1652         // Need to be sure to put both the lib_path and the aux path in the dylib
1653         // search path for the child.
1654         let mut path = env::split_paths(&env::var_os(dylib_env_var()).unwrap_or(OsString::new()))
1655             .collect::<Vec<_>>();
1656         if let Some(p) = aux_path {
1657             path.insert(0, PathBuf::from(p))
1658         }
1659         path.insert(0, PathBuf::from(lib_path));
1660
1661         // Add the new dylib search path var
1662         let newpath = env::join_paths(&path).unwrap();
1663         command.env(dylib_env_var(), newpath);
1664
1665         let mut child = disable_error_reporting(|| command.spawn())
1666             .expect(&format!("failed to exec `{:?}`", &command));
1667         if let Some(input) = input {
1668             child
1669                 .stdin
1670                 .as_mut()
1671                 .unwrap()
1672                 .write_all(input.as_bytes())
1673                 .unwrap();
1674         }
1675
1676         let Output {
1677             status,
1678             stdout,
1679             stderr,
1680         } = read2_abbreviated(child).expect("failed to read output");
1681
1682         let result = ProcRes {
1683             status,
1684             stdout: String::from_utf8_lossy(&stdout).into_owned(),
1685             stderr: String::from_utf8_lossy(&stderr).into_owned(),
1686             cmdline,
1687         };
1688
1689         self.dump_output(&result.stdout, &result.stderr);
1690
1691         result
1692     }
1693
1694     fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
1695         let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui");
1696         let mut rustc = if !is_rustdoc {
1697             Command::new(&self.config.rustc_path)
1698         } else {
1699             Command::new(
1700                 &self
1701                     .config
1702                     .rustdoc_path
1703                     .clone()
1704                     .expect("no rustdoc built yet"),
1705             )
1706         };
1707         // FIXME Why is -L here?
1708         rustc.arg(input_file); //.arg("-L").arg(&self.config.build_base);
1709
1710         // Optionally prevent default --target if specified in test compile-flags.
1711         let custom_target = self
1712             .props
1713             .compile_flags
1714             .iter()
1715             .any(|x| x.starts_with("--target"));
1716
1717         if !custom_target {
1718             let target = if self.props.force_host {
1719                 &*self.config.host
1720             } else {
1721                 &*self.config.target
1722             };
1723
1724             rustc.arg(&format!("--target={}", target));
1725         }
1726
1727         if let Some(revision) = self.revision {
1728             rustc.args(&["--cfg", revision]);
1729         }
1730
1731         if !is_rustdoc {
1732             if let Some(ref incremental_dir) = self.props.incremental_dir {
1733                 rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]);
1734                 rustc.args(&["-Z", "incremental-verify-ich"]);
1735                 rustc.args(&["-Z", "incremental-queries"]);
1736             }
1737
1738             if self.config.mode == CodegenUnits {
1739                 rustc.args(&["-Z", "human_readable_cgu_names"]);
1740             }
1741         }
1742
1743         match self.config.mode {
1744             CompileFail | ParseFail | Incremental => {
1745                 // If we are extracting and matching errors in the new
1746                 // fashion, then you want JSON mode. Old-skool error
1747                 // patterns still match the raw compiler output.
1748                 if self.props.error_patterns.is_empty() {
1749                     rustc.args(&["--error-format", "json"]);
1750                 }
1751                 if !self.props.disable_ui_testing_normalization {
1752                     rustc.arg("-Zui-testing");
1753                 }
1754             }
1755             RunPass | Ui => {
1756                 if !self
1757                     .props
1758                     .compile_flags
1759                     .iter()
1760                     .any(|s| s.starts_with("--error-format"))
1761                 {
1762                     rustc.args(&["--error-format", "json"]);
1763                 }
1764                 if !self.props.disable_ui_testing_normalization {
1765                     rustc.arg("-Zui-testing");
1766                 }
1767             }
1768             MirOpt => {
1769                 rustc.args(&[
1770                     "-Zdump-mir=all",
1771                     "-Zmir-opt-level=3",
1772                     "-Zdump-mir-exclude-pass-number",
1773                 ]);
1774
1775                 let mir_dump_dir = self.get_mir_dump_dir();
1776                 let _ = fs::remove_dir_all(&mir_dump_dir);
1777                 create_dir_all(mir_dump_dir.as_path()).unwrap();
1778                 let mut dir_opt = "-Zdump-mir-dir=".to_string();
1779                 dir_opt.push_str(mir_dump_dir.to_str().unwrap());
1780                 debug!("dir_opt: {:?}", dir_opt);
1781
1782                 rustc.arg(dir_opt);
1783             }
1784             RunFail | RunPassValgrind | Pretty | DebugInfoBoth | DebugInfoGdb | DebugInfoLldb
1785             | Codegen | Rustdoc | RunMake | CodegenUnits => {
1786                 // do not use JSON output
1787             }
1788         }
1789
1790         if self.props.skip_codegen {
1791             assert!(
1792                 !self
1793                     .props
1794                     .compile_flags
1795                     .iter()
1796                     .any(|s| s.starts_with("--emit"))
1797             );
1798             rustc.args(&["--emit", "metadata"]);
1799         }
1800
1801         if !is_rustdoc {
1802             if self.config.target == "wasm32-unknown-unknown" {
1803                 // rustc.arg("-g"); // get any backtrace at all on errors
1804             } else if !self.props.no_prefer_dynamic {
1805                 rustc.args(&["-C", "prefer-dynamic"]);
1806             }
1807         }
1808
1809         match output_file {
1810             TargetLocation::ThisFile(path) => {
1811                 rustc.arg("-o").arg(path);
1812             }
1813             TargetLocation::ThisDirectory(path) => {
1814                 rustc.arg("--out-dir").arg(path);
1815             }
1816         }
1817
1818         match self.config.compare_mode {
1819             Some(CompareMode::Nll) => {
1820                 rustc.args(&["-Zborrowck=migrate", "-Ztwo-phase-borrows"]);
1821             }
1822             Some(CompareMode::Polonius) => {
1823                 rustc.args(&["-Zpolonius", "-Zborrowck=mir", "-Ztwo-phase-borrows"]);
1824             }
1825             None => {}
1826         }
1827
1828         if self.props.force_host {
1829             rustc.args(self.split_maybe_args(&self.config.host_rustcflags));
1830         } else {
1831             rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
1832         }
1833         if !is_rustdoc {
1834             if let Some(ref linker) = self.config.linker {
1835                 rustc.arg(format!("-Clinker={}", linker));
1836             }
1837         }
1838
1839         rustc.args(&self.props.compile_flags);
1840
1841         rustc
1842     }
1843
1844     fn make_exe_name(&self) -> PathBuf {
1845         // Using a single letter here to keep the path length down for
1846         // Windows.  Some test names get very long.  rustc creates `rcgu`
1847         // files with the module name appended to it which can more than
1848         // double the length.
1849         let mut f = self.output_base_dir().join("a");
1850         // FIXME: This is using the host architecture exe suffix, not target!
1851         if self.config.target.contains("emscripten") {
1852             f = f.with_extra_extension("js");
1853         } else if self.config.target.contains("wasm32") {
1854             f = f.with_extra_extension("wasm");
1855         } else if !env::consts::EXE_SUFFIX.is_empty() {
1856             f = f.with_extra_extension(env::consts::EXE_SUFFIX);
1857         }
1858         f
1859     }
1860
1861     fn make_run_args(&self) -> ProcArgs {
1862         // If we've got another tool to run under (valgrind),
1863         // then split apart its command
1864         let mut args = self.split_maybe_args(&self.config.runtool);
1865
1866         // If this is emscripten, then run tests under nodejs
1867         if self.config.target.contains("emscripten") {
1868             if let Some(ref p) = self.config.nodejs {
1869                 args.push(p.clone());
1870             } else {
1871                 self.fatal("no NodeJS binary found (--nodejs)");
1872             }
1873         }
1874
1875         // If this is otherwise wasm , then run tests under nodejs with our
1876         // shim
1877         if self.config.target.contains("wasm32") {
1878             if let Some(ref p) = self.config.nodejs {
1879                 args.push(p.clone());
1880             } else {
1881                 self.fatal("no NodeJS binary found (--nodejs)");
1882             }
1883
1884             let src = self.config.src_base
1885                 .parent().unwrap() // chop off `run-pass`
1886                 .parent().unwrap() // chop off `test`
1887                 .parent().unwrap(); // chop off `src`
1888             args.push(src.join("src/etc/wasm32-shim.js").display().to_string());
1889         }
1890
1891         let exe_file = self.make_exe_name();
1892
1893         // FIXME (#9639): This needs to handle non-utf8 paths
1894         args.push(exe_file.to_str().unwrap().to_owned());
1895
1896         // Add the arguments in the run_flags directive
1897         args.extend(self.split_maybe_args(&self.props.run_flags));
1898
1899         let prog = args.remove(0);
1900         ProcArgs { prog, args }
1901     }
1902
1903     fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<String> {
1904         match *argstr {
1905             Some(ref s) => s
1906                 .split(' ')
1907                 .filter_map(|s| {
1908                     if s.chars().all(|c| c.is_whitespace()) {
1909                         None
1910                     } else {
1911                         Some(s.to_owned())
1912                     }
1913                 })
1914                 .collect(),
1915             None => Vec::new(),
1916         }
1917     }
1918
1919     fn make_cmdline(&self, command: &Command, libpath: &str) -> String {
1920         use util;
1921
1922         // Linux and mac don't require adjusting the library search path
1923         if cfg!(unix) {
1924             format!("{:?}", command)
1925         } else {
1926             // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1927             // for diagnostic purposes
1928             fn lib_path_cmd_prefix(path: &str) -> String {
1929                 format!(
1930                     "{}=\"{}\"",
1931                     util::lib_path_env_var(),
1932                     util::make_new_path(path)
1933                 )
1934             }
1935
1936             format!("{} {:?}", lib_path_cmd_prefix(libpath), command)
1937         }
1938     }
1939
1940     fn dump_output(&self, out: &str, err: &str) {
1941         let revision = if let Some(r) = self.revision {
1942             format!("{}.", r)
1943         } else {
1944             String::new()
1945         };
1946
1947         self.dump_output_file(out, &format!("{}out", revision));
1948         self.dump_output_file(err, &format!("{}err", revision));
1949         self.maybe_dump_to_stdout(out, err);
1950     }
1951
1952     fn dump_output_file(&self, out: &str, extension: &str) {
1953         let outfile = self.make_out_name(extension);
1954         File::create(&outfile)
1955             .unwrap()
1956             .write_all(out.as_bytes())
1957             .unwrap();
1958     }
1959
1960     /// Create a filename for output with the given extension.  Example:
1961     ///   /.../testname.revision.mode/testname.extension
1962     fn make_out_name(&self, extension: &str) -> PathBuf {
1963         self.output_base_name().with_extension(extension)
1964     }
1965
1966     /// Directory where auxiliary files are written.  Example:
1967     ///   /.../testname.revision.mode/auxiliary/
1968     fn aux_output_dir_name(&self) -> PathBuf {
1969         self.output_base_dir()
1970             .join("auxiliary")
1971             .with_extra_extension(self.config.mode.disambiguator())
1972     }
1973
1974     /// Generates a unique name for the test, such as `testname.revision.mode`.
1975     fn output_testname_unique(&self) -> PathBuf {
1976         output_testname_unique(self.config, self.testpaths, self.safe_revision())
1977     }
1978
1979     /// The revision, ignored for Incremental since it wants all revisions in
1980     /// the same directory.
1981     fn safe_revision(&self) -> Option<&str> {
1982         if self.config.mode == Incremental {
1983             None
1984         } else {
1985             self.revision
1986         }
1987     }
1988
1989     /// Absolute path to the directory where all output for the given
1990     /// test/revision should reside.  Example:
1991     ///   /path/to/build/host-triple/test/ui/relative/testname.revision.mode/
1992     fn output_base_dir(&self) -> PathBuf {
1993         output_base_dir(self.config, self.testpaths, self.safe_revision())
1994     }
1995
1996     /// Absolute path to the base filename used as output for the given
1997     /// test/revision.  Example:
1998     ///   /.../relative/testname.revision.mode/testname
1999     fn output_base_name(&self) -> PathBuf {
2000         output_base_name(self.config, self.testpaths, self.safe_revision())
2001     }
2002
2003     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
2004         if self.config.verbose {
2005             println!("------{}------------------------------", "stdout");
2006             println!("{}", out);
2007             println!("------{}------------------------------", "stderr");
2008             println!("{}", err);
2009             println!("------------------------------------------");
2010         }
2011     }
2012
2013     fn error(&self, err: &str) {
2014         match self.revision {
2015             Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
2016             None => println!("\nerror: {}", err),
2017         }
2018     }
2019
2020     fn fatal(&self, err: &str) -> ! {
2021         self.error(err);
2022         panic!();
2023     }
2024
2025     fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
2026         self.try_print_open_handles();
2027         self.error(err);
2028         proc_res.fatal(None);
2029     }
2030
2031     // This function is a poor man's attempt to debug rust-lang/rust#38620, if
2032     // that's closed then this should be deleted
2033     //
2034     // This is a very "opportunistic" debugging attempt, so we ignore all
2035     // errors here.
2036     fn try_print_open_handles(&self) {
2037         if !cfg!(windows) {
2038             return;
2039         }
2040         if self.config.mode != Incremental {
2041             return;
2042         }
2043
2044         let filename = match self.testpaths.file.file_stem() {
2045             Some(path) => path,
2046             None => return,
2047         };
2048
2049         let mut cmd = Command::new("handle.exe");
2050         cmd.arg("-a").arg("-u");
2051         cmd.arg(filename);
2052         cmd.arg("-nobanner");
2053         cmd.stdout(Stdio::piped());
2054         cmd.stderr(Stdio::piped());
2055         let output = match cmd.spawn().and_then(read2_abbreviated) {
2056             Ok(output) => output,
2057             Err(_) => return,
2058         };
2059         println!("---------------------------------------------------");
2060         println!("ran extra command to debug rust-lang/rust#38620: ");
2061         println!("{:?}", cmd);
2062         println!("result: {}", output.status);
2063         println!("--- stdout ----------------------------------------");
2064         println!("{}", String::from_utf8_lossy(&output.stdout));
2065         println!("--- stderr ----------------------------------------");
2066         println!("{}", String::from_utf8_lossy(&output.stderr));
2067         println!("---------------------------------------------------");
2068     }
2069
2070     // codegen tests (using FileCheck)
2071
2072     fn compile_test_and_save_ir(&self) -> ProcRes {
2073         let aux_dir = self.aux_output_dir_name();
2074
2075         let output_file = TargetLocation::ThisDirectory(self.output_base_dir());
2076         let mut rustc = self.make_compile_args(&self.testpaths.file, output_file);
2077         rustc.arg("-L").arg(aux_dir).arg("--emit=llvm-ir");
2078
2079         self.compose_and_run_compiler(rustc, None)
2080     }
2081
2082     fn check_ir_with_filecheck(&self) -> ProcRes {
2083         let irfile = self.output_base_name().with_extension("ll");
2084         let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
2085         filecheck
2086             .arg("--input-file")
2087             .arg(irfile)
2088             .arg(&self.testpaths.file);
2089         self.compose_and_run(filecheck, "", None, None)
2090     }
2091
2092     fn run_codegen_test(&self) {
2093         assert!(self.revision.is_none(), "revisions not relevant here");
2094
2095         if self.config.llvm_filecheck.is_none() {
2096             self.fatal("missing --llvm-filecheck");
2097         }
2098
2099         let mut proc_res = self.compile_test_and_save_ir();
2100         if !proc_res.status.success() {
2101             self.fatal_proc_rec("compilation failed!", &proc_res);
2102         }
2103
2104         proc_res = self.check_ir_with_filecheck();
2105         if !proc_res.status.success() {
2106             self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
2107         }
2108     }
2109
2110     fn charset() -> &'static str {
2111         // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
2112         if cfg!(target_os = "bitrig") {
2113             "auto"
2114         } else if cfg!(target_os = "freebsd") {
2115             "ISO-8859-1"
2116         } else {
2117             "UTF-8"
2118         }
2119     }
2120
2121     fn run_rustdoc_test(&self) {
2122         assert!(self.revision.is_none(), "revisions not relevant here");
2123
2124         let out_dir = self.output_base_dir();
2125         let _ = fs::remove_dir_all(&out_dir);
2126         create_dir_all(&out_dir).unwrap();
2127
2128         let proc_res = self.document(&out_dir);
2129         if !proc_res.status.success() {
2130             self.fatal_proc_rec("rustdoc failed!", &proc_res);
2131         }
2132
2133         if self.props.check_test_line_numbers_match {
2134             self.check_rustdoc_test_option(proc_res);
2135         } else {
2136             let root = self.config.find_rust_src_root().unwrap();
2137             let res = self.cmd2procres(
2138                 Command::new(&self.config.docck_python)
2139                     .arg(root.join("src/etc/htmldocck.py"))
2140                     .arg(out_dir)
2141                     .arg(&self.testpaths.file),
2142             );
2143             if !res.status.success() {
2144                 self.fatal_proc_rec("htmldocck failed!", &res);
2145             }
2146         }
2147     }
2148
2149     fn get_lines<P: AsRef<Path>>(
2150         &self,
2151         path: &P,
2152         mut other_files: Option<&mut Vec<String>>,
2153     ) -> Vec<usize> {
2154         let mut file =
2155             fs::File::open(path).expect("markdown_test_output_check_entry File::open failed");
2156         let mut content = String::new();
2157         file.read_to_string(&mut content)
2158             .expect("markdown_test_output_check_entry read_to_string failed");
2159         let mut ignore = false;
2160         content
2161             .lines()
2162             .enumerate()
2163             .filter_map(|(line_nb, line)| {
2164                 if (line.trim_left().starts_with("pub mod ")
2165                     || line.trim_left().starts_with("mod "))
2166                     && line.ends_with(';')
2167                 {
2168                     if let Some(ref mut other_files) = other_files {
2169                         other_files.push(line.rsplit("mod ").next().unwrap().replace(";", ""));
2170                     }
2171                     None
2172                 } else {
2173                     let sline = line.split("///").last().unwrap_or("");
2174                     let line = sline.trim_left();
2175                     if line.starts_with("```") {
2176                         if ignore {
2177                             ignore = false;
2178                             None
2179                         } else {
2180                             ignore = true;
2181                             Some(line_nb + 1)
2182                         }
2183                     } else {
2184                         None
2185                     }
2186                 }
2187             })
2188             .collect()
2189     }
2190
2191     fn check_rustdoc_test_option(&self, res: ProcRes) {
2192         let mut other_files = Vec::new();
2193         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
2194         let cwd = env::current_dir().unwrap();
2195         files.insert(
2196             self.testpaths
2197                 .file
2198                 .strip_prefix(&cwd)
2199                 .unwrap_or(&self.testpaths.file)
2200                 .to_str()
2201                 .unwrap()
2202                 .replace('\\', "/"),
2203             self.get_lines(&self.testpaths.file, Some(&mut other_files)),
2204         );
2205         for other_file in other_files {
2206             let mut path = self.testpaths.file.clone();
2207             path.set_file_name(&format!("{}.rs", other_file));
2208             files.insert(
2209                 path.strip_prefix(&cwd)
2210                     .unwrap_or(&path)
2211                     .to_str()
2212                     .unwrap()
2213                     .replace('\\', "/"),
2214                 self.get_lines(&path, None),
2215             );
2216         }
2217
2218         let mut tested = 0;
2219         for _ in res
2220             .stdout
2221             .split('\n')
2222             .filter(|s| s.starts_with("test "))
2223             .inspect(|s| {
2224                 let tmp: Vec<&str> = s.split(" - ").collect();
2225                 if tmp.len() == 2 {
2226                     let path = tmp[0].rsplit("test ").next().unwrap();
2227                     if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
2228                         tested += 1;
2229                         let mut iter = tmp[1].split("(line ");
2230                         iter.next();
2231                         let line = iter
2232                             .next()
2233                             .unwrap_or(")")
2234                             .split(')')
2235                             .next()
2236                             .unwrap_or("0")
2237                             .parse()
2238                             .unwrap_or(0);
2239                         if let Ok(pos) = v.binary_search(&line) {
2240                             v.remove(pos);
2241                         } else {
2242                             self.fatal_proc_rec(
2243                                 &format!("Not found doc test: \"{}\" in \"{}\":{:?}", s, path, v),
2244                                 &res,
2245                             );
2246                         }
2247                     }
2248                 }
2249             }) {}
2250         if tested == 0 {
2251             self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res);
2252         } else {
2253             for (entry, v) in &files {
2254                 if !v.is_empty() {
2255                     self.fatal_proc_rec(
2256                         &format!(
2257                             "Not found test at line{} \"{}\":{:?}",
2258                             if v.len() > 1 { "s" } else { "" },
2259                             entry,
2260                             v
2261                         ),
2262                         &res,
2263                     );
2264                 }
2265             }
2266         }
2267     }
2268
2269     fn run_codegen_units_test(&self) {
2270         assert!(self.revision.is_none(), "revisions not relevant here");
2271
2272         let proc_res = self.compile_test();
2273
2274         if !proc_res.status.success() {
2275             self.fatal_proc_rec("compilation failed!", &proc_res);
2276         }
2277
2278         self.check_no_compiler_crash(&proc_res);
2279
2280         const PREFIX: &'static str = "MONO_ITEM ";
2281         const CGU_MARKER: &'static str = "@@";
2282
2283         let actual: Vec<MonoItem> = proc_res
2284             .stdout
2285             .lines()
2286             .filter(|line| line.starts_with(PREFIX))
2287             .map(|line| str_to_mono_item(line, true))
2288             .collect();
2289
2290         let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
2291             .iter()
2292             .map(|e| str_to_mono_item(&e.msg[..], false))
2293             .collect();
2294
2295         let mut missing = Vec::new();
2296         let mut wrong_cgus = Vec::new();
2297
2298         for expected_item in &expected {
2299             let actual_item_with_same_name = actual.iter().find(|ti| ti.name == expected_item.name);
2300
2301             if let Some(actual_item) = actual_item_with_same_name {
2302                 if !expected_item.codegen_units.is_empty() &&
2303                    // Also check for codegen units
2304                    expected_item.codegen_units != actual_item.codegen_units
2305                 {
2306                     wrong_cgus.push((expected_item.clone(), actual_item.clone()));
2307                 }
2308             } else {
2309                 missing.push(expected_item.string.clone());
2310             }
2311         }
2312
2313         let unexpected: Vec<_> = actual
2314             .iter()
2315             .filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
2316             .map(|acgu| acgu.string.clone())
2317             .collect();
2318
2319         if !missing.is_empty() {
2320             missing.sort();
2321
2322             println!("\nThese items should have been contained but were not:\n");
2323
2324             for item in &missing {
2325                 println!("{}", item);
2326             }
2327
2328             println!("\n");
2329         }
2330
2331         if !unexpected.is_empty() {
2332             let sorted = {
2333                 let mut sorted = unexpected.clone();
2334                 sorted.sort();
2335                 sorted
2336             };
2337
2338             println!("\nThese items were contained but should not have been:\n");
2339
2340             for item in sorted {
2341                 println!("{}", item);
2342             }
2343
2344             println!("\n");
2345         }
2346
2347         if !wrong_cgus.is_empty() {
2348             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
2349             println!("\nThe following items were assigned to wrong codegen units:\n");
2350
2351             for &(ref expected_item, ref actual_item) in &wrong_cgus {
2352                 println!("{}", expected_item.name);
2353                 println!(
2354                     "  expected: {}",
2355                     codegen_units_to_str(&expected_item.codegen_units)
2356                 );
2357                 println!(
2358                     "  actual:   {}",
2359                     codegen_units_to_str(&actual_item.codegen_units)
2360                 );
2361                 println!("");
2362             }
2363         }
2364
2365         if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) {
2366             panic!();
2367         }
2368
2369         #[derive(Clone, Eq, PartialEq)]
2370         struct MonoItem {
2371             name: String,
2372             codegen_units: HashSet<String>,
2373             string: String,
2374         }
2375
2376         // [MONO_ITEM] name [@@ (cgu)+]
2377         fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem {
2378             let s = if s.starts_with(PREFIX) {
2379                 (&s[PREFIX.len()..]).trim()
2380             } else {
2381                 s.trim()
2382             };
2383
2384             let full_string = format!("{}{}", PREFIX, s);
2385
2386             let parts: Vec<&str> = s
2387                 .split(CGU_MARKER)
2388                 .map(str::trim)
2389                 .filter(|s| !s.is_empty())
2390                 .collect();
2391
2392             let name = parts[0].trim();
2393
2394             let cgus = if parts.len() > 1 {
2395                 let cgus_str = parts[1];
2396
2397                 cgus_str
2398                     .split(' ')
2399                     .map(str::trim)
2400                     .filter(|s| !s.is_empty())
2401                     .map(|s| {
2402                         if cgu_has_crate_disambiguator {
2403                             remove_crate_disambiguator_from_cgu(s)
2404                         } else {
2405                             s.to_string()
2406                         }
2407                     })
2408                     .collect()
2409             } else {
2410                 HashSet::new()
2411             };
2412
2413             MonoItem {
2414                 name: name.to_owned(),
2415                 codegen_units: cgus,
2416                 string: full_string,
2417             }
2418         }
2419
2420         fn codegen_units_to_str(cgus: &HashSet<String>) -> String {
2421             let mut cgus: Vec<_> = cgus.iter().collect();
2422             cgus.sort();
2423
2424             let mut string = String::new();
2425             for cgu in cgus {
2426                 string.push_str(&cgu[..]);
2427                 string.push_str(" ");
2428             }
2429
2430             string
2431         }
2432
2433         // Given a cgu-name-prefix of the form <crate-name>.<crate-disambiguator> or
2434         // the form <crate-name1>.<crate-disambiguator1>-in-<crate-name2>.<crate-disambiguator2>,
2435         // remove all crate-disambiguators.
2436         fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String {
2437             lazy_static! {
2438                 static ref RE: Regex = Regex::new(
2439                     r"^[^\.]+(?P<d1>\.[[:alnum:]]+)(-in-[^\.]+(?P<d2>\.[[:alnum:]]+))?"
2440                 ).unwrap();
2441             }
2442
2443             let captures = RE.captures(cgu).unwrap_or_else(|| {
2444                 panic!("invalid cgu name encountered: {}", cgu)
2445             });
2446
2447             let mut new_name = cgu.to_owned();
2448
2449             if let Some(d2) = captures.name("d2") {
2450                 new_name.replace_range(d2.start() .. d2.end(), "");
2451             }
2452
2453             let d1 = captures.name("d1").unwrap();
2454             new_name.replace_range(d1.start() .. d1.end(), "");
2455
2456             new_name
2457         }
2458     }
2459
2460     fn init_incremental_test(&self) {
2461         // (See `run_incremental_test` for an overview of how incremental tests work.)
2462
2463         // Before any of the revisions have executed, create the
2464         // incremental workproduct directory.  Delete any old
2465         // incremental work products that may be there from prior
2466         // runs.
2467         let incremental_dir = self.incremental_dir();
2468         if incremental_dir.exists() {
2469             // Canonicalizing the path will convert it to the //?/ format
2470             // on Windows, which enables paths longer than 260 character
2471             let canonicalized = incremental_dir.canonicalize().unwrap();
2472             fs::remove_dir_all(canonicalized).unwrap();
2473         }
2474         fs::create_dir_all(&incremental_dir).unwrap();
2475
2476         if self.config.verbose {
2477             print!(
2478                 "init_incremental_test: incremental_dir={}",
2479                 incremental_dir.display()
2480             );
2481         }
2482     }
2483
2484     fn run_incremental_test(&self) {
2485         // Basic plan for a test incremental/foo/bar.rs:
2486         // - load list of revisions rpass1, cfail2, rpass3
2487         //   - each should begin with `rpass`, `cfail`, or `rfail`
2488         //   - if `rpass`, expect compile and execution to succeed
2489         //   - if `cfail`, expect compilation to fail
2490         //   - if `rfail`, expect execution to fail
2491         // - create a directory build/foo/bar.incremental
2492         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass1
2493         //   - because name of revision starts with "rpass", expect success
2494         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C cfail2
2495         //   - because name of revision starts with "cfail", expect an error
2496         //   - load expected errors as usual, but filter for those that end in `[rfail2]`
2497         // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass3
2498         //   - because name of revision starts with "rpass", expect success
2499         // - execute build/foo/bar.exe and save output
2500         //
2501         // FIXME -- use non-incremental mode as an oracle? That doesn't apply
2502         // to #[rustc_dirty] and clean tests I guess
2503
2504         let revision = self
2505             .revision
2506             .expect("incremental tests require a list of revisions");
2507
2508         // Incremental workproduct directory should have already been created.
2509         let incremental_dir = self.incremental_dir();
2510         assert!(
2511             incremental_dir.exists(),
2512             "init_incremental_test failed to create incremental dir"
2513         );
2514
2515         // Add an extra flag pointing at the incremental directory.
2516         let mut revision_props = self.props.clone();
2517         revision_props.incremental_dir = Some(incremental_dir);
2518
2519         let revision_cx = TestCx {
2520             config: self.config,
2521             props: &revision_props,
2522             testpaths: self.testpaths,
2523             revision: self.revision,
2524         };
2525
2526         if self.config.verbose {
2527             print!(
2528                 "revision={:?} revision_props={:#?}",
2529                 revision, revision_props
2530             );
2531         }
2532
2533         if revision.starts_with("rpass") {
2534             revision_cx.run_rpass_test();
2535         } else if revision.starts_with("rfail") {
2536             revision_cx.run_rfail_test();
2537         } else if revision.starts_with("cfail") {
2538             revision_cx.run_cfail_test();
2539         } else {
2540             revision_cx.fatal("revision name must begin with rpass, rfail, or cfail");
2541         }
2542     }
2543
2544     /// Directory where incremental work products are stored.
2545     fn incremental_dir(&self) -> PathBuf {
2546         self.output_base_name().with_extension("inc")
2547     }
2548
2549     fn run_rmake_test(&self) {
2550         let cwd = env::current_dir().unwrap();
2551         let src_root = self
2552             .config
2553             .src_base
2554             .parent()
2555             .unwrap()
2556             .parent()
2557             .unwrap()
2558             .parent()
2559             .unwrap();
2560         let src_root = cwd.join(&src_root);
2561
2562         let tmpdir = cwd.join(self.output_base_name());
2563         if tmpdir.exists() {
2564             self.aggressive_rm_rf(&tmpdir).unwrap();
2565         }
2566         create_dir_all(&tmpdir).unwrap();
2567
2568         let host = &self.config.host;
2569         let make = if host.contains("bitrig")
2570             || host.contains("dragonfly")
2571             || host.contains("freebsd")
2572             || host.contains("netbsd")
2573             || host.contains("openbsd")
2574         {
2575             "gmake"
2576         } else {
2577             "make"
2578         };
2579
2580         let mut cmd = Command::new(make);
2581         cmd.current_dir(&self.testpaths.file)
2582             .stdout(Stdio::piped())
2583             .stderr(Stdio::piped())
2584             .env("TARGET", &self.config.target)
2585             .env("PYTHON", &self.config.docck_python)
2586             .env("S", src_root)
2587             .env("RUST_BUILD_STAGE", &self.config.stage_id)
2588             .env("RUSTC", cwd.join(&self.config.rustc_path))
2589             .env("TMPDIR", &tmpdir)
2590             .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
2591             .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
2592             .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
2593             .env("LLVM_COMPONENTS", &self.config.llvm_components)
2594             .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags)
2595
2596             // We for sure don't want these tests to run in parallel, so make
2597             // sure they don't have access to these vars if we we run via `make`
2598             // at the top level
2599             .env_remove("MAKEFLAGS")
2600             .env_remove("MFLAGS")
2601             .env_remove("CARGO_MAKEFLAGS");
2602
2603         if let Some(ref rustdoc) = self.config.rustdoc_path {
2604             cmd.env("RUSTDOC", cwd.join(rustdoc));
2605         }
2606
2607         if let Some(ref node) = self.config.nodejs {
2608             cmd.env("NODE", node);
2609         }
2610
2611         if let Some(ref linker) = self.config.linker {
2612             cmd.env("RUSTC_LINKER", linker);
2613         }
2614
2615         // We don't want RUSTFLAGS set from the outside to interfere with
2616         // compiler flags set in the test cases:
2617         cmd.env_remove("RUSTFLAGS");
2618
2619         if self.config.target.contains("msvc") && self.config.cc != "" {
2620             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
2621             // and that `lib.exe` lives next to it.
2622             let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
2623
2624             // MSYS doesn't like passing flags of the form `/foo` as it thinks it's
2625             // a path and instead passes `C:\msys64\foo`, so convert all
2626             // `/`-arguments to MSVC here to `-` arguments.
2627             let cflags = self
2628                 .config
2629                 .cflags
2630                 .split(' ')
2631                 .map(|s| s.replace("/", "-"))
2632                 .collect::<Vec<_>>()
2633                 .join(" ");
2634
2635             cmd.env("IS_MSVC", "1")
2636                 .env("IS_WINDOWS", "1")
2637                 .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
2638                 .env("CC", format!("'{}' {}", self.config.cc, cflags))
2639                 .env("CXX", format!("'{}'", &self.config.cxx));
2640         } else {
2641             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
2642                 .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
2643                 .env("AR", &self.config.ar);
2644
2645             if self.config.target.contains("windows") {
2646                 cmd.env("IS_WINDOWS", "1");
2647             }
2648         }
2649
2650         let output = cmd
2651             .spawn()
2652             .and_then(read2_abbreviated)
2653             .expect("failed to spawn `make`");
2654         if !output.status.success() {
2655             let res = ProcRes {
2656                 status: output.status,
2657                 stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
2658                 stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
2659                 cmdline: format!("{:?}", cmd),
2660             };
2661             self.fatal_proc_rec("make failed", &res);
2662         }
2663     }
2664
2665     fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
2666         for e in path.read_dir()? {
2667             let entry = e?;
2668             let path = entry.path();
2669             if entry.file_type()?.is_dir() {
2670                 self.aggressive_rm_rf(&path)?;
2671             } else {
2672                 // Remove readonly files as well on windows (by default we can't)
2673                 fs::remove_file(&path).or_else(|e| {
2674                     if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied {
2675                         let mut meta = entry.metadata()?.permissions();
2676                         meta.set_readonly(false);
2677                         fs::set_permissions(&path, meta)?;
2678                         fs::remove_file(&path)
2679                     } else {
2680                         Err(e)
2681                     }
2682                 })?;
2683             }
2684         }
2685         fs::remove_dir(path)
2686     }
2687
2688     fn run_ui_test(&self) {
2689         // if the user specified a format in the ui test
2690         // print the output to the stderr file, otherwise extract
2691         // the rendered error messages from json and print them
2692         let explicit = self
2693             .props
2694             .compile_flags
2695             .iter()
2696             .any(|s| s.contains("--error-format"));
2697         let proc_res = self.compile_test();
2698         self.check_if_test_should_compile(&proc_res);
2699
2700         let expected_stderr = self.load_expected_output(UI_STDERR);
2701         let expected_stdout = self.load_expected_output(UI_STDOUT);
2702         let expected_fixed = self.load_expected_output(UI_FIXED);
2703
2704         let normalized_stdout =
2705             self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
2706
2707         let stderr = if explicit {
2708             proc_res.stderr.clone()
2709         } else {
2710             json::extract_rendered(&proc_res.stderr, &proc_res)
2711         };
2712
2713         let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
2714
2715         let mut errors = 0;
2716         if !self.props.dont_check_compiler_stdout {
2717             errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2718         }
2719         if !self.props.dont_check_compiler_stderr {
2720             errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
2721         }
2722
2723         let modes_to_prune = vec![CompareMode::Nll];
2724         self.prune_duplicate_outputs(&modes_to_prune);
2725
2726         if self.config.compare_mode.is_some() {
2727             // don't test rustfix with nll right now
2728         } else if self.props.run_rustfix {
2729             // Apply suggestions from rustc to the code itself
2730             let unfixed_code = self
2731                 .load_expected_output_from_path(&self.testpaths.file)
2732                 .unwrap();
2733             let suggestions = get_suggestions_from_json(
2734                 &proc_res.stderr,
2735                 &HashSet::new(),
2736                 if self.props.rustfix_only_machine_applicable {
2737                     Filter::MachineApplicableOnly
2738                 } else {
2739                     Filter::Everything
2740                 },
2741             ).unwrap();
2742             let fixed_code = apply_suggestions(&unfixed_code, &suggestions).expect(&format!(
2743                 "failed to apply suggestions for {:?} with rustfix",
2744                 self.testpaths.file
2745             ));
2746
2747             errors += self.compare_output("fixed", &fixed_code, &expected_fixed);
2748         } else if !expected_fixed.is_empty() {
2749             panic!(
2750                 "the `// run-rustfix` directive wasn't found but a `*.fixed` \
2751                  file was found"
2752             );
2753         }
2754
2755         if errors > 0 {
2756             println!("To update references, rerun the tests and pass the `--bless` flag");
2757             let relative_path_to_file = self
2758                 .testpaths
2759                 .relative_dir
2760                 .join(self.testpaths.file.file_name().unwrap());
2761             println!(
2762                 "To only update this specific test, also pass `--test-args {}`",
2763                 relative_path_to_file.display(),
2764             );
2765             self.fatal_proc_rec(
2766                 &format!("{} errors occurred comparing output.", errors),
2767                 &proc_res,
2768             );
2769         }
2770
2771         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
2772
2773         if self.should_run_successfully() {
2774             let proc_res = self.exec_compiled_test();
2775
2776             if !proc_res.status.success() {
2777                 self.fatal_proc_rec("test run failed!", &proc_res);
2778             }
2779         }
2780
2781         debug!("run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \
2782                proc_res.status={:?} props.error_patterns={:?}",
2783                explicit, self.config.compare_mode, expected_errors, proc_res.status,
2784                self.props.error_patterns);
2785         if !explicit && self.config.compare_mode.is_none() {
2786             if !expected_errors.is_empty() && !proc_res.status.success() {
2787                 // "//~ERROR comments"
2788                 self.check_expected_errors(expected_errors, &proc_res);
2789             } else if !self.props.error_patterns.is_empty() && !proc_res.status.success() {
2790                 // "// error-pattern" comments
2791                 self.check_error_patterns(&proc_res.stderr, &proc_res);
2792             }
2793         }
2794
2795         if self.props.run_rustfix && self.config.compare_mode.is_none() {
2796             // And finally, compile the fixed code and make sure it both
2797             // succeeds and has no diagnostics.
2798             let mut rustc = self.make_compile_args(
2799                 &self.testpaths.file.with_extension(UI_FIXED),
2800                 TargetLocation::ThisFile(self.make_exe_name()),
2801             );
2802             rustc.arg("-L").arg(&self.aux_output_dir_name());
2803             let res = self.compose_and_run_compiler(rustc, None);
2804             if !res.status.success() {
2805                 self.fatal_proc_rec("failed to compile fixed code", &res);
2806             }
2807             if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
2808                 self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
2809             }
2810         }
2811     }
2812
2813     fn run_mir_opt_test(&self) {
2814         let proc_res = self.compile_test();
2815
2816         if !proc_res.status.success() {
2817             self.fatal_proc_rec("compilation failed!", &proc_res);
2818         }
2819
2820         let proc_res = self.exec_compiled_test();
2821
2822         if !proc_res.status.success() {
2823             self.fatal_proc_rec("test run failed!", &proc_res);
2824         }
2825         self.check_mir_dump();
2826     }
2827
2828     fn check_mir_dump(&self) {
2829         let mut test_file_contents = String::new();
2830         fs::File::open(self.testpaths.file.clone())
2831             .unwrap()
2832             .read_to_string(&mut test_file_contents)
2833             .unwrap();
2834         if let Some(idx) = test_file_contents.find("// END RUST SOURCE") {
2835             let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
2836             let tests_text_str = String::from(tests_text);
2837             let mut curr_test: Option<&str> = None;
2838             let mut curr_test_contents = vec![ExpectedLine::Elision];
2839             for l in tests_text_str.lines() {
2840                 debug!("line: {:?}", l);
2841                 if l.starts_with("// START ") {
2842                     let (_, t) = l.split_at("// START ".len());
2843                     curr_test = Some(t);
2844                 } else if l.starts_with("// END") {
2845                     let (_, t) = l.split_at("// END ".len());
2846                     if Some(t) != curr_test {
2847                         panic!("mismatched START END test name");
2848                     }
2849                     self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
2850                     curr_test = None;
2851                     curr_test_contents.clear();
2852                     curr_test_contents.push(ExpectedLine::Elision);
2853                 } else if l.is_empty() {
2854                     // ignore
2855                 } else if l.starts_with("//") && l.split_at("//".len()).1.trim() == "..." {
2856                     curr_test_contents.push(ExpectedLine::Elision)
2857                 } else if l.starts_with("// ") {
2858                     let (_, test_content) = l.split_at("// ".len());
2859                     curr_test_contents.push(ExpectedLine::Text(test_content));
2860                 }
2861             }
2862         }
2863     }
2864
2865     fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
2866         let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap());
2867         let source_file = &self.testpaths.file;
2868         let output_time = t(output_file);
2869         let source_time = t(source_file);
2870         if source_time > output_time {
2871             debug!(
2872                 "source file time: {:?} output file time: {:?}",
2873                 source_time, output_time
2874             );
2875             panic!(
2876                 "test source file `{}` is newer than potentially stale output file `{}`.",
2877                 source_file.display(),
2878                 test_name
2879             );
2880         }
2881     }
2882
2883     fn compare_mir_test_output(&self, test_name: &str, expected_content: &[ExpectedLine<&str>]) {
2884         let mut output_file = PathBuf::new();
2885         output_file.push(self.get_mir_dump_dir());
2886         output_file.push(test_name);
2887         debug!("comparing the contests of: {:?}", output_file);
2888         debug!("with: {:?}", expected_content);
2889         if !output_file.exists() {
2890             panic!(
2891                 "Output file `{}` from test does not exist",
2892                 output_file.into_os_string().to_string_lossy()
2893             );
2894         }
2895         self.check_mir_test_timestamp(test_name, &output_file);
2896
2897         let mut dumped_file = fs::File::open(output_file.clone()).unwrap();
2898         let mut dumped_string = String::new();
2899         dumped_file.read_to_string(&mut dumped_string).unwrap();
2900         let mut dumped_lines = dumped_string
2901             .lines()
2902             .map(|l| nocomment_mir_line(l))
2903             .filter(|l| !l.is_empty());
2904         let mut expected_lines = expected_content
2905             .iter()
2906             .filter(|&l| {
2907                 if let &ExpectedLine::Text(l) = l {
2908                     !l.is_empty()
2909                 } else {
2910                     true
2911                 }
2912             })
2913             .peekable();
2914
2915         let compare = |expected_line, dumped_line| {
2916             let e_norm = normalize_mir_line(expected_line);
2917             let d_norm = normalize_mir_line(dumped_line);
2918             debug!("found: {:?}", d_norm);
2919             debug!("expected: {:?}", e_norm);
2920             e_norm == d_norm
2921         };
2922
2923         let error = |expected_line, extra_msg| {
2924             let normalize_all = dumped_string
2925                 .lines()
2926                 .map(nocomment_mir_line)
2927                 .filter(|l| !l.is_empty())
2928                 .collect::<Vec<_>>()
2929                 .join("\n");
2930             let f = |l: &ExpectedLine<_>| match l {
2931                 &ExpectedLine::Elision => "... (elided)".into(),
2932                 &ExpectedLine::Text(t) => t,
2933             };
2934             let expected_content = expected_content
2935                 .iter()
2936                 .map(|l| f(l))
2937                 .collect::<Vec<_>>()
2938                 .join("\n");
2939             panic!(
2940                 "Did not find expected line, error: {}\n\
2941                  Expected Line: {:?}\n\
2942                  Test Name: {}\n\
2943                  Expected:\n{}\n\
2944                  Actual:\n{}",
2945                 extra_msg, expected_line, test_name, expected_content, normalize_all
2946             );
2947         };
2948
2949         // We expect each non-empty line to appear consecutively, non-consecutive lines
2950         // must be separated by at least one Elision
2951         let mut start_block_line = None;
2952         while let Some(dumped_line) = dumped_lines.next() {
2953             match expected_lines.next() {
2954                 Some(&ExpectedLine::Text(expected_line)) => {
2955                     let normalized_expected_line = normalize_mir_line(expected_line);
2956                     if normalized_expected_line.contains(":{") {
2957                         start_block_line = Some(expected_line);
2958                     }
2959
2960                     if !compare(expected_line, dumped_line) {
2961                         error!("{:?}", start_block_line);
2962                         error(
2963                             expected_line,
2964                             format!(
2965                                 "Mismatch in lines\n\
2966                                  Current block: {}\n\
2967                                  Actual Line: {:?}",
2968                                 start_block_line.unwrap_or("None"),
2969                                 dumped_line
2970                             ),
2971                         );
2972                     }
2973                 }
2974                 Some(&ExpectedLine::Elision) => {
2975                     // skip any number of elisions in a row.
2976                     while let Some(&&ExpectedLine::Elision) = expected_lines.peek() {
2977                         expected_lines.next();
2978                     }
2979                     if let Some(&ExpectedLine::Text(expected_line)) = expected_lines.next() {
2980                         let mut found = compare(expected_line, dumped_line);
2981                         if found {
2982                             continue;
2983                         }
2984                         while let Some(dumped_line) = dumped_lines.next() {
2985                             found = compare(expected_line, dumped_line);
2986                             if found {
2987                                 break;
2988                             }
2989                         }
2990                         if !found {
2991                             error(expected_line, "ran out of mir dump to match against".into());
2992                         }
2993                     }
2994                 }
2995                 None => {}
2996             }
2997         }
2998     }
2999
3000     fn get_mir_dump_dir(&self) -> PathBuf {
3001         let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path());
3002         debug!("input_file: {:?}", self.testpaths.file);
3003         mir_dump_dir.push(&self.testpaths.relative_dir);
3004         mir_dump_dir.push(self.testpaths.file.file_stem().unwrap());
3005         mir_dump_dir
3006     }
3007
3008     fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
3009         let parent_dir = self.testpaths.file.parent().unwrap();
3010         let cflags = self.props.compile_flags.join(" ");
3011         let json = cflags.contains("--error-format json")
3012             || cflags.contains("--error-format pretty-json")
3013             || cflags.contains("--error-format=json")
3014             || cflags.contains("--error-format=pretty-json");
3015         let parent_dir_str = if json {
3016             parent_dir.display().to_string().replace("\\", "\\\\")
3017         } else {
3018             parent_dir.display().to_string()
3019         };
3020
3021         let mut normalized = output.replace(&parent_dir_str, "$DIR");
3022
3023         // Paths into the libstd/libcore
3024         let src_dir = self.config.src_base.parent().unwrap().parent().unwrap();
3025         let src_dir_str = if json {
3026             src_dir.display().to_string().replace("\\", "\\\\")
3027         } else {
3028             src_dir.display().to_string()
3029         };
3030         normalized = normalized.replace(&src_dir_str, "$SRC_DIR");
3031
3032         // Paths into the build directory
3033         let test_build_dir = &self.config.build_base;
3034         let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap();
3035
3036         // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui
3037         normalized = normalized.replace(test_build_dir.to_str().unwrap(), "$TEST_BUILD_DIR");
3038         // eg. /home/user/rust/build
3039         normalized = normalized.replace(&parent_build_dir.to_str().unwrap(), "$BUILD_DIR");
3040
3041         // Paths into lib directory.
3042         let mut lib_dir = parent_build_dir.parent().unwrap().to_path_buf();
3043         lib_dir.push("lib");
3044         normalized = normalized.replace(&lib_dir.to_str().unwrap(), "$LIB_DIR");
3045
3046         if json {
3047             // escaped newlines in json strings should be readable
3048             // in the stderr files. There's no point int being correct,
3049             // since only humans process the stderr files.
3050             // Thus we just turn escaped newlines back into newlines.
3051             normalized = normalized.replace("\\n", "\n");
3052         }
3053
3054         // If there are `$SRC_DIR` normalizations with line and column numbers, then replace them
3055         // with placeholders as we do not want tests needing updated when compiler source code
3056         // changes.
3057         // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL
3058         normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+").unwrap()
3059             .replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned();
3060
3061         normalized = normalized.replace("\\\\", "\\") // denormalize for paths on windows
3062               .replace("\\", "/") // normalize for paths on windows
3063               .replace("\r\n", "\n") // normalize for linebreaks on windows
3064               .replace("\t", "\\t"); // makes tabs visible
3065         for rule in custom_rules {
3066             let re = Regex::new(&rule.0).expect("bad regex in custom normalization rule");
3067             normalized = re.replace_all(&normalized, &rule.1[..]).into_owned();
3068         }
3069         normalized
3070     }
3071
3072     fn expected_output_path(&self, kind: &str) -> PathBuf {
3073         let mut path = expected_output_path(
3074             &self.testpaths,
3075             self.revision,
3076             &self.config.compare_mode,
3077             kind,
3078         );
3079
3080         if !path.exists() {
3081             if let Some(CompareMode::Polonius) = self.config.compare_mode {
3082                 path = expected_output_path(
3083                     &self.testpaths,
3084                     self.revision,
3085                     &Some(CompareMode::Nll),
3086                     kind,
3087                 );
3088             }
3089         }
3090
3091         if !path.exists() {
3092             path = expected_output_path(&self.testpaths, self.revision, &None, kind);
3093         }
3094
3095         path
3096     }
3097
3098     fn load_expected_output(&self, kind: &str) -> String {
3099         let path = self.expected_output_path(kind);
3100         if path.exists() {
3101             match self.load_expected_output_from_path(&path) {
3102                 Ok(x) => x,
3103                 Err(x) => self.fatal(&x),
3104             }
3105         } else {
3106             String::new()
3107         }
3108     }
3109
3110     fn load_expected_output_from_path(&self, path: &Path) -> Result<String, String> {
3111         let mut result = String::new();
3112         match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) {
3113             Ok(_) => Ok(result),
3114             Err(e) => Err(format!(
3115                 "failed to load expected output from `{}`: {}",
3116                 path.display(),
3117                 e
3118             )),
3119         }
3120     }
3121
3122     fn delete_file(&self, file: &PathBuf) {
3123         if let Err(e) = ::std::fs::remove_file(file) {
3124             self.fatal(&format!(
3125                 "failed to delete `{}`: {}",
3126                 file.display(),
3127                 e,
3128             ));
3129         }
3130     }
3131
3132     fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
3133         if actual == expected {
3134             return 0;
3135         }
3136
3137         if !self.config.bless {
3138             if expected.is_empty() {
3139                 println!("normalized {}:\n{}\n", kind, actual);
3140             } else {
3141                 println!("diff of {}:\n", kind);
3142                 let diff_results = make_diff(expected, actual, 3);
3143                 for result in diff_results {
3144                     let mut line_number = result.line_number;
3145                     for line in result.lines {
3146                         match line {
3147                             DiffLine::Expected(e) => {
3148                                 println!("-\t{}", e);
3149                                 line_number += 1;
3150                             }
3151                             DiffLine::Context(c) => {
3152                                 println!("{}\t{}", line_number, c);
3153                                 line_number += 1;
3154                             }
3155                             DiffLine::Resulting(r) => {
3156                                 println!("+\t{}", r);
3157                             }
3158                         }
3159                     }
3160                     println!("");
3161                 }
3162             }
3163         }
3164
3165         let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
3166         let output_file = self
3167             .output_base_name()
3168             .with_extra_extension(self.revision.unwrap_or(""))
3169             .with_extra_extension(mode)
3170             .with_extra_extension(kind);
3171
3172         let mut files = vec![output_file];
3173         if self.config.bless {
3174             files.push(expected_output_path(
3175                 self.testpaths,
3176                 self.revision,
3177                 &self.config.compare_mode,
3178                 kind,
3179             ));
3180         }
3181
3182         for output_file in &files {
3183             if actual.is_empty() {
3184                 self.delete_file(output_file);
3185             } else {
3186                 match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
3187                     Ok(()) => {}
3188                     Err(e) => self.fatal(&format!(
3189                         "failed to write {} to `{}`: {}",
3190                         kind,
3191                         output_file.display(),
3192                         e
3193                     )),
3194                 }
3195             }
3196         }
3197
3198         println!("\nThe actual {0} differed from the expected {0}.", kind);
3199         for output_file in files {
3200             println!("Actual {} saved to {}", kind, output_file.display());
3201         }
3202         if self.config.bless {
3203             0
3204         } else {
3205             1
3206         }
3207     }
3208
3209     fn prune_duplicate_output(&self, mode: CompareMode, kind: &str, canon_content: &str) {
3210         let examined_path = expected_output_path(
3211             &self.testpaths,
3212             self.revision,
3213             &Some(mode),
3214             kind,
3215         );
3216
3217         let examined_content = self
3218             .load_expected_output_from_path(&examined_path)
3219             .unwrap_or_else(|_| String::new());
3220
3221         if examined_path.exists() && canon_content == &examined_content {
3222             self.delete_file(&examined_path);
3223         }
3224     }
3225
3226     fn prune_duplicate_outputs(&self, modes: &[CompareMode]) {
3227         if self.config.bless {
3228             for kind in UI_EXTENSIONS {
3229                 let canon_comparison_path = expected_output_path(
3230                     &self.testpaths,
3231                     self.revision,
3232                     &None,
3233                     kind,
3234                 );
3235
3236                 if let Ok(canon) = self.load_expected_output_from_path(&canon_comparison_path) {
3237                     for mode in modes {
3238                         self.prune_duplicate_output(mode.clone(), kind, &canon);
3239                     }
3240                 }
3241             }
3242         }
3243     }
3244
3245     fn create_stamp(&self) {
3246         let mut f = File::create(::stamp(&self.config, self.testpaths, self.revision)).unwrap();
3247         f.write_all(compute_stamp_hash(&self.config).as_bytes())
3248             .unwrap();
3249     }
3250 }
3251
3252 struct ProcArgs {
3253     prog: String,
3254     args: Vec<String>,
3255 }
3256
3257 pub struct ProcRes {
3258     status: ExitStatus,
3259     stdout: String,
3260     stderr: String,
3261     cmdline: String,
3262 }
3263
3264 impl ProcRes {
3265     pub fn fatal(&self, err: Option<&str>) -> ! {
3266         if let Some(e) = err {
3267             println!("\nerror: {}", e);
3268         }
3269         print!(
3270             "\
3271              status: {}\n\
3272              command: {}\n\
3273              stdout:\n\
3274              ------------------------------------------\n\
3275              {}\n\
3276              ------------------------------------------\n\
3277              stderr:\n\
3278              ------------------------------------------\n\
3279              {}\n\
3280              ------------------------------------------\n\
3281              \n",
3282             self.status, self.cmdline, self.stdout, self.stderr
3283         );
3284         panic!();
3285     }
3286 }
3287
3288 enum TargetLocation {
3289     ThisFile(PathBuf),
3290     ThisDirectory(PathBuf),
3291 }
3292
3293 #[derive(Clone, PartialEq, Eq)]
3294 enum ExpectedLine<T: AsRef<str>> {
3295     Elision,
3296     Text(T),
3297 }
3298
3299 impl<T> fmt::Debug for ExpectedLine<T>
3300 where
3301     T: AsRef<str> + fmt::Debug,
3302 {
3303     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
3304         if let &ExpectedLine::Text(ref t) = self {
3305             write!(formatter, "{:?}", t)
3306         } else {
3307             write!(formatter, "\"...\" (Elision)")
3308         }
3309     }
3310 }
3311
3312 fn normalize_mir_line(line: &str) -> String {
3313     nocomment_mir_line(line).replace(char::is_whitespace, "")
3314 }
3315
3316 fn nocomment_mir_line(line: &str) -> &str {
3317     if let Some(idx) = line.find("//") {
3318         let (l, _) = line.split_at(idx);
3319         l.trim_right()
3320     } else {
3321         line
3322     }
3323 }
3324
3325 fn read2_abbreviated(mut child: Child) -> io::Result<Output> {
3326     use read2::read2;
3327     use std::mem::replace;
3328
3329     const HEAD_LEN: usize = 160 * 1024;
3330     const TAIL_LEN: usize = 256 * 1024;
3331
3332     enum ProcOutput {
3333         Full(Vec<u8>),
3334         Abbreviated {
3335             head: Vec<u8>,
3336             skipped: usize,
3337             tail: Box<[u8]>,
3338         },
3339     }
3340
3341     impl ProcOutput {
3342         fn extend(&mut self, data: &[u8]) {
3343             let new_self = match *self {
3344                 ProcOutput::Full(ref mut bytes) => {
3345                     bytes.extend_from_slice(data);
3346                     let new_len = bytes.len();
3347                     if new_len <= HEAD_LEN + TAIL_LEN {
3348                         return;
3349                     }
3350                     let tail = bytes.split_off(new_len - TAIL_LEN).into_boxed_slice();
3351                     let head = replace(bytes, Vec::new());
3352                     let skipped = new_len - HEAD_LEN - TAIL_LEN;
3353                     ProcOutput::Abbreviated {
3354                         head,
3355                         skipped,
3356                         tail,
3357                     }
3358                 }
3359                 ProcOutput::Abbreviated {
3360                     ref mut skipped,
3361                     ref mut tail,
3362                     ..
3363                 } => {
3364                     *skipped += data.len();
3365                     if data.len() <= TAIL_LEN {
3366                         tail[..data.len()].copy_from_slice(data);
3367                         tail.rotate_left(data.len());
3368                     } else {
3369                         tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]);
3370                     }
3371                     return;
3372                 }
3373             };
3374             *self = new_self;
3375         }
3376
3377         fn into_bytes(self) -> Vec<u8> {
3378             match self {
3379                 ProcOutput::Full(bytes) => bytes,
3380                 ProcOutput::Abbreviated {
3381                     mut head,
3382                     skipped,
3383                     tail,
3384                 } => {
3385                     write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap();
3386                     head.extend_from_slice(&tail);
3387                     head
3388                 }
3389             }
3390         }
3391     }
3392
3393     let mut stdout = ProcOutput::Full(Vec::new());
3394     let mut stderr = ProcOutput::Full(Vec::new());
3395
3396     drop(child.stdin.take());
3397     read2(
3398         child.stdout.take().unwrap(),
3399         child.stderr.take().unwrap(),
3400         &mut |is_stdout, data, _| {
3401             if is_stdout { &mut stdout } else { &mut stderr }.extend(data);
3402             data.clear();
3403         },
3404     )?;
3405     let status = child.wait()?;
3406
3407     Ok(Output {
3408         status,
3409         stdout: stdout.into_bytes(),
3410         stderr: stderr.into_bytes(),
3411     })
3412 }