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