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.
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.
12 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
13 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
15 use header::TestProps;
22 use std::collections::HashSet;
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};
31 pub fn run(config: Config, testpaths: &TestPaths) {
32 match &*config.target {
34 "arm-linux-androideabi" | "aarch64-linux-android" => {
35 if !config.adb_device_status {
36 panic!("android device not available");
44 // We're going to be dumping a lot of info. Start on a new line.
47 debug!("running {:?}", testpaths.file.display());
48 let props = header::load_props(&testpaths.file);
49 debug!("loaded props");
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),
65 fn get_output(props: &TestProps, proc_res: &ProcRes) -> String {
66 if props.check_stdout {
67 format!("{}{}", proc_res.stdout, proc_res.stderr)
69 proc_res.stderr.clone()
74 fn for_each_revision<OP>(config: &Config, props: &TestProps, testpaths: &TestPaths,
76 where OP: FnMut(&Config, &TestProps, &TestPaths, Option<&str>)
78 if props.revisions.is_empty() {
79 op(config, props, testpaths, None)
81 for revision in &props.revisions {
82 let mut revision_props = props.clone();
83 header::load_props_into(&mut revision_props,
86 revision_props.compile_flags.extend(vec![
88 format!("{}", revision),
90 op(config, &revision_props, testpaths, Some(revision));
95 fn run_cfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
96 for_each_revision(config, props, testpaths, run_cfail_test_revision);
99 fn run_cfail_test_revision(config: &Config,
101 testpaths: &TestPaths,
102 revision: Option<&str>) {
103 let proc_res = compile_test(config, props, testpaths);
105 if proc_res.status.success() {
108 &format!("{} test compiled successfully!", config.mode)[..],
112 check_correct_failure_status(revision, &proc_res);
114 if proc_res.status.success() {
115 fatal(revision, "process did not return an error status");
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");
124 check_expected_errors(revision, expected_errors, testpaths, &proc_res);
126 check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
128 check_no_compiler_crash(revision, &proc_res);
129 check_forbid_output(revision, props, &output_to_check, &proc_res);
132 fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
133 for_each_revision(config, props, testpaths, run_rfail_test_revision);
136 fn run_rfail_test_revision(config: &Config,
138 testpaths: &TestPaths,
139 revision: Option<&str>) {
140 let proc_res = compile_test(config, props, testpaths);
142 if !proc_res.status.success() {
143 fatal_proc_rec(revision, "compilation failed!", &proc_res);
146 let proc_res = exec_compiled_test(config, props, testpaths);
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);
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);
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) {
165 &format!("failure produced the wrong error: {}",
171 fn run_rpass_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
172 for_each_revision(config, props, testpaths, run_rpass_test_revision);
175 fn run_rpass_test_revision(config: &Config,
177 testpaths: &TestPaths,
178 revision: Option<&str>) {
179 let proc_res = compile_test(config, props, testpaths);
181 if !proc_res.status.success() {
182 fatal_proc_rec(revision, "compilation failed!", &proc_res);
185 let proc_res = exec_compiled_test(config, props, testpaths);
187 if !proc_res.status.success() {
188 fatal_proc_rec(revision, "test run failed!", &proc_res);
192 fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
193 assert!(props.revisions.is_empty(), "revisions not relevant here");
195 if config.valgrind_path.is_none() {
196 assert!(!config.force_valgrind);
197 return run_rpass_test(config, props, testpaths);
200 let mut proc_res = compile_test(config, props, testpaths);
202 if !proc_res.status.success() {
203 fatal_proc_rec(None, "compilation failed!", &proc_res);
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);
210 if !proc_res.status.success() {
211 fatal_proc_rec(None, "test run failed!", &proc_res);
215 fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
216 for_each_revision(config, props, testpaths, run_pretty_test_revision);
219 fn run_pretty_test_revision(config: &Config,
221 testpaths: &TestPaths,
222 revision: Option<&str>) {
223 if props.pp_exact.is_some() {
224 logv(config, "testing for exact pretty-printing".to_owned());
226 logv(config, "testing for converging pretty-printing".to_owned());
230 match props.pp_exact { Some(_) => 1, None => 2 };
232 let mut src = String::new();
233 File::open(&testpaths.file).unwrap().read_to_string(&mut src).unwrap();
234 let mut srcs = vec!(src);
237 while round < rounds {
238 logv(config, format!("pretty-printing round {} revision {:?}",
240 let proc_res = print_source(config,
243 srcs[round].to_owned(),
246 if !proc_res.status.success() {
247 fatal_proc_rec(revision,
248 &format!("pretty-printing failed in round {} revision {:?}",
253 let ProcRes{ stdout, .. } = proc_res;
258 let mut expected = match props.pp_exact {
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();
265 None => { srcs[srcs.len() - 2].clone() }
267 let mut actual = srcs[srcs.len() - 1].clone();
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();
276 compare_source(revision, &expected, &actual);
278 // If we're only making sure that the output matches then just stop here
279 if props.pretty_compare_only { return; }
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);
287 if !props.pretty_expanded { return }
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);
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() {
300 "pretty-printed source (expanded) does not typecheck",
306 fn print_source(config: &Config,
308 testpaths: &TestPaths,
310 pretty_type: &str) -> ProcRes {
311 let aux_dir = aux_output_dir_name(config, testpaths);
312 compose_and_run(config,
317 pretty_type.to_owned()),
318 props.exec_env.clone(),
319 &config.compile_lib_path,
320 Some(aux_dir.to_str().unwrap()),
324 fn make_pp_args(config: &Config,
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(),
334 format!("--target={}", config.target),
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());
340 prog: config.rustc_path.to_str().unwrap().to_owned(),
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");
350 ------------------------------------------\n\
352 ------------------------------------------\n\
354 ------------------------------------------\n\
356 ------------------------------------------\n\
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))
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 {
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),
381 config.build_base.to_str().unwrap().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
388 prog: config.rustc_path.to_str().unwrap().to_owned(),
394 fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
395 assert!(props.revisions.is_empty(), "revisions not relevant here");
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),
403 let config = &mut config;
404 let DebuggerCommands {
408 } = parse_debugger_commands(testpaths, "gdb");
409 let mut cmds = commands.join("\n");
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);
417 let exe_file = make_exe_name(config, testpaths);
419 let debugger_run_result;
420 match &*config.target {
421 "arm-linux-androideabi" | "aarch64-linux-android" => {
423 cmds = cmds.replace("run", "continue");
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",
441 script_str.push_str(&cmds);
442 script_str.push_str("\nquit\n");
444 debug!("script_str = {}", script_str);
445 dump_output_file(config,
456 exe_file.to_str().unwrap().to_owned(),
457 config.adb_test_dir.clone()
459 vec!(("".to_owned(), "".to_owned())),
461 .expect(&format!("failed to exec `{:?}`", config.adb_path));
467 "forward".to_owned(),
468 "tcp:5039".to_owned(),
469 "tcp:5039".to_owned()
471 vec!(("".to_owned(), "".to_owned())),
473 .expect(&format!("failed to exec `{:?}`", config.adb_path));
475 let adb_arg = format!("export LD_LIBRARY_PATH={}; \
476 gdbserver{} :5039 {}/{}",
477 config.adb_test_dir.clone(),
478 if config.target.contains("aarch64")
480 config.adb_test_dir.clone(),
481 exe_file.file_name().unwrap().to_str()
484 let mut process = procsrv::run_background("",
495 .expect(&format!("failed to exec `{:?}`", config.adb_path));
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() {
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")
509 let debugger_script = make_out_name(config, testpaths, "debugger.script");
510 // FIXME (#9639): This needs to handle non-utf8 paths
512 vec!("-quiet".to_owned(),
515 format!("-command={}", debugger_script.to_str().unwrap()));
517 let mut gdb_path = tool_path;
518 gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
519 let procsrv::Result {
527 vec!(("".to_owned(), "".to_owned())),
529 .expect(&format!("failed to exec `{:?}`", gdb_path));
531 let cmdline = make_cmdline("",
532 &format!("{}-gdb", config.target),
534 logv(config, format!("executing {}", cmdline));
538 debugger_run_result = ProcRes {
539 status: Status::Normal(status),
544 if process.kill().is_err() {
545 println!("Adb process is already finished.");
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)
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");
562 match config.gdb_version {
563 Some(ref version) => {
564 println!("NOTE: compiletest thinks it is using GDB version {}",
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
572 &format!("add-auto-load-safe-path {}\n",
573 rust_pp_module_abs_path.replace(r"\", r"\\"))
578 println!("NOTE: compiletest does not know which version of \
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");
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));
591 // Load the target executable
592 script_str.push_str(&format!("file {}\n",
593 exe_file.to_str().unwrap()
594 .replace(r"\", r"\\")));
596 // Add line breakpoints
597 for line in &breakpoint_lines {
598 script_str.push_str(&format!("break '{}':{}\n",
599 testpaths.file.file_name().unwrap()
604 script_str.push_str(&cmds);
605 script_str.push_str("\nquit\n");
607 debug!("script_str = {}", script_str);
608 dump_output_file(config,
613 // run debugger script with gdb
614 fn debugger() -> &'static str {
615 if cfg!(windows) {"gdb.exe"} else {"gdb"}
618 let debugger_script = make_out_name(config, testpaths, "debugger.script");
620 // FIXME (#9639): This needs to handle non-utf8 paths
622 vec!("-quiet".to_owned(),
625 format!("-command={}", debugger_script.to_str().unwrap()));
627 let proc_args = ProcArgs {
628 prog: debugger().to_owned(),
632 let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)];
634 debugger_run_result = compose_and_run(config,
638 &config.run_lib_path,
644 if !debugger_run_result.status.success() {
645 fatal(None, "gdb failed to execute");
648 check_debugger_output(&debugger_run_result, &check_lines);
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");
656 if path.join(&path_postfix).is_file() {
664 fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
665 assert!(props.revisions.is_empty(), "revisions not relevant here");
667 if config.lldb_python_dir.is_none() {
668 fatal(None, "Can't run LLDB test because LLDB's python path is not set.");
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),
677 let config = &mut config;
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);
685 let exe_file = make_exe_name(config, testpaths);
687 match config.lldb_version {
688 Some(ref version) => {
689 println!("NOTE: compiletest thinks it is using LLDB version {}",
693 println!("NOTE: compiletest does not know which version of \
698 // Parse debugger commands etc from test files
699 let DebuggerCommands {
704 } = parse_debugger_commands(testpaths, "lldb");
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");
710 // Make LLDB emit its version, so we have it documented in the test output
711 script_str.push_str("version\n");
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)
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");
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));
734 // Append the other commands
735 for line in &commands {
736 script_str.push_str(line);
737 script_str.push_str("\n");
740 // Finally, quit the debugger
741 script_str.push_str("\nquit\n");
743 // Write the script into a file
744 debug!("script_str = {}", script_str);
745 dump_output_file(config,
749 let debugger_script = make_out_name(config, testpaths, "debugger.script");
751 // Let LLDB execute the script via lldb_batchmode.py
752 let debugger_run_result = run_lldb(config,
758 if !debugger_run_result.status.success() {
759 fatal_proc_rec(None, "Error while running LLDB", &debugger_run_result);
762 check_debugger_output(&debugger_run_result, &check_lines);
764 fn run_lldb(config: &Config,
765 testpaths: &TestPaths,
766 test_executable: &Path,
767 debugger_script: &Path,
768 rust_src_root: &Path)
770 // Prepare the lldb_batchmode which executes the debugger script
771 let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
774 Command::new(&config.python)
775 .arg(&lldb_script_path)
776 .arg(test_executable)
777 .arg(debugger_script)
779 config.lldb_python_dir.as_ref().unwrap()))
783 fn cmd2procres(config: &Config, testpaths: &TestPaths, cmd: &mut Command)
785 let (status, out, err) = match cmd.output() {
786 Ok(Output { status, stdout, stderr }) => {
788 String::from_utf8(stdout).unwrap(),
789 String::from_utf8(stderr).unwrap())
792 fatal(None, &format!("Failed to setup Python process for \
793 LLDB script: {}", e))
797 dump_output(config, testpaths, &out, &err);
799 status: Status::Normal(status),
802 cmdline: format!("{:?}", cmd)
806 struct DebuggerCommands {
807 commands: Vec<String>,
808 check_lines: Vec<String>,
809 breakpoint_lines: Vec<usize>,
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);
817 let mut breakpoint_lines = vec!();
818 let mut commands = vec!();
819 let mut check_lines = vec!();
821 let reader = BufReader::new(File::open(&testpaths.file).unwrap());
822 for line in reader.lines() {
825 if line.contains("#break") {
826 breakpoint_lines.push(counter);
829 header::parse_name_value_directive(
831 &command_directive).map(|cmd| {
835 header::parse_name_value_directive(
837 &check_directive).map(|cmd| {
838 check_lines.push(cmd)
842 fatal(None, &format!("Error while parsing debugger commands: {}", e))
850 check_lines: check_lines,
851 breakpoint_lines: breakpoint_lines,
855 fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
856 if options.is_none() {
860 // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
861 let options_to_remove = [
864 "--debuginfo".to_owned()
866 let mut new_options =
867 split_maybe_args(options).into_iter()
868 .filter(|x| !options_to_remove.contains(x))
869 .collect::<Vec<String>>();
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);
881 // Always skip over -Z's argument.
887 Some(new_options.join(" "))
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| {
903 // check if each line in props.check_lines appears in the
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) {
926 rest = &rest[(i + frag.len())..];
931 if !failed && rest.is_empty() {
934 if i == num_check_lines {
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);
947 fn check_error_patterns(revision: Option<&str>,
949 testpaths: &TestPaths,
950 output_to_check: &str,
951 proc_res: &ProcRes) {
952 if props.error_patterns.is_empty() {
954 &format!("no error pattern specified in {:?}",
955 testpaths.file.display()));
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);
964 if next_err_idx == props.error_patterns.len() {
965 debug!("found all error patterns");
969 next_err_pat = &props.error_patterns[next_err_idx];
974 let missing_patterns = &props.error_patterns[next_err_idx..];
975 if missing_patterns.len() == 1 {
978 &format!("error pattern '{}' not found!", missing_patterns[0]),
981 for pattern in missing_patterns {
982 error(revision, &format!("error pattern '{}' not found!", *pattern));
984 fatal_proc_rec(revision, "multiple error patterns not found", proc_res);
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",
998 fn check_forbid_output(revision: Option<&str>,
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",
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()];
1018 if proc_res.status.success() {
1019 fatal_proc_rec(revision, "process did not return an error status", proc_res);
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>>();
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:"));
1035 // Scan and extract our error/warning messages,
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.
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;
1049 for (i, ee) in expected_errors.iter().enumerate() {
1050 if !found_flags[i] {
1051 debug!("prefix={} ee.kind={} ee.msg={} 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;
1068 (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
1069 line.contains(&ee.kind) &&
1070 line.contains(&ee.msg)
1072 found_flags[i] = true;
1073 was_expected = true;
1080 // ignore this msg which gets printed at the end
1081 if line.contains("aborting due to") {
1082 was_expected = true;
1085 if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) {
1086 error(revision, &format!("unexpected compiler message: '{}'", line));
1091 for (i, &flag) in found_flags.iter().enumerate() {
1093 let ee = &expected_errors[i];
1094 error(revision, &format!("expected {} on line {} not found: {}",
1095 ee.kind, ee.line_num, ee.msg));
1100 if unexpected > 0 || not_found > 0 {
1103 &format!("{} unexpected errors found, {} expected errors not found",
1104 unexpected, not_found),
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"\", "/");
1113 line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
1115 line.starts_with(prefix)
1119 // A multi-line error will have followup lines which start with a space
1121 fn continuation( line: &str) -> bool {
1122 line.starts_with(" ") || line.starts_with("(")
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(),
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))
1152 fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1153 if *idx >= haystack.len() {
1156 let opt = haystack[(*idx)..].find(needle);
1160 *idx = opt.unwrap();
1164 fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1165 if *idx >= haystack.len() {
1168 let ch = haystack.char_at(*idx);
1172 *idx += ch.len_utf8();
1176 fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
1178 while i < haystack.len() {
1179 let ch = haystack.char_at(i);
1180 if ch < '0' || '9' < ch {
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() {
1199 let ch = haystack.char_at(haystack_i);
1200 haystack_i += ch.len_utf8();
1201 if !scan_char(needle, ch, &mut needle_i) {
1227 fn code(&self) -> Option<i32> {
1229 Status::Parsed(i) => Some(i),
1230 Status::Normal(ref e) => e.code(),
1234 fn success(&self) -> bool {
1236 Status::Parsed(i) => i == 0,
1237 Status::Normal(ref e) => e.success(),
1242 impl fmt::Display for Status {
1243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1245 Status::Parsed(i) => write!(f, "exit code: {}", i),
1246 Status::Normal(ref e) => e.fmt(f),
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,
1260 |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testpaths);
1261 compose_and_run_compiler(config, props, testpaths, args, None)
1264 fn document(config: &Config,
1266 testpaths: &TestPaths,
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() {
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(),
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(),
1291 compose_and_run_compiler(config, props, testpaths, args, None)
1294 fn exec_compiled_test(config: &Config, props: &TestProps,
1295 testpaths: &TestPaths) -> ProcRes {
1297 let env = props.exec_env.clone();
1299 match &*config.target {
1301 "arm-linux-androideabi" | "aarch64-linux-android" => {
1302 _arm_exec_compiled_test(config, props, testpaths, env)
1306 let aux_dir = aux_output_dir_name(config, testpaths);
1307 compose_and_run(config,
1309 make_run_args(config, props, testpaths),
1311 &config.run_lib_path,
1312 Some(aux_dir.to_str().unwrap()),
1318 fn compute_aux_test_paths(config: &Config,
1319 testpaths: &TestPaths,
1323 let abs_ab = config.aux_base.join(rel_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())
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));
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()];
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 {
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).
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")
1363 vec!("--crate-type=lib".to_owned())
1365 vec!("--crate-type=dylib".to_owned())
1368 crate_type.extend(extra_link_args.clone());
1370 make_compile_args(config,
1374 let f = make_lib_name(a, &b.file, testpaths);
1375 let parent = f.parent().unwrap();
1376 TargetLocation::ThisDirectory(parent.to_path_buf())
1379 let auxres = compose_and_run(config,
1383 &config.compile_lib_path,
1384 Some(aux_dir.to_str().unwrap()),
1386 if !auxres.status.success() {
1389 &format!("auxiliary build of {:?} failed to compile: ",
1390 aux_testpaths.file.display()),
1394 match &*config.target {
1395 "arm-linux-androideabi" | "aarch64-linux-android" => {
1396 _arm_push_aux_shared_library(config, testpaths);
1402 compose_and_run(config,
1405 props.rustc_env.clone(),
1406 &config.compile_lib_path,
1407 Some(aux_dir.to_str().unwrap()),
1411 fn ensure_dir(path: &Path) {
1412 if path.is_dir() { return; }
1413 fs::create_dir_all(path).unwrap();
1416 fn compose_and_run(config: &Config,
1417 testpaths: &TestPaths,
1418 ProcArgs{ args, prog }: ProcArgs,
1419 procenv: Vec<(String, String)> ,
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);
1427 enum TargetLocation {
1429 ThisDirectory(PathBuf),
1432 fn make_compile_args<F>(config: &Config,
1434 extras: Vec<String> ,
1436 testpaths: &TestPaths)
1438 F: FnOnce(&Config, &TestPaths) -> TargetLocation,
1440 let xform_file = xform(config, testpaths);
1441 let target = if props.force_host {
1446 // FIXME (#9639): This needs to handle non-utf8 paths
1447 let mut args = vec!(testpaths.file.to_str().unwrap().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());
1456 let path = match xform_file {
1457 TargetLocation::ThisFile(path) => {
1458 args.push("-o".to_owned());
1461 TargetLocation::ThisDirectory(path) => {
1462 args.push("--out-dir".to_owned());
1466 args.push(path.to_str().unwrap().to_owned());
1467 if props.force_host {
1468 args.extend(split_maybe_args(&config.host_rustcflags));
1470 args.extend(split_maybe_args(&config.target_rustcflags));
1472 args.extend(props.compile_flags.iter().cloned());
1474 prog: config.rustc_path.to_str().unwrap().to_owned(),
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)
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();
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);
1501 fn make_run_args(config: &Config, props: &TestProps, testpaths: &TestPaths)
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);
1507 // If this is emscripten, then run tests under nodejs
1508 if config.target == "asmjs-unknown-emscripten" {
1509 args.push("nodejs".to_owned());
1512 let exe_file = make_exe_name(config, testpaths);
1514 // FIXME (#9639): This needs to handle non-utf8 paths
1515 args.push(exe_file.to_str().unwrap().to_owned());
1517 // Add the arguments in the run_flags directive
1518 args.extend(split_maybe_args(&props.run_flags));
1520 let prog = args.remove(0);
1527 fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
1533 if s.chars().all(|c| c.is_whitespace()) {
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 {
1550 let cmdline = make_cmdline(lib_path,
1553 logv(config, format!("executing {}", cmdline));
1556 let procsrv::Result {
1560 } = procsrv::run(lib_path,
1565 input).expect(&format!("failed to exec `{}`", prog));
1566 dump_output(config, testpaths, &out, &err);
1568 status: Status::Normal(status),
1575 fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
1578 // Linux and mac don't require adjusting the library search path
1580 format!("{} {}", prog, args.join(" "))
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))
1588 format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
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);
1598 fn dump_output_file(config: &Config,
1599 testpaths: &TestPaths,
1602 let outfile = make_out_name(config, testpaths, extension);
1603 File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1606 fn make_out_name(config: &Config, testpaths: &TestPaths, extension: &str) -> PathBuf {
1607 output_base_name(config, testpaths).with_extension(extension)
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)
1617 fn output_testname(filepath: &Path) -> PathBuf {
1618 PathBuf::from(filepath.file_stem().unwrap())
1621 fn output_base_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1622 let dir = config.build_base.join(&testpaths.relative_dir);
1624 // Note: The directory `dir` is created during `collect_tests_from_dir`
1626 .join(&output_testname(&testpaths.file))
1627 .with_extension(&config.stage_id)
1630 fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
1632 println!("------{}------------------------------", "stdout");
1633 println!("{}", out);
1634 println!("------{}------------------------------", "stderr");
1635 println!("{}", err);
1636 println!("------------------------------------------");
1640 fn error(revision: Option<&str>, err: &str) {
1642 Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1643 None => println!("\nerror: {}", err)
1647 fn fatal(revision: Option<&str>, err: &str) -> ! {
1648 error(revision, err); panic!();
1651 fn fatal_proc_rec(revision: Option<&str>, err: &str, proc_res: &ProcRes) -> ! {
1652 error(revision, err);
1657 ------------------------------------------\n\
1659 ------------------------------------------\n\
1661 ------------------------------------------\n\
1663 ------------------------------------------\n\
1665 proc_res.status, proc_res.cmdline, proc_res.stdout,
1670 fn _arm_exec_compiled_test(config: &Config,
1672 testpaths: &TestPaths,
1673 env: Vec<(String, String)>)
1675 let args = make_run_args(config, props, testpaths);
1676 let cmdline = make_cmdline("",
1680 // get bare program string
1681 let mut tvec: Vec<String> = args.prog
1685 let prog_short = tvec.pop().unwrap();
1688 let copy_result = procsrv::run("",
1694 config.adb_test_dir.clone()
1696 vec!(("".to_owned(), "".to_owned())),
1697 Some("".to_owned()))
1698 .expect(&format!("failed to exec `{}`", config.adb_path));
1701 println!("push ({}) {} {} {}",
1708 logv(config, format!("executing ({}) {}", config.target, cmdline));
1710 let mut runargs = Vec::new();
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));
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));
1721 for tv in &args.args {
1722 runargs.push(tv.to_owned());
1728 vec!(("".to_owned(), "".to_owned())), Some("".to_owned()))
1729 .expect(&format!("failed to exec `{}`", config.adb_path));
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));
1737 let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
1742 vec!(("".to_owned(), "".to_owned())),
1743 Some("".to_owned()))
1744 .expect(&format!("failed to exec `{}`", config.adb_path));
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),
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));
1761 let procsrv::Result{ out: stdout_out, err: _, status: _ } =
1766 vec!(("".to_owned(), "".to_owned())),
1767 Some("".to_owned()))
1768 .expect(&format!("failed to exec `{}`", config.adb_path));
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));
1776 let procsrv::Result{ out: stderr_out, err: _, status: _ } =
1781 vec!(("".to_owned(), "".to_owned())),
1782 Some("".to_owned()))
1783 .expect(&format!("failed to exec `{}`", config.adb_path));
1791 status: Status::Parsed(exitcode),
1798 fn _arm_push_aux_shared_library(config: &Config, testpaths: &TestPaths) {
1799 let tdir = aux_output_dir_name(config, testpaths);
1801 let dirs = fs::read_dir(&tdir).unwrap();
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("",
1814 config.adb_test_dir.to_owned(),
1816 vec!(("".to_owned(),
1818 Some("".to_owned()))
1819 .expect(&format!("failed to exec `{}`", config.adb_path));
1822 println!("push ({}) {:?} {} {}",
1823 config.target, file.display(),
1824 copy_result.out, copy_result.err);
1830 // codegen tests (using FileCheck)
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,
1843 |a, b| TargetLocation::ThisDirectory(
1844 output_base_name(a, b).parent()
1845 .unwrap().to_path_buf()),
1847 compose_and_run_compiler(config, props, testpaths, args, None)
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())
1859 compose_and_run(config, testpaths, proc_args, Vec::new(), "", None, None)
1862 fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1863 assert!(props.revisions.is_empty(), "revisions not relevant here");
1865 if config.llvm_bin_path.is_none() {
1866 fatal(None, "missing --llvm-bin-path");
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);
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",
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") {
1886 } else if cfg!(target_os = "freebsd") {
1893 fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1894 assert!(props.revisions.is_empty(), "revisions not relevant here");
1896 let out_dir = output_base_name(config, testpaths);
1897 let _ = fs::remove_dir_all(&out_dir);
1898 ensure_dir(&out_dir);
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);
1904 let root = find_rust_src_root(config).unwrap();
1906 let res = cmd2procres(config,
1908 Command::new(&config.python)
1909 .arg(root.join("src/etc/htmldocck.py"))
1911 .arg(&testpaths.file));
1912 if !res.status.success() {
1913 fatal_proc_rec(None, "htmldocck failed!", &res);
1917 fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1918 assert!(props.revisions.is_empty(), "revisions not relevant here");
1920 let proc_res = compile_test(config, props, testpaths);
1922 if !proc_res.status.success() {
1923 fatal_proc_rec(None, "compilation failed!", &proc_res);
1926 check_no_compiler_crash(None, &proc_res);
1928 let prefix = "TRANS_ITEM ";
1930 let actual: HashSet<String> = proc_res
1933 .filter(|line| line.starts_with(prefix))
1934 .map(|s| (&s[prefix.len()..]).to_string())
1937 let expected: HashSet<String> = errors::load_errors(&testpaths.file, None)
1939 .map(|e| e.msg.trim().to_string())
1942 if actual != expected {
1943 let mut missing: Vec<_> = expected.difference(&actual).collect();
1946 let mut too_much: Vec<_> = actual.difference(&expected).collect();
1949 println!("Expected and actual sets of codegen-items differ.\n\
1950 These items should have been contained but were not:\n\n\
1952 These items were contained but should not have been:\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));