]> git.lizzy.rs Git - rust.git/blob - src/compiletest/runtest.rs
Add #[rustc_no_mir] to make tests pass with -Z orbit.
[rust.git] / src / compiletest / 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 errors;
15 use header::TestProps;
16 use header;
17 use procsrv;
18 use test::TestPaths;
19 use util::logv;
20
21 use std::env;
22 use std::collections::HashSet;
23 use std::fmt;
24 use std::fs::{self, File};
25 use std::io::BufReader;
26 use std::io::prelude::*;
27 use std::net::TcpStream;
28 use std::path::{Path, PathBuf, Component};
29 use std::process::{Command, Output, ExitStatus};
30
31 pub fn run(config: Config, testpaths: &TestPaths) {
32     match &*config.target {
33
34         "arm-linux-androideabi" | "aarch64-linux-android" => {
35             if !config.adb_device_status {
36                 panic!("android device not available");
37             }
38         }
39
40         _=> { }
41     }
42
43     if config.verbose {
44         // We're going to be dumping a lot of info. Start on a new line.
45         print!("\n\n");
46     }
47     debug!("running {:?}", testpaths.file.display());
48     let props = header::load_props(&testpaths.file);
49     debug!("loaded props");
50     match config.mode {
51         CompileFail => run_cfail_test(&config, &props, &testpaths),
52         ParseFail => run_cfail_test(&config, &props, &testpaths),
53         RunFail => run_rfail_test(&config, &props, &testpaths),
54         RunPass => run_rpass_test(&config, &props, &testpaths),
55         RunPassValgrind => run_valgrind_test(&config, &props, &testpaths),
56         Pretty => run_pretty_test(&config, &props, &testpaths),
57         DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testpaths),
58         DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testpaths),
59         Codegen => run_codegen_test(&config, &props, &testpaths),
60         Rustdoc => run_rustdoc_test(&config, &props, &testpaths),
61         CodegenUnits => run_codegen_units_test(&config, &props, &testpaths),
62     }
63 }
64
65 fn get_output(props: &TestProps, proc_res: &ProcRes) -> String {
66     if props.check_stdout {
67         format!("{}{}", proc_res.stdout, proc_res.stderr)
68     } else {
69         proc_res.stderr.clone()
70     }
71 }
72
73
74 fn for_each_revision<OP>(config: &Config, props: &TestProps, testpaths: &TestPaths,
75                          mut op: OP)
76     where OP: FnMut(&Config, &TestProps, &TestPaths, Option<&str>)
77 {
78     if props.revisions.is_empty() {
79         op(config, props, testpaths, None)
80     } else {
81         for revision in &props.revisions {
82             let mut revision_props = props.clone();
83             header::load_props_into(&mut revision_props,
84                                     &testpaths.file,
85                                     Some(&revision));
86             revision_props.compile_flags.extend(vec![
87                 format!("--cfg"),
88                 format!("{}", revision),
89             ]);
90             op(config, &revision_props, testpaths, Some(revision));
91         }
92     }
93 }
94
95 fn run_cfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
96     for_each_revision(config, props, testpaths, run_cfail_test_revision);
97 }
98
99 fn run_cfail_test_revision(config: &Config,
100                            props: &TestProps,
101                            testpaths: &TestPaths,
102                            revision: Option<&str>) {
103     let proc_res = compile_test(config, props, testpaths);
104
105     if proc_res.status.success() {
106         fatal_proc_rec(
107             revision,
108             &format!("{} test compiled successfully!", config.mode)[..],
109             &proc_res);
110     }
111
112     check_correct_failure_status(revision, &proc_res);
113
114     if proc_res.status.success() {
115         fatal(revision, "process did not return an error status");
116     }
117
118     let output_to_check = get_output(props, &proc_res);
119     let expected_errors = errors::load_errors(&testpaths.file, revision);
120     if !expected_errors.is_empty() {
121         if !props.error_patterns.is_empty() {
122             fatal(revision, "both error pattern and expected errors specified");
123         }
124         check_expected_errors(revision, expected_errors, testpaths, &proc_res);
125     } else {
126         check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
127     }
128     check_no_compiler_crash(revision, &proc_res);
129     check_forbid_output(revision, props, &output_to_check, &proc_res);
130 }
131
132 fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
133     for_each_revision(config, props, testpaths, run_rfail_test_revision);
134 }
135
136 fn run_rfail_test_revision(config: &Config,
137                            props: &TestProps,
138                            testpaths: &TestPaths,
139                            revision: Option<&str>) {
140     let proc_res = compile_test(config, props, testpaths);
141
142     if !proc_res.status.success() {
143         fatal_proc_rec(revision, "compilation failed!", &proc_res);
144     }
145
146     let proc_res = exec_compiled_test(config, props, testpaths);
147
148     // The value our Makefile configures valgrind to return on failure
149     const VALGRIND_ERR: i32 = 100;
150     if proc_res.status.code() == Some(VALGRIND_ERR) {
151         fatal_proc_rec(revision, "run-fail test isn't valgrind-clean!", &proc_res);
152     }
153
154     let output_to_check = get_output(props, &proc_res);
155     check_correct_failure_status(revision, &proc_res);
156     check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
157 }
158
159 fn check_correct_failure_status(revision: Option<&str>, proc_res: &ProcRes) {
160     // The value the rust runtime returns on failure
161     const RUST_ERR: i32 = 101;
162     if proc_res.status.code() != Some(RUST_ERR) {
163         fatal_proc_rec(
164             revision,
165             &format!("failure produced the wrong error: {}",
166                      proc_res.status),
167             proc_res);
168     }
169 }
170
171 fn run_rpass_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
172     for_each_revision(config, props, testpaths, run_rpass_test_revision);
173 }
174
175 fn run_rpass_test_revision(config: &Config,
176                            props: &TestProps,
177                            testpaths: &TestPaths,
178                            revision: Option<&str>) {
179     let proc_res = compile_test(config, props, testpaths);
180
181     if !proc_res.status.success() {
182         fatal_proc_rec(revision, "compilation failed!", &proc_res);
183     }
184
185     let proc_res = exec_compiled_test(config, props, testpaths);
186
187     if !proc_res.status.success() {
188         fatal_proc_rec(revision, "test run failed!", &proc_res);
189     }
190 }
191
192 fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
193     assert!(props.revisions.is_empty(), "revisions not relevant here");
194
195     if config.valgrind_path.is_none() {
196         assert!(!config.force_valgrind);
197         return run_rpass_test(config, props, testpaths);
198     }
199
200     let mut proc_res = compile_test(config, props, testpaths);
201
202     if !proc_res.status.success() {
203         fatal_proc_rec(None, "compilation failed!", &proc_res);
204     }
205
206     let mut new_config = config.clone();
207     new_config.runtool = new_config.valgrind_path.clone();
208     proc_res = exec_compiled_test(&new_config, props, testpaths);
209
210     if !proc_res.status.success() {
211         fatal_proc_rec(None, "test run failed!", &proc_res);
212     }
213 }
214
215 fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
216     for_each_revision(config, props, testpaths, run_pretty_test_revision);
217 }
218
219 fn run_pretty_test_revision(config: &Config,
220                             props: &TestProps,
221                             testpaths: &TestPaths,
222                             revision: Option<&str>) {
223     if props.pp_exact.is_some() {
224         logv(config, "testing for exact pretty-printing".to_owned());
225     } else {
226         logv(config, "testing for converging pretty-printing".to_owned());
227     }
228
229     let rounds =
230         match props.pp_exact { Some(_) => 1, None => 2 };
231
232     let mut src = String::new();
233     File::open(&testpaths.file).unwrap().read_to_string(&mut src).unwrap();
234     let mut srcs = vec!(src);
235
236     let mut round = 0;
237     while round < rounds {
238         logv(config, format!("pretty-printing round {} revision {:?}",
239                              round, revision));
240         let proc_res = print_source(config,
241                                     props,
242                                     testpaths,
243                                     srcs[round].to_owned(),
244                                     &props.pretty_mode);
245
246         if !proc_res.status.success() {
247             fatal_proc_rec(revision,
248                            &format!("pretty-printing failed in round {} revision {:?}",
249                                     round, revision),
250                            &proc_res);
251         }
252
253         let ProcRes{ stdout, .. } = proc_res;
254         srcs.push(stdout);
255         round += 1;
256     }
257
258     let mut expected = match props.pp_exact {
259         Some(ref file) => {
260             let filepath = testpaths.file.parent().unwrap().join(file);
261             let mut s = String::new();
262             File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
263             s
264         }
265         None => { srcs[srcs.len() - 2].clone() }
266     };
267     let mut actual = srcs[srcs.len() - 1].clone();
268
269     if props.pp_exact.is_some() {
270         // Now we have to care about line endings
271         let cr = "\r".to_owned();
272         actual = actual.replace(&cr, "").to_owned();
273         expected = expected.replace(&cr, "").to_owned();
274     }
275
276     compare_source(revision, &expected, &actual);
277
278     // If we're only making sure that the output matches then just stop here
279     if props.pretty_compare_only { return; }
280
281     // Finally, let's make sure it actually appears to remain valid code
282     let proc_res = typecheck_source(config, props, testpaths, actual);
283     if !proc_res.status.success() {
284         fatal_proc_rec(revision, "pretty-printed source does not typecheck", &proc_res);
285     }
286
287     if !props.pretty_expanded { return }
288
289     // additionally, run `--pretty expanded` and try to build it.
290     let proc_res = print_source(config, props, testpaths, srcs[round].clone(), "expanded");
291     if !proc_res.status.success() {
292         fatal_proc_rec(revision, "pretty-printing (expanded) failed", &proc_res);
293     }
294
295     let ProcRes{ stdout: expanded_src, .. } = proc_res;
296     let proc_res = typecheck_source(config, props, testpaths, expanded_src);
297     if !proc_res.status.success() {
298         fatal_proc_rec(
299             revision,
300             "pretty-printed source (expanded) does not typecheck",
301             &proc_res);
302     }
303
304     return;
305
306     fn print_source(config: &Config,
307                     props: &TestProps,
308                     testpaths: &TestPaths,
309                     src: String,
310                     pretty_type: &str) -> ProcRes {
311         let aux_dir = aux_output_dir_name(config, testpaths);
312         compose_and_run(config,
313                         testpaths,
314                         make_pp_args(config,
315                                      props,
316                                      testpaths,
317                                      pretty_type.to_owned()),
318                         props.exec_env.clone(),
319                         &config.compile_lib_path,
320                         Some(aux_dir.to_str().unwrap()),
321                         Some(src))
322     }
323
324     fn make_pp_args(config: &Config,
325                     props: &TestProps,
326                     testpaths: &TestPaths,
327                     pretty_type: String) -> ProcArgs {
328         let aux_dir = aux_output_dir_name(config, testpaths);
329         // FIXME (#9639): This needs to handle non-utf8 paths
330         let mut args = vec!("-".to_owned(),
331                             "-Zunstable-options".to_owned(),
332                             "--unpretty".to_owned(),
333                             pretty_type,
334                             format!("--target={}", config.target),
335                             "-L".to_owned(),
336                             aux_dir.to_str().unwrap().to_owned());
337         args.extend(split_maybe_args(&config.target_rustcflags));
338         args.extend(props.compile_flags.iter().cloned());
339         return ProcArgs {
340             prog: config.rustc_path.to_str().unwrap().to_owned(),
341             args: args,
342         };
343     }
344
345     fn compare_source(revision: Option<&str>, expected: &str, actual: &str) {
346         if expected != actual {
347             error(revision, "pretty-printed source does not match expected source");
348             println!("\n\
349 expected:\n\
350 ------------------------------------------\n\
351 {}\n\
352 ------------------------------------------\n\
353 actual:\n\
354 ------------------------------------------\n\
355 {}\n\
356 ------------------------------------------\n\
357 \n",
358                      expected, actual);
359             panic!();
360         }
361     }
362
363     fn typecheck_source(config: &Config, props: &TestProps,
364                         testpaths: &TestPaths, src: String) -> ProcRes {
365         let args = make_typecheck_args(config, props, testpaths);
366         compose_and_run_compiler(config, props, testpaths, args, Some(src))
367     }
368
369     fn make_typecheck_args(config: &Config, props: &TestProps, testpaths: &TestPaths) -> ProcArgs {
370         let aux_dir = aux_output_dir_name(config, testpaths);
371         let target = if props.force_host {
372             &*config.host
373         } else {
374             &*config.target
375         };
376         // FIXME (#9639): This needs to handle non-utf8 paths
377         let mut args = vec!("-".to_owned(),
378                             "-Zno-trans".to_owned(),
379                             format!("--target={}", target),
380                             "-L".to_owned(),
381                             config.build_base.to_str().unwrap().to_owned(),
382                             "-L".to_owned(),
383                             aux_dir.to_str().unwrap().to_owned());
384         args.extend(split_maybe_args(&config.target_rustcflags));
385         args.extend(props.compile_flags.iter().cloned());
386         // FIXME (#9639): This needs to handle non-utf8 paths
387         return ProcArgs {
388             prog: config.rustc_path.to_str().unwrap().to_owned(),
389             args: args,
390         };
391     }
392 }
393
394 fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
395     assert!(props.revisions.is_empty(), "revisions not relevant here");
396
397     let mut config = Config {
398         target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
399         host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
400         .. config.clone()
401     };
402
403     let config = &mut config;
404     let DebuggerCommands {
405         commands,
406         check_lines,
407         breakpoint_lines
408     } = parse_debugger_commands(testpaths, "gdb");
409     let mut cmds = commands.join("\n");
410
411     // compile test file (it should have 'compile-flags:-g' in the header)
412     let compiler_run_result = compile_test(config, props, testpaths);
413     if !compiler_run_result.status.success() {
414         fatal_proc_rec(None, "compilation failed!", &compiler_run_result);
415     }
416
417     let exe_file = make_exe_name(config, testpaths);
418
419     let debugger_run_result;
420     match &*config.target {
421         "arm-linux-androideabi" | "aarch64-linux-android" => {
422
423             cmds = cmds.replace("run", "continue");
424
425             // write debugger script
426             let mut script_str = String::with_capacity(2048);
427             script_str.push_str(&format!("set charset {}\n", charset()));
428             script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
429             script_str.push_str("target remote :5039\n");
430             script_str.push_str(&format!("set solib-search-path \
431                                          ./{}/stage2/lib/rustlib/{}/lib/\n",
432                                          config.host, config.target));
433             for line in &breakpoint_lines {
434                 script_str.push_str(&format!("break {:?}:{}\n",
435                                              testpaths.file
436                                                       .file_name()
437                                                       .unwrap()
438                                                       .to_string_lossy(),
439                                              *line)[..]);
440             }
441             script_str.push_str(&cmds);
442             script_str.push_str("\nquit\n");
443
444             debug!("script_str = {}", script_str);
445             dump_output_file(config,
446                              testpaths,
447                              &script_str,
448                              "debugger.script");
449
450
451             procsrv::run("",
452                          &config.adb_path,
453                          None,
454                          &[
455                             "push".to_owned(),
456                             exe_file.to_str().unwrap().to_owned(),
457                             config.adb_test_dir.clone()
458                          ],
459                          vec!(("".to_owned(), "".to_owned())),
460                          Some("".to_owned()))
461                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
462
463             procsrv::run("",
464                          &config.adb_path,
465                          None,
466                          &[
467                             "forward".to_owned(),
468                             "tcp:5039".to_owned(),
469                             "tcp:5039".to_owned()
470                          ],
471                          vec!(("".to_owned(), "".to_owned())),
472                          Some("".to_owned()))
473                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
474
475             let adb_arg = format!("export LD_LIBRARY_PATH={}; \
476                                    gdbserver{} :5039 {}/{}",
477                                   config.adb_test_dir.clone(),
478                                   if config.target.contains("aarch64")
479                                   {"64"} else {""},
480                                   config.adb_test_dir.clone(),
481                                   exe_file.file_name().unwrap().to_str()
482                                           .unwrap());
483
484             let mut process = procsrv::run_background("",
485                                                       &config.adb_path
486                                                             ,
487                                                       None,
488                                                       &[
489                                                         "shell".to_owned(),
490                                                         adb_arg.clone()
491                                                       ],
492                                                       vec!(("".to_owned(),
493                                                             "".to_owned())),
494                                                       Some("".to_owned()))
495                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
496             loop {
497                 //waiting 1 second for gdbserver start
498                 ::std::thread::sleep(::std::time::Duration::new(1,0));
499                 if TcpStream::connect("127.0.0.1:5039").is_ok() {
500                     break
501                 }
502             }
503
504             let tool_path = match config.android_cross_path.to_str() {
505                 Some(x) => x.to_owned(),
506                 None => fatal(None, "cannot find android cross path")
507             };
508
509             let debugger_script = make_out_name(config, testpaths, "debugger.script");
510             // FIXME (#9639): This needs to handle non-utf8 paths
511             let debugger_opts =
512                 vec!("-quiet".to_owned(),
513                      "-batch".to_owned(),
514                      "-nx".to_owned(),
515                      format!("-command={}", debugger_script.to_str().unwrap()));
516
517             let mut gdb_path = tool_path;
518             gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
519             let procsrv::Result {
520                 out,
521                 err,
522                 status
523             } = procsrv::run("",
524                              &gdb_path,
525                              None,
526                              &debugger_opts,
527                              vec!(("".to_owned(), "".to_owned())),
528                              None)
529                 .expect(&format!("failed to exec `{:?}`", gdb_path));
530             let cmdline = {
531                 let cmdline = make_cmdline("",
532                                            &format!("{}-gdb", config.target),
533                                            &debugger_opts);
534                 logv(config, format!("executing {}", cmdline));
535                 cmdline
536             };
537
538             debugger_run_result = ProcRes {
539                 status: Status::Normal(status),
540                 stdout: out,
541                 stderr: err,
542                 cmdline: cmdline
543             };
544             if process.kill().is_err() {
545                 println!("Adb process is already finished.");
546             }
547         }
548
549         _=> {
550             let rust_src_root = find_rust_src_root(config)
551                 .expect("Could not find Rust source root");
552             let rust_pp_module_rel_path = Path::new("./src/etc");
553             let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
554                                                        .to_str()
555                                                        .unwrap()
556                                                        .to_owned();
557             // write debugger script
558             let mut script_str = String::with_capacity(2048);
559             script_str.push_str(&format!("set charset {}\n", charset()));
560             script_str.push_str("show version\n");
561
562             match config.gdb_version {
563                 Some(ref version) => {
564                     println!("NOTE: compiletest thinks it is using GDB version {}",
565                              version);
566
567                     if header::gdb_version_to_int(version) >
568                         header::gdb_version_to_int("7.4") {
569                         // Add the directory containing the pretty printers to
570                         // GDB's script auto loading safe path
571                         script_str.push_str(
572                             &format!("add-auto-load-safe-path {}\n",
573                                      rust_pp_module_abs_path.replace(r"\", r"\\"))
574                                 );
575                     }
576                 }
577                 _ => {
578                     println!("NOTE: compiletest does not know which version of \
579                               GDB it is using");
580                 }
581             }
582
583             // The following line actually doesn't have to do anything with
584             // pretty printing, it just tells GDB to print values on one line:
585             script_str.push_str("set print pretty off\n");
586
587             // Add the pretty printer directory to GDB's source-file search path
588             script_str.push_str(&format!("directory {}\n",
589                                          rust_pp_module_abs_path));
590
591             // Load the target executable
592             script_str.push_str(&format!("file {}\n",
593                                          exe_file.to_str().unwrap()
594                                                  .replace(r"\", r"\\")));
595
596             // Add line breakpoints
597             for line in &breakpoint_lines {
598                 script_str.push_str(&format!("break '{}':{}\n",
599                                              testpaths.file.file_name().unwrap()
600                                                      .to_string_lossy(),
601                                              *line));
602             }
603
604             script_str.push_str(&cmds);
605             script_str.push_str("\nquit\n");
606
607             debug!("script_str = {}", script_str);
608             dump_output_file(config,
609                              testpaths,
610                              &script_str,
611                              "debugger.script");
612
613             // run debugger script with gdb
614             fn debugger() -> &'static str {
615                 if cfg!(windows) {"gdb.exe"} else {"gdb"}
616             }
617
618             let debugger_script = make_out_name(config, testpaths, "debugger.script");
619
620             // FIXME (#9639): This needs to handle non-utf8 paths
621             let debugger_opts =
622                 vec!("-quiet".to_owned(),
623                      "-batch".to_owned(),
624                      "-nx".to_owned(),
625                      format!("-command={}", debugger_script.to_str().unwrap()));
626
627             let proc_args = ProcArgs {
628                 prog: debugger().to_owned(),
629                 args: debugger_opts,
630             };
631
632             let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)];
633
634             debugger_run_result = compose_and_run(config,
635                                                   testpaths,
636                                                   proc_args,
637                                                   environment,
638                                                   &config.run_lib_path,
639                                                   None,
640                                                   None);
641         }
642     }
643
644     if !debugger_run_result.status.success() {
645         fatal(None, "gdb failed to execute");
646     }
647
648     check_debugger_output(&debugger_run_result, &check_lines);
649 }
650
651 fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
652     let mut path = config.src_base.clone();
653     let path_postfix = Path::new("src/etc/lldb_batchmode.py");
654
655     while path.pop() {
656         if path.join(&path_postfix).is_file() {
657             return Some(path);
658         }
659     }
660
661     return None;
662 }
663
664 fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
665     assert!(props.revisions.is_empty(), "revisions not relevant here");
666
667     if config.lldb_python_dir.is_none() {
668         fatal(None, "Can't run LLDB test because LLDB's python path is not set.");
669     }
670
671     let mut config = Config {
672         target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
673         host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
674         .. config.clone()
675     };
676
677     let config = &mut config;
678
679     // compile test file (it should have 'compile-flags:-g' in the header)
680     let compile_result = compile_test(config, props, testpaths);
681     if !compile_result.status.success() {
682         fatal_proc_rec(None, "compilation failed!", &compile_result);
683     }
684
685     let exe_file = make_exe_name(config, testpaths);
686
687     match config.lldb_version {
688         Some(ref version) => {
689             println!("NOTE: compiletest thinks it is using LLDB version {}",
690                      version);
691         }
692         _ => {
693             println!("NOTE: compiletest does not know which version of \
694                       LLDB it is using");
695         }
696     }
697
698     // Parse debugger commands etc from test files
699     let DebuggerCommands {
700         commands,
701         check_lines,
702         breakpoint_lines,
703         ..
704     } = parse_debugger_commands(testpaths, "lldb");
705
706     // Write debugger script:
707     // We don't want to hang when calling `quit` while the process is still running
708     let mut script_str = String::from("settings set auto-confirm true\n");
709
710     // Make LLDB emit its version, so we have it documented in the test output
711     script_str.push_str("version\n");
712
713     // Switch LLDB into "Rust mode"
714     let rust_src_root = find_rust_src_root(config)
715         .expect("Could not find Rust source root");
716     let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
717     let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
718                                                .to_str()
719                                                .unwrap()
720                                                .to_owned();
721
722     script_str.push_str(&format!("command script import {}\n",
723                                  &rust_pp_module_abs_path[..])[..]);
724     script_str.push_str("type summary add --no-value ");
725     script_str.push_str("--python-function lldb_rust_formatters.print_val ");
726     script_str.push_str("-x \".*\" --category Rust\n");
727     script_str.push_str("type category enable Rust\n");
728
729     // Set breakpoints on every line that contains the string "#break"
730     for line in &breakpoint_lines {
731         script_str.push_str(&format!("breakpoint set --line {}\n", line));
732     }
733
734     // Append the other commands
735     for line in &commands {
736         script_str.push_str(line);
737         script_str.push_str("\n");
738     }
739
740     // Finally, quit the debugger
741     script_str.push_str("\nquit\n");
742
743     // Write the script into a file
744     debug!("script_str = {}", script_str);
745     dump_output_file(config,
746                      testpaths,
747                      &script_str,
748                      "debugger.script");
749     let debugger_script = make_out_name(config, testpaths, "debugger.script");
750
751     // Let LLDB execute the script via lldb_batchmode.py
752     let debugger_run_result = run_lldb(config,
753                                        testpaths,
754                                        &exe_file,
755                                        &debugger_script,
756                                        &rust_src_root);
757
758     if !debugger_run_result.status.success() {
759         fatal_proc_rec(None, "Error while running LLDB", &debugger_run_result);
760     }
761
762     check_debugger_output(&debugger_run_result, &check_lines);
763
764     fn run_lldb(config: &Config,
765                 testpaths: &TestPaths,
766                 test_executable: &Path,
767                 debugger_script: &Path,
768                 rust_src_root: &Path)
769                 -> ProcRes {
770         // Prepare the lldb_batchmode which executes the debugger script
771         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
772         cmd2procres(config,
773                     testpaths,
774                     Command::new(&config.python)
775                             .arg(&lldb_script_path)
776                             .arg(test_executable)
777                             .arg(debugger_script)
778                             .env("PYTHONPATH",
779                                  config.lldb_python_dir.as_ref().unwrap()))
780     }
781 }
782
783 fn cmd2procres(config: &Config, testpaths: &TestPaths, cmd: &mut Command)
784               -> ProcRes {
785     let (status, out, err) = match cmd.output() {
786         Ok(Output { status, stdout, stderr }) => {
787             (status,
788              String::from_utf8(stdout).unwrap(),
789              String::from_utf8(stderr).unwrap())
790         },
791         Err(e) => {
792             fatal(None, &format!("Failed to setup Python process for \
793                             LLDB script: {}", e))
794         }
795     };
796
797     dump_output(config, testpaths, &out, &err);
798     ProcRes {
799         status: Status::Normal(status),
800         stdout: out,
801         stderr: err,
802         cmdline: format!("{:?}", cmd)
803     }
804 }
805
806 struct DebuggerCommands {
807     commands: Vec<String>,
808     check_lines: Vec<String>,
809     breakpoint_lines: Vec<usize>,
810 }
811
812 fn parse_debugger_commands(testpaths: &TestPaths, debugger_prefix: &str)
813                            -> DebuggerCommands {
814     let command_directive = format!("{}-command", debugger_prefix);
815     let check_directive = format!("{}-check", debugger_prefix);
816
817     let mut breakpoint_lines = vec!();
818     let mut commands = vec!();
819     let mut check_lines = vec!();
820     let mut counter = 1;
821     let reader = BufReader::new(File::open(&testpaths.file).unwrap());
822     for line in reader.lines() {
823         match line {
824             Ok(line) => {
825                 if line.contains("#break") {
826                     breakpoint_lines.push(counter);
827                 }
828
829                 header::parse_name_value_directive(
830                         &line,
831                         &command_directive).map(|cmd| {
832                     commands.push(cmd)
833                 });
834
835                 header::parse_name_value_directive(
836                         &line,
837                         &check_directive).map(|cmd| {
838                     check_lines.push(cmd)
839                 });
840             }
841             Err(e) => {
842                 fatal(None, &format!("Error while parsing debugger commands: {}", e))
843             }
844         }
845         counter += 1;
846     }
847
848     DebuggerCommands {
849         commands: commands,
850         check_lines: check_lines,
851         breakpoint_lines: breakpoint_lines,
852     }
853 }
854
855 fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
856     if options.is_none() {
857         return None;
858     }
859
860     // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
861     let options_to_remove = [
862         "-O".to_owned(),
863         "-g".to_owned(),
864         "--debuginfo".to_owned()
865     ];
866     let mut new_options =
867         split_maybe_args(options).into_iter()
868                                  .filter(|x| !options_to_remove.contains(x))
869                                  .collect::<Vec<String>>();
870
871     let mut i = 0;
872     while i + 1 < new_options.len() {
873         if new_options[i] == "-Z" {
874             // FIXME #31005 MIR missing debuginfo currently.
875             if new_options[i + 1] == "orbit" {
876                 // Remove "-Z" and "orbit".
877                 new_options.remove(i);
878                 new_options.remove(i);
879                 continue;
880             }
881             // Always skip over -Z's argument.
882             i += 1;
883         }
884         i += 1;
885     }
886
887     Some(new_options.join(" "))
888 }
889
890 fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) {
891     let num_check_lines = check_lines.len();
892     if num_check_lines > 0 {
893         // Allow check lines to leave parts unspecified (e.g., uninitialized
894         // bits in the wrong case of an enum) with the notation "[...]".
895         let check_fragments: Vec<Vec<String>> =
896             check_lines.iter().map(|s| {
897                 s
898                  .trim()
899                  .split("[...]")
900                  .map(str::to_owned)
901                  .collect()
902             }).collect();
903         // check if each line in props.check_lines appears in the
904         // output (in order)
905         let mut i = 0;
906         for line in debugger_run_result.stdout.lines() {
907             let mut rest = line.trim();
908             let mut first = true;
909             let mut failed = false;
910             for frag in &check_fragments[i] {
911                 let found = if first {
912                     if rest.starts_with(frag) {
913                         Some(0)
914                     } else {
915                         None
916                     }
917                 } else {
918                     rest.find(frag)
919                 };
920                 match found {
921                     None => {
922                         failed = true;
923                         break;
924                     }
925                     Some(i) => {
926                         rest = &rest[(i + frag.len())..];
927                     }
928                 }
929                 first = false;
930             }
931             if !failed && rest.is_empty() {
932                 i += 1;
933             }
934             if i == num_check_lines {
935                 // all lines checked
936                 break;
937             }
938         }
939         if i != num_check_lines {
940             fatal_proc_rec(None, &format!("line not found in debugger output: {}",
941                                     check_lines.get(i).unwrap()),
942                           debugger_run_result);
943         }
944     }
945 }
946
947 fn check_error_patterns(revision: Option<&str>,
948                         props: &TestProps,
949                         testpaths: &TestPaths,
950                         output_to_check: &str,
951                         proc_res: &ProcRes) {
952     if props.error_patterns.is_empty() {
953         fatal(revision,
954               &format!("no error pattern specified in {:?}",
955                        testpaths.file.display()));
956     }
957     let mut next_err_idx = 0;
958     let mut next_err_pat = &props.error_patterns[next_err_idx];
959     let mut done = false;
960     for line in output_to_check.lines() {
961         if line.contains(next_err_pat) {
962             debug!("found error pattern {}", next_err_pat);
963             next_err_idx += 1;
964             if next_err_idx == props.error_patterns.len() {
965                 debug!("found all error patterns");
966                 done = true;
967                 break;
968             }
969             next_err_pat = &props.error_patterns[next_err_idx];
970         }
971     }
972     if done { return; }
973
974     let missing_patterns = &props.error_patterns[next_err_idx..];
975     if missing_patterns.len() == 1 {
976         fatal_proc_rec(
977             revision,
978             &format!("error pattern '{}' not found!", missing_patterns[0]),
979             proc_res);
980     } else {
981         for pattern in missing_patterns {
982             error(revision, &format!("error pattern '{}' not found!", *pattern));
983         }
984         fatal_proc_rec(revision, "multiple error patterns not found", proc_res);
985     }
986 }
987
988 fn check_no_compiler_crash(revision: Option<&str>, proc_res: &ProcRes) {
989     for line in proc_res.stderr.lines() {
990         if line.starts_with("error: internal compiler error:") {
991             fatal_proc_rec(revision,
992                            "compiler encountered internal error",
993                            proc_res);
994         }
995     }
996 }
997
998 fn check_forbid_output(revision: Option<&str>,
999                        props: &TestProps,
1000                        output_to_check: &str,
1001                        proc_res: &ProcRes) {
1002     for pat in &props.forbid_output {
1003         if output_to_check.contains(pat) {
1004             fatal_proc_rec(revision,
1005                            "forbidden pattern found in compiler output",
1006                            proc_res);
1007         }
1008     }
1009 }
1010
1011 fn check_expected_errors(revision: Option<&str>,
1012                          expected_errors: Vec<errors::ExpectedError>,
1013                          testpaths: &TestPaths,
1014                          proc_res: &ProcRes) {
1015     // true if we found the error in question
1016     let mut found_flags = vec![false; expected_errors.len()];
1017
1018     if proc_res.status.success() {
1019         fatal_proc_rec(revision, "process did not return an error status", proc_res);
1020     }
1021
1022     let prefixes = expected_errors.iter().map(|ee| {
1023         let expected = format!("{}:{}:", testpaths.file.display(), ee.line_num);
1024         // On windows just translate all '\' path separators to '/'
1025         expected.replace(r"\", "/")
1026     }).collect::<Vec<String>>();
1027
1028     let (expect_help, expect_note) =
1029         expected_errors.iter()
1030                         .fold((false, false),
1031                               |(acc_help, acc_note), ee|
1032                                   (acc_help || ee.kind == "help:", acc_note ||
1033                                    ee.kind == "note:"));
1034
1035     // Scan and extract our error/warning messages,
1036     // which look like:
1037     //    filename:line1:col1: line2:col2: *error:* msg
1038     //    filename:line1:col1: line2:col2: *warning:* msg
1039     // where line1:col1: is the starting point, line2:col2:
1040     // is the ending point, and * represents ANSI color codes.
1041     //
1042     // This pattern is ambiguous on windows, because filename may contain
1043     // a colon, so any path prefix must be detected and removed first.
1044     let mut unexpected = 0;
1045     let mut not_found = 0;
1046     for line in proc_res.stderr.lines() {
1047         let mut was_expected = false;
1048         let mut prev = 0;
1049         for (i, ee) in expected_errors.iter().enumerate() {
1050             if !found_flags[i] {
1051                 debug!("prefix={} ee.kind={} ee.msg={} line={}",
1052                        prefixes[i],
1053                        ee.kind,
1054                        ee.msg,
1055                        line);
1056                 // Suggestions have no line number in their output, so take on the line number of
1057                 // the previous expected error
1058                 if ee.kind == "suggestion" {
1059                     assert!(expected_errors[prev].kind == "help",
1060                             "SUGGESTIONs must be preceded by a HELP");
1061                     if line.contains(&ee.msg) {
1062                         found_flags[i] = true;
1063                         was_expected = true;
1064                         break;
1065                     }
1066                 }
1067                 if
1068                     (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
1069                     line.contains(&ee.kind) &&
1070                     line.contains(&ee.msg)
1071                 {
1072                     found_flags[i] = true;
1073                     was_expected = true;
1074                     break;
1075                 }
1076             }
1077             prev = i;
1078         }
1079
1080         // ignore this msg which gets printed at the end
1081         if line.contains("aborting due to") {
1082             was_expected = true;
1083         }
1084
1085         if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) {
1086             error(revision, &format!("unexpected compiler message: '{}'", line));
1087             unexpected += 1;
1088         }
1089     }
1090
1091     for (i, &flag) in found_flags.iter().enumerate() {
1092         if !flag {
1093             let ee = &expected_errors[i];
1094             error(revision, &format!("expected {} on line {} not found: {}",
1095                                      ee.kind, ee.line_num, ee.msg));
1096             not_found += 1;
1097         }
1098     }
1099
1100     if unexpected > 0 || not_found > 0 {
1101         fatal_proc_rec(
1102             revision,
1103             &format!("{} unexpected errors found, {} expected errors not found",
1104                      unexpected, not_found),
1105             proc_res);
1106     }
1107
1108     fn prefix_matches(line: &str, prefix: &str) -> bool {
1109         use std::ascii::AsciiExt;
1110         // On windows just translate all '\' path separators to '/'
1111         let line = line.replace(r"\", "/");
1112         if cfg!(windows) {
1113             line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
1114         } else {
1115             line.starts_with(prefix)
1116         }
1117     }
1118
1119     // A multi-line error will have followup lines which start with a space
1120     // or open paren.
1121     fn continuation( line: &str) -> bool {
1122         line.starts_with(" ") || line.starts_with("(")
1123     }
1124 }
1125
1126 fn is_unexpected_compiler_message(line: &str, expect_help: bool, expect_note: bool) -> bool {
1127     let mut c = Path::new(line).components();
1128     let line = match c.next() {
1129         Some(Component::Prefix(_)) => c.as_path().to_str().unwrap(),
1130         _ => line,
1131     };
1132
1133     let mut i = 0;
1134     return scan_until_char(line, ':', &mut i) &&
1135         scan_char(line, ':', &mut i) &&
1136         scan_integer(line, &mut i) &&
1137         scan_char(line, ':', &mut i) &&
1138         scan_integer(line, &mut i) &&
1139         scan_char(line, ':', &mut i) &&
1140         scan_char(line, ' ', &mut i) &&
1141         scan_integer(line, &mut i) &&
1142         scan_char(line, ':', &mut i) &&
1143         scan_integer(line, &mut i) &&
1144         scan_char(line, ' ', &mut i) &&
1145         (scan_string(line, "error", &mut i) ||
1146          scan_string(line, "warning", &mut i) ||
1147          (expect_help && scan_string(line, "help", &mut i)) ||
1148          (expect_note && scan_string(line, "note", &mut i))
1149         );
1150 }
1151
1152 fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1153     if *idx >= haystack.len() {
1154         return false;
1155     }
1156     let opt = haystack[(*idx)..].find(needle);
1157     if opt.is_none() {
1158         return false;
1159     }
1160     *idx = opt.unwrap();
1161     return true;
1162 }
1163
1164 fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1165     if *idx >= haystack.len() {
1166         return false;
1167     }
1168     let ch = haystack.char_at(*idx);
1169     if ch != needle {
1170         return false;
1171     }
1172     *idx += ch.len_utf8();
1173     return true;
1174 }
1175
1176 fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
1177     let mut i = *idx;
1178     while i < haystack.len() {
1179         let ch = haystack.char_at(i);
1180         if ch < '0' || '9' < ch {
1181             break;
1182         }
1183         i += ch.len_utf8();
1184     }
1185     if i == *idx {
1186         return false;
1187     }
1188     *idx = i;
1189     return true;
1190 }
1191
1192 fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool {
1193     let mut haystack_i = *idx;
1194     let mut needle_i = 0;
1195     while needle_i < needle.len() {
1196         if haystack_i >= haystack.len() {
1197             return false;
1198         }
1199         let ch = haystack.char_at(haystack_i);
1200         haystack_i += ch.len_utf8();
1201         if !scan_char(needle, ch, &mut needle_i) {
1202             return false;
1203         }
1204     }
1205     *idx = haystack_i;
1206     return true;
1207 }
1208
1209 struct ProcArgs {
1210     prog: String,
1211     args: Vec<String>,
1212 }
1213
1214 struct ProcRes {
1215     status: Status,
1216     stdout: String,
1217     stderr: String,
1218     cmdline: String,
1219 }
1220
1221 enum Status {
1222     Parsed(i32),
1223     Normal(ExitStatus),
1224 }
1225
1226 impl Status {
1227     fn code(&self) -> Option<i32> {
1228         match *self {
1229             Status::Parsed(i) => Some(i),
1230             Status::Normal(ref e) => e.code(),
1231         }
1232     }
1233
1234     fn success(&self) -> bool {
1235         match *self {
1236             Status::Parsed(i) => i == 0,
1237             Status::Normal(ref e) => e.success(),
1238         }
1239     }
1240 }
1241
1242 impl fmt::Display for Status {
1243     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1244         match *self {
1245             Status::Parsed(i) => write!(f, "exit code: {}", i),
1246             Status::Normal(ref e) => e.fmt(f),
1247         }
1248     }
1249 }
1250
1251 fn compile_test(config: &Config, props: &TestProps,
1252                 testpaths: &TestPaths) -> ProcRes {
1253     let aux_dir = aux_output_dir_name(config, testpaths);
1254     // FIXME (#9639): This needs to handle non-utf8 paths
1255     let link_args = vec!("-L".to_owned(),
1256                          aux_dir.to_str().unwrap().to_owned());
1257     let args = make_compile_args(config,
1258                                  props,
1259                                  link_args,
1260                                  |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testpaths);
1261     compose_and_run_compiler(config, props, testpaths, args, None)
1262 }
1263
1264 fn document(config: &Config,
1265             props: &TestProps,
1266             testpaths: &TestPaths,
1267             out_dir: &Path)
1268             -> ProcRes {
1269     if props.build_aux_docs {
1270         for rel_ab in &props.aux_builds {
1271             let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1272             let aux_props = header::load_props(&aux_testpaths.file);
1273             let auxres = document(config, &aux_props, &aux_testpaths, out_dir);
1274             if !auxres.status.success() {
1275                 return auxres;
1276             }
1277         }
1278     }
1279
1280     let aux_dir = aux_output_dir_name(config, testpaths);
1281     let mut args = vec!["-L".to_owned(),
1282                         aux_dir.to_str().unwrap().to_owned(),
1283                         "-o".to_owned(),
1284                         out_dir.to_str().unwrap().to_owned(),
1285                         testpaths.file.to_str().unwrap().to_owned()];
1286     args.extend(props.compile_flags.iter().cloned());
1287     let args = ProcArgs {
1288         prog: config.rustdoc_path.to_str().unwrap().to_owned(),
1289         args: args,
1290     };
1291     compose_and_run_compiler(config, props, testpaths, args, None)
1292 }
1293
1294 fn exec_compiled_test(config: &Config, props: &TestProps,
1295                       testpaths: &TestPaths) -> ProcRes {
1296
1297     let env = props.exec_env.clone();
1298
1299     match &*config.target {
1300
1301         "arm-linux-androideabi" | "aarch64-linux-android" => {
1302             _arm_exec_compiled_test(config, props, testpaths, env)
1303         }
1304
1305         _=> {
1306             let aux_dir = aux_output_dir_name(config, testpaths);
1307             compose_and_run(config,
1308                             testpaths,
1309                             make_run_args(config, props, testpaths),
1310                             env,
1311                             &config.run_lib_path,
1312                             Some(aux_dir.to_str().unwrap()),
1313                             None)
1314         }
1315     }
1316 }
1317
1318 fn compute_aux_test_paths(config: &Config,
1319                           testpaths: &TestPaths,
1320                           rel_ab: &str)
1321                           -> TestPaths
1322 {
1323     let abs_ab = config.aux_base.join(rel_ab);
1324     TestPaths {
1325         file: abs_ab,
1326         base: testpaths.base.clone(),
1327         relative_dir: Path::new(rel_ab).parent()
1328                                        .map(|p| p.to_path_buf())
1329                                        .unwrap_or_else(|| PathBuf::new())
1330     }
1331 }
1332
1333 fn compose_and_run_compiler(config: &Config, props: &TestProps,
1334                             testpaths: &TestPaths, args: ProcArgs,
1335                             input: Option<String>) -> ProcRes {
1336     if !props.aux_builds.is_empty() {
1337         ensure_dir(&aux_output_dir_name(config, testpaths));
1338     }
1339
1340     let aux_dir = aux_output_dir_name(config, testpaths);
1341     // FIXME (#9639): This needs to handle non-utf8 paths
1342     let extra_link_args = vec!["-L".to_owned(),
1343                                aux_dir.to_str().unwrap().to_owned()];
1344
1345     for rel_ab in &props.aux_builds {
1346         let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1347         let aux_props = header::load_props(&aux_testpaths.file);
1348         let mut crate_type = if aux_props.no_prefer_dynamic {
1349             Vec::new()
1350         } else {
1351             // We primarily compile all auxiliary libraries as dynamic libraries
1352             // to avoid code size bloat and large binaries as much as possible
1353             // for the test suite (otherwise including libstd statically in all
1354             // executables takes up quite a bit of space).
1355             //
1356             // For targets like MUSL or Emscripten, however, there is no support for
1357             // dynamic libraries so we just go back to building a normal library. Note,
1358             // however, that for MUSL if the library is built with `force_host` then
1359             // it's ok to be a dylib as the host should always support dylibs.
1360             if (config.target.contains("musl") && !aux_props.force_host) ||
1361                 config.target.contains("emscripten")
1362             {
1363                 vec!("--crate-type=lib".to_owned())
1364             } else {
1365                 vec!("--crate-type=dylib".to_owned())
1366             }
1367         };
1368         crate_type.extend(extra_link_args.clone());
1369         let aux_args =
1370             make_compile_args(config,
1371                               &aux_props,
1372                               crate_type,
1373                               |a,b| {
1374                                   let f = make_lib_name(a, &b.file, testpaths);
1375                                   let parent = f.parent().unwrap();
1376                                   TargetLocation::ThisDirectory(parent.to_path_buf())
1377                               },
1378                               &aux_testpaths);
1379         let auxres = compose_and_run(config,
1380                                      &aux_testpaths,
1381                                      aux_args,
1382                                      Vec::new(),
1383                                      &config.compile_lib_path,
1384                                      Some(aux_dir.to_str().unwrap()),
1385                                      None);
1386         if !auxres.status.success() {
1387             fatal_proc_rec(
1388                 None,
1389                 &format!("auxiliary build of {:?} failed to compile: ",
1390                         aux_testpaths.file.display()),
1391                 &auxres);
1392         }
1393
1394         match &*config.target {
1395             "arm-linux-androideabi"  | "aarch64-linux-android" => {
1396                 _arm_push_aux_shared_library(config, testpaths);
1397             }
1398             _ => {}
1399         }
1400     }
1401
1402     compose_and_run(config,
1403                     testpaths,
1404                     args,
1405                     props.rustc_env.clone(),
1406                     &config.compile_lib_path,
1407                     Some(aux_dir.to_str().unwrap()),
1408                     input)
1409 }
1410
1411 fn ensure_dir(path: &Path) {
1412     if path.is_dir() { return; }
1413     fs::create_dir_all(path).unwrap();
1414 }
1415
1416 fn compose_and_run(config: &Config,
1417                    testpaths: &TestPaths,
1418                    ProcArgs{ args, prog }: ProcArgs,
1419                    procenv: Vec<(String, String)> ,
1420                    lib_path: &str,
1421                    aux_path: Option<&str>,
1422                    input: Option<String>) -> ProcRes {
1423     return program_output(config, testpaths, lib_path,
1424                           prog, aux_path, args, procenv, input);
1425 }
1426
1427 enum TargetLocation {
1428     ThisFile(PathBuf),
1429     ThisDirectory(PathBuf),
1430 }
1431
1432 fn make_compile_args<F>(config: &Config,
1433                         props: &TestProps,
1434                         extras: Vec<String> ,
1435                         xform: F,
1436                         testpaths: &TestPaths)
1437                         -> ProcArgs where
1438     F: FnOnce(&Config, &TestPaths) -> TargetLocation,
1439 {
1440     let xform_file = xform(config, testpaths);
1441     let target = if props.force_host {
1442         &*config.host
1443     } else {
1444         &*config.target
1445     };
1446     // FIXME (#9639): This needs to handle non-utf8 paths
1447     let mut args = vec!(testpaths.file.to_str().unwrap().to_owned(),
1448                         "-L".to_owned(),
1449                         config.build_base.to_str().unwrap().to_owned(),
1450                         format!("--target={}", target));
1451     args.extend_from_slice(&extras);
1452     if !props.no_prefer_dynamic {
1453         args.push("-C".to_owned());
1454         args.push("prefer-dynamic".to_owned());
1455     }
1456     let path = match xform_file {
1457         TargetLocation::ThisFile(path) => {
1458             args.push("-o".to_owned());
1459             path
1460         }
1461         TargetLocation::ThisDirectory(path) => {
1462             args.push("--out-dir".to_owned());
1463             path
1464         }
1465     };
1466     args.push(path.to_str().unwrap().to_owned());
1467     if props.force_host {
1468         args.extend(split_maybe_args(&config.host_rustcflags));
1469     } else {
1470         args.extend(split_maybe_args(&config.target_rustcflags));
1471     }
1472     args.extend(props.compile_flags.iter().cloned());
1473     return ProcArgs {
1474         prog: config.rustc_path.to_str().unwrap().to_owned(),
1475         args: args,
1476     };
1477 }
1478
1479 fn make_lib_name(config: &Config, auxfile: &Path, testpaths: &TestPaths) -> PathBuf {
1480     // what we return here is not particularly important, as it
1481     // happens; rustc ignores everything except for the directory.
1482     let auxname = output_testname(auxfile);
1483     aux_output_dir_name(config, testpaths).join(&auxname)
1484 }
1485
1486 fn make_exe_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1487     let mut f = output_base_name(config, testpaths);
1488     // FIXME: This is using the host architecture exe suffix, not target!
1489     if config.target == "asmjs-unknown-emscripten" {
1490         let mut fname = f.file_name().unwrap().to_os_string();
1491         fname.push(".js");
1492         f.set_file_name(&fname);
1493     } else if !env::consts::EXE_SUFFIX.is_empty() {
1494         let mut fname = f.file_name().unwrap().to_os_string();
1495         fname.push(env::consts::EXE_SUFFIX);
1496         f.set_file_name(&fname);
1497     }
1498     f
1499 }
1500
1501 fn make_run_args(config: &Config, props: &TestProps, testpaths: &TestPaths)
1502                  -> ProcArgs {
1503     // If we've got another tool to run under (valgrind),
1504     // then split apart its command
1505     let mut args = split_maybe_args(&config.runtool);
1506
1507     // If this is emscripten, then run tests under nodejs
1508     if config.target == "asmjs-unknown-emscripten" {
1509         args.push("nodejs".to_owned());
1510     }
1511
1512     let exe_file = make_exe_name(config, testpaths);
1513
1514     // FIXME (#9639): This needs to handle non-utf8 paths
1515     args.push(exe_file.to_str().unwrap().to_owned());
1516
1517     // Add the arguments in the run_flags directive
1518     args.extend(split_maybe_args(&props.run_flags));
1519
1520     let prog = args.remove(0);
1521     return ProcArgs {
1522         prog: prog,
1523         args: args,
1524     };
1525 }
1526
1527 fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
1528     match *argstr {
1529         Some(ref s) => {
1530             s
1531              .split(' ')
1532              .filter_map(|s| {
1533                  if s.chars().all(|c| c.is_whitespace()) {
1534                      None
1535                  } else {
1536                      Some(s.to_owned())
1537                  }
1538              }).collect()
1539         }
1540         None => Vec::new()
1541     }
1542 }
1543
1544 fn program_output(config: &Config, testpaths: &TestPaths, lib_path: &str, prog: String,
1545                   aux_path: Option<&str>, args: Vec<String>,
1546                   env: Vec<(String, String)>,
1547                   input: Option<String>) -> ProcRes {
1548     let cmdline =
1549         {
1550             let cmdline = make_cmdline(lib_path,
1551                                        &prog,
1552                                        &args);
1553             logv(config, format!("executing {}", cmdline));
1554             cmdline
1555         };
1556     let procsrv::Result {
1557         out,
1558         err,
1559         status
1560     } = procsrv::run(lib_path,
1561                      &prog,
1562                      aux_path,
1563                      &args,
1564                      env,
1565                      input).expect(&format!("failed to exec `{}`", prog));
1566     dump_output(config, testpaths, &out, &err);
1567     return ProcRes {
1568         status: Status::Normal(status),
1569         stdout: out,
1570         stderr: err,
1571         cmdline: cmdline,
1572     };
1573 }
1574
1575 fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
1576     use util;
1577
1578     // Linux and mac don't require adjusting the library search path
1579     if cfg!(unix) {
1580         format!("{} {}", prog, args.join(" "))
1581     } else {
1582         // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1583         // for diagnostic purposes
1584         fn lib_path_cmd_prefix(path: &str) -> String {
1585             format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
1586         }
1587
1588         format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
1589     }
1590 }
1591
1592 fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) {
1593     dump_output_file(config, testpaths, out, "out");
1594     dump_output_file(config, testpaths, err, "err");
1595     maybe_dump_to_stdout(config, out, err);
1596 }
1597
1598 fn dump_output_file(config: &Config,
1599                     testpaths: &TestPaths,
1600                     out: &str,
1601                     extension: &str) {
1602     let outfile = make_out_name(config, testpaths, extension);
1603     File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1604 }
1605
1606 fn make_out_name(config: &Config, testpaths: &TestPaths, extension: &str) -> PathBuf {
1607     output_base_name(config, testpaths).with_extension(extension)
1608 }
1609
1610 fn aux_output_dir_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1611     let f = output_base_name(config, testpaths);
1612     let mut fname = f.file_name().unwrap().to_os_string();
1613     fname.push(&format!(".{}.libaux", config.mode));
1614     f.with_file_name(&fname)
1615 }
1616
1617 fn output_testname(filepath: &Path) -> PathBuf {
1618     PathBuf::from(filepath.file_stem().unwrap())
1619 }
1620
1621 fn output_base_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1622     let dir = config.build_base.join(&testpaths.relative_dir);
1623
1624     // Note: The directory `dir` is created during `collect_tests_from_dir`
1625     dir
1626         .join(&output_testname(&testpaths.file))
1627         .with_extension(&config.stage_id)
1628 }
1629
1630 fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
1631     if config.verbose {
1632         println!("------{}------------------------------", "stdout");
1633         println!("{}", out);
1634         println!("------{}------------------------------", "stderr");
1635         println!("{}", err);
1636         println!("------------------------------------------");
1637     }
1638 }
1639
1640 fn error(revision: Option<&str>, err: &str) {
1641     match revision {
1642         Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1643         None => println!("\nerror: {}", err)
1644     }
1645 }
1646
1647 fn fatal(revision: Option<&str>, err: &str) -> ! {
1648     error(revision, err); panic!();
1649 }
1650
1651 fn fatal_proc_rec(revision: Option<&str>, err: &str, proc_res: &ProcRes) -> ! {
1652     error(revision, err);
1653     print!("\
1654 status: {}\n\
1655 command: {}\n\
1656 stdout:\n\
1657 ------------------------------------------\n\
1658 {}\n\
1659 ------------------------------------------\n\
1660 stderr:\n\
1661 ------------------------------------------\n\
1662 {}\n\
1663 ------------------------------------------\n\
1664 \n",
1665              proc_res.status, proc_res.cmdline, proc_res.stdout,
1666              proc_res.stderr);
1667     panic!();
1668 }
1669
1670 fn _arm_exec_compiled_test(config: &Config,
1671                            props: &TestProps,
1672                            testpaths: &TestPaths,
1673                            env: Vec<(String, String)>)
1674                            -> ProcRes {
1675     let args = make_run_args(config, props, testpaths);
1676     let cmdline = make_cmdline("",
1677                                &args.prog,
1678                                &args.args);
1679
1680     // get bare program string
1681     let mut tvec: Vec<String> = args.prog
1682                                     .split('/')
1683                                     .map(str::to_owned)
1684                                     .collect();
1685     let prog_short = tvec.pop().unwrap();
1686
1687     // copy to target
1688     let copy_result = procsrv::run("",
1689                                    &config.adb_path,
1690                                    None,
1691                                    &[
1692                                     "push".to_owned(),
1693                                     args.prog.clone(),
1694                                     config.adb_test_dir.clone()
1695                                    ],
1696                                    vec!(("".to_owned(), "".to_owned())),
1697                                    Some("".to_owned()))
1698         .expect(&format!("failed to exec `{}`", config.adb_path));
1699
1700     if config.verbose {
1701         println!("push ({}) {} {} {}",
1702                  config.target,
1703                  args.prog,
1704                  copy_result.out,
1705                  copy_result.err);
1706     }
1707
1708     logv(config, format!("executing ({}) {}", config.target, cmdline));
1709
1710     let mut runargs = Vec::new();
1711
1712     // run test via adb_run_wrapper
1713     runargs.push("shell".to_owned());
1714     for (key, val) in env {
1715         runargs.push(format!("{}={}", key, val));
1716     }
1717     runargs.push(format!("{}/../adb_run_wrapper.sh", config.adb_test_dir));
1718     runargs.push(format!("{}", config.adb_test_dir));
1719     runargs.push(format!("{}", prog_short));
1720
1721     for tv in &args.args {
1722         runargs.push(tv.to_owned());
1723     }
1724     procsrv::run("",
1725                  &config.adb_path,
1726                  None,
1727                  &runargs,
1728                  vec!(("".to_owned(), "".to_owned())), Some("".to_owned()))
1729         .expect(&format!("failed to exec `{}`", config.adb_path));
1730
1731     // get exitcode of result
1732     runargs = Vec::new();
1733     runargs.push("shell".to_owned());
1734     runargs.push("cat".to_owned());
1735     runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
1736
1737     let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
1738         procsrv::run("",
1739                      &config.adb_path,
1740                      None,
1741                      &runargs,
1742                      vec!(("".to_owned(), "".to_owned())),
1743                      Some("".to_owned()))
1744         .expect(&format!("failed to exec `{}`", config.adb_path));
1745
1746     let mut exitcode: i32 = 0;
1747     for c in exitcode_out.chars() {
1748         if !c.is_numeric() { break; }
1749         exitcode = exitcode * 10 + match c {
1750             '0' ... '9' => c as i32 - ('0' as i32),
1751             _ => 101,
1752         }
1753     }
1754
1755     // get stdout of result
1756     runargs = Vec::new();
1757     runargs.push("shell".to_owned());
1758     runargs.push("cat".to_owned());
1759     runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
1760
1761     let procsrv::Result{ out: stdout_out, err: _, status: _ } =
1762         procsrv::run("",
1763                      &config.adb_path,
1764                      None,
1765                      &runargs,
1766                      vec!(("".to_owned(), "".to_owned())),
1767                      Some("".to_owned()))
1768         .expect(&format!("failed to exec `{}`", config.adb_path));
1769
1770     // get stderr of result
1771     runargs = Vec::new();
1772     runargs.push("shell".to_owned());
1773     runargs.push("cat".to_owned());
1774     runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
1775
1776     let procsrv::Result{ out: stderr_out, err: _, status: _ } =
1777         procsrv::run("",
1778                      &config.adb_path,
1779                      None,
1780                      &runargs,
1781                      vec!(("".to_owned(), "".to_owned())),
1782                      Some("".to_owned()))
1783         .expect(&format!("failed to exec `{}`", config.adb_path));
1784
1785     dump_output(config,
1786                 testpaths,
1787                 &stdout_out,
1788                 &stderr_out);
1789
1790     ProcRes {
1791         status: Status::Parsed(exitcode),
1792         stdout: stdout_out,
1793         stderr: stderr_out,
1794         cmdline: cmdline
1795     }
1796 }
1797
1798 fn _arm_push_aux_shared_library(config: &Config, testpaths: &TestPaths) {
1799     let tdir = aux_output_dir_name(config, testpaths);
1800
1801     let dirs = fs::read_dir(&tdir).unwrap();
1802     for file in dirs {
1803         let file = file.unwrap().path();
1804         if file.extension().and_then(|s| s.to_str()) == Some("so") {
1805             // FIXME (#9639): This needs to handle non-utf8 paths
1806             let copy_result = procsrv::run("",
1807                                            &config.adb_path,
1808                                            None,
1809                                            &[
1810                                             "push".to_owned(),
1811                                             file.to_str()
1812                                                 .unwrap()
1813                                                 .to_owned(),
1814                                             config.adb_test_dir.to_owned(),
1815                                            ],
1816                                            vec!(("".to_owned(),
1817                                                  "".to_owned())),
1818                                            Some("".to_owned()))
1819                 .expect(&format!("failed to exec `{}`", config.adb_path));
1820
1821             if config.verbose {
1822                 println!("push ({}) {:?} {} {}",
1823                     config.target, file.display(),
1824                     copy_result.out, copy_result.err);
1825             }
1826         }
1827     }
1828 }
1829
1830 // codegen tests (using FileCheck)
1831
1832 fn compile_test_and_save_ir(config: &Config, props: &TestProps,
1833                                  testpaths: &TestPaths) -> ProcRes {
1834     let aux_dir = aux_output_dir_name(config, testpaths);
1835     // FIXME (#9639): This needs to handle non-utf8 paths
1836     let mut link_args = vec!("-L".to_owned(),
1837                              aux_dir.to_str().unwrap().to_owned());
1838     let llvm_args = vec!("--emit=llvm-ir".to_owned(),);
1839     link_args.extend(llvm_args);
1840     let args = make_compile_args(config,
1841                                  props,
1842                                  link_args,
1843                                  |a, b| TargetLocation::ThisDirectory(
1844                                      output_base_name(a, b).parent()
1845                                         .unwrap().to_path_buf()),
1846                                  testpaths);
1847     compose_and_run_compiler(config, props, testpaths, args, None)
1848 }
1849
1850 fn check_ir_with_filecheck(config: &Config, testpaths: &TestPaths) -> ProcRes {
1851     let irfile = output_base_name(config, testpaths).with_extension("ll");
1852     let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck");
1853     let proc_args = ProcArgs {
1854         // FIXME (#9639): This needs to handle non-utf8 paths
1855         prog: prog.to_str().unwrap().to_owned(),
1856         args: vec!(format!("-input-file={}", irfile.to_str().unwrap()),
1857                    testpaths.file.to_str().unwrap().to_owned())
1858     };
1859     compose_and_run(config, testpaths, proc_args, Vec::new(), "", None, None)
1860 }
1861
1862 fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1863     assert!(props.revisions.is_empty(), "revisions not relevant here");
1864
1865     if config.llvm_bin_path.is_none() {
1866         fatal(None, "missing --llvm-bin-path");
1867     }
1868
1869     let mut proc_res = compile_test_and_save_ir(config, props, testpaths);
1870     if !proc_res.status.success() {
1871         fatal_proc_rec(None, "compilation failed!", &proc_res);
1872     }
1873
1874     proc_res = check_ir_with_filecheck(config, testpaths);
1875     if !proc_res.status.success() {
1876         fatal_proc_rec(None,
1877                        "verification with 'FileCheck' failed",
1878                        &proc_res);
1879     }
1880 }
1881
1882 fn charset() -> &'static str {
1883     // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1884     if cfg!(target_os = "bitrig") {
1885         "auto"
1886     } else if cfg!(target_os = "freebsd") {
1887         "ISO-8859-1"
1888     } else {
1889         "UTF-8"
1890     }
1891 }
1892
1893 fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1894     assert!(props.revisions.is_empty(), "revisions not relevant here");
1895
1896     let out_dir = output_base_name(config, testpaths);
1897     let _ = fs::remove_dir_all(&out_dir);
1898     ensure_dir(&out_dir);
1899
1900     let proc_res = document(config, props, testpaths, &out_dir);
1901     if !proc_res.status.success() {
1902         fatal_proc_rec(None, "rustdoc failed!", &proc_res);
1903     }
1904     let root = find_rust_src_root(config).unwrap();
1905
1906     let res = cmd2procres(config,
1907                           testpaths,
1908                           Command::new(&config.python)
1909                                   .arg(root.join("src/etc/htmldocck.py"))
1910                                   .arg(out_dir)
1911                                   .arg(&testpaths.file));
1912     if !res.status.success() {
1913         fatal_proc_rec(None, "htmldocck failed!", &res);
1914     }
1915 }
1916
1917 fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1918     assert!(props.revisions.is_empty(), "revisions not relevant here");
1919
1920     let proc_res = compile_test(config, props, testpaths);
1921
1922     if !proc_res.status.success() {
1923         fatal_proc_rec(None, "compilation failed!", &proc_res);
1924     }
1925
1926     check_no_compiler_crash(None, &proc_res);
1927
1928     let prefix = "TRANS_ITEM ";
1929
1930     let actual: HashSet<String> = proc_res
1931         .stdout
1932         .lines()
1933         .filter(|line| line.starts_with(prefix))
1934         .map(|s| (&s[prefix.len()..]).to_string())
1935         .collect();
1936
1937     let expected: HashSet<String> = errors::load_errors(&testpaths.file, None)
1938         .iter()
1939         .map(|e| e.msg.trim().to_string())
1940         .collect();
1941
1942     if actual != expected {
1943         let mut missing: Vec<_> = expected.difference(&actual).collect();
1944         missing.sort();
1945
1946         let mut too_much: Vec<_> = actual.difference(&expected).collect();
1947         too_much.sort();
1948
1949         println!("Expected and actual sets of codegen-items differ.\n\
1950                   These items should have been contained but were not:\n\n\
1951                   {}\n\n\
1952                   These items were contained but should not have been:\n\n\
1953                   {}\n\n",
1954             missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
1955             too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));
1956         panic!();
1957     }
1958 }