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