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};
14 use errors::{self, ErrorKind};
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 // If the testcase being checked contains at least one expected "help"
1029 // message, then we'll ensure that all "help" messages are expected.
1030 // Otherwise, all "help" messages reported by the compiler will be ignored.
1031 // This logic also applies to "note" messages.
1032 let (expect_help, expect_note) =
1033 expected_errors.iter()
1034 .fold((false, false),
1035 |(acc_help, acc_note), ee|
1036 (acc_help || ee.kind == Some(ErrorKind::Help),
1037 acc_note || ee.kind == Some(ErrorKind::Note)));
1039 // Scan and extract our error/warning messages,
1041 // filename:line1:col1: line2:col2: *error:* msg
1042 // filename:line1:col1: line2:col2: *warning:* msg
1043 // where line1:col1: is the starting point, line2:col2:
1044 // is the ending point, and * represents ANSI color codes.
1046 // This pattern is ambiguous on windows, because filename may contain
1047 // a colon, so any path prefix must be detected and removed first.
1048 let mut unexpected = 0;
1049 let mut not_found = 0;
1050 for line in proc_res.stderr.lines() {
1051 let mut was_expected = false;
1053 for (i, ee) in expected_errors.iter().enumerate() {
1054 if !found_flags[i] {
1055 debug!("prefix={} ee.kind={:?} ee.msg={} line={}",
1060 // Suggestions have no line number in their output, so take on the line number of
1061 // the previous expected error
1062 if ee.kind == Some(ErrorKind::Suggestion) {
1063 assert!(expected_errors[prev].kind == Some(ErrorKind::Help),
1064 "SUGGESTIONs must be preceded by a HELP");
1065 if line.contains(&ee.msg) {
1066 found_flags[i] = true;
1067 was_expected = true;
1072 (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
1073 (ee.kind.is_none() || line.contains(&ee.kind.as_ref().unwrap().to_string())) &&
1074 line.contains(&ee.msg)
1076 found_flags[i] = true;
1077 was_expected = true;
1084 // ignore this msg which gets printed at the end
1085 if line.contains("aborting due to") {
1086 was_expected = true;
1089 if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) {
1090 error(revision, &format!("unexpected compiler message: '{}'", line));
1095 for (i, &flag) in found_flags.iter().enumerate() {
1097 let ee = &expected_errors[i];
1098 error(revision, &format!("expected {} on line {} not found: {}",
1100 .map_or("message".into(),
1102 ee.line_num, ee.msg));
1107 if unexpected > 0 || not_found > 0 {
1110 &format!("{} unexpected errors found, {} expected errors not found",
1111 unexpected, not_found),
1115 fn prefix_matches(line: &str, prefix: &str) -> bool {
1116 use std::ascii::AsciiExt;
1117 // On windows just translate all '\' path separators to '/'
1118 let line = line.replace(r"\", "/");
1120 line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
1122 line.starts_with(prefix)
1126 // A multi-line error will have followup lines which start with a space
1128 fn continuation( line: &str) -> bool {
1129 line.starts_with(" ") || line.starts_with("(")
1133 fn is_unexpected_compiler_message(line: &str, expect_help: bool, expect_note: bool) -> bool {
1134 let mut c = Path::new(line).components();
1135 let line = match c.next() {
1136 Some(Component::Prefix(_)) => c.as_path().to_str().unwrap(),
1141 return scan_until_char(line, ':', &mut i) &&
1142 scan_char(line, ':', &mut i) &&
1143 scan_integer(line, &mut i) &&
1144 scan_char(line, ':', &mut i) &&
1145 scan_integer(line, &mut i) &&
1146 scan_char(line, ':', &mut i) &&
1147 scan_char(line, ' ', &mut i) &&
1148 scan_integer(line, &mut i) &&
1149 scan_char(line, ':', &mut i) &&
1150 scan_integer(line, &mut i) &&
1151 scan_char(line, ' ', &mut i) &&
1152 (scan_string(line, "error", &mut i) ||
1153 scan_string(line, "warning", &mut i) ||
1154 (expect_help && scan_string(line, "help", &mut i)) ||
1155 (expect_note && scan_string(line, "note", &mut i))
1159 fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1160 if *idx >= haystack.len() {
1163 let opt = haystack[(*idx)..].find(needle);
1167 *idx = opt.unwrap();
1171 fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1172 if *idx >= haystack.len() {
1175 let ch = haystack.char_at(*idx);
1179 *idx += ch.len_utf8();
1183 fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
1185 while i < haystack.len() {
1186 let ch = haystack.char_at(i);
1187 if ch < '0' || '9' < ch {
1199 fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool {
1200 let mut haystack_i = *idx;
1201 let mut needle_i = 0;
1202 while needle_i < needle.len() {
1203 if haystack_i >= haystack.len() {
1206 let ch = haystack.char_at(haystack_i);
1207 haystack_i += ch.len_utf8();
1208 if !scan_char(needle, ch, &mut needle_i) {
1234 fn code(&self) -> Option<i32> {
1236 Status::Parsed(i) => Some(i),
1237 Status::Normal(ref e) => e.code(),
1241 fn success(&self) -> bool {
1243 Status::Parsed(i) => i == 0,
1244 Status::Normal(ref e) => e.success(),
1249 impl fmt::Display for Status {
1250 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1252 Status::Parsed(i) => write!(f, "exit code: {}", i),
1253 Status::Normal(ref e) => e.fmt(f),
1258 fn compile_test(config: &Config, props: &TestProps,
1259 testpaths: &TestPaths) -> ProcRes {
1260 let aux_dir = aux_output_dir_name(config, testpaths);
1261 // FIXME (#9639): This needs to handle non-utf8 paths
1262 let link_args = vec!("-L".to_owned(),
1263 aux_dir.to_str().unwrap().to_owned());
1264 let args = make_compile_args(config,
1267 |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testpaths);
1268 compose_and_run_compiler(config, props, testpaths, args, None)
1271 fn document(config: &Config,
1273 testpaths: &TestPaths,
1276 if props.build_aux_docs {
1277 for rel_ab in &props.aux_builds {
1278 let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1279 let aux_props = header::load_props(&aux_testpaths.file);
1280 let auxres = document(config, &aux_props, &aux_testpaths, out_dir);
1281 if !auxres.status.success() {
1287 let aux_dir = aux_output_dir_name(config, testpaths);
1288 let mut args = vec!["-L".to_owned(),
1289 aux_dir.to_str().unwrap().to_owned(),
1291 out_dir.to_str().unwrap().to_owned(),
1292 testpaths.file.to_str().unwrap().to_owned()];
1293 args.extend(props.compile_flags.iter().cloned());
1294 let args = ProcArgs {
1295 prog: config.rustdoc_path.to_str().unwrap().to_owned(),
1298 compose_and_run_compiler(config, props, testpaths, args, None)
1301 fn exec_compiled_test(config: &Config, props: &TestProps,
1302 testpaths: &TestPaths) -> ProcRes {
1304 let env = props.exec_env.clone();
1306 match &*config.target {
1308 "arm-linux-androideabi" | "aarch64-linux-android" => {
1309 _arm_exec_compiled_test(config, props, testpaths, env)
1313 let aux_dir = aux_output_dir_name(config, testpaths);
1314 compose_and_run(config,
1316 make_run_args(config, props, testpaths),
1318 &config.run_lib_path,
1319 Some(aux_dir.to_str().unwrap()),
1325 fn compute_aux_test_paths(config: &Config,
1326 testpaths: &TestPaths,
1330 let abs_ab = config.aux_base.join(rel_ab);
1333 base: testpaths.base.clone(),
1334 relative_dir: Path::new(rel_ab).parent()
1335 .map(|p| p.to_path_buf())
1336 .unwrap_or_else(|| PathBuf::new())
1340 fn compose_and_run_compiler(config: &Config, props: &TestProps,
1341 testpaths: &TestPaths, args: ProcArgs,
1342 input: Option<String>) -> ProcRes {
1343 if !props.aux_builds.is_empty() {
1344 ensure_dir(&aux_output_dir_name(config, testpaths));
1347 let aux_dir = aux_output_dir_name(config, testpaths);
1348 // FIXME (#9639): This needs to handle non-utf8 paths
1349 let extra_link_args = vec!["-L".to_owned(),
1350 aux_dir.to_str().unwrap().to_owned()];
1352 for rel_ab in &props.aux_builds {
1353 let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1354 let aux_props = header::load_props(&aux_testpaths.file);
1355 let mut crate_type = if aux_props.no_prefer_dynamic {
1358 // We primarily compile all auxiliary libraries as dynamic libraries
1359 // to avoid code size bloat and large binaries as much as possible
1360 // for the test suite (otherwise including libstd statically in all
1361 // executables takes up quite a bit of space).
1363 // For targets like MUSL or Emscripten, however, there is no support for
1364 // dynamic libraries so we just go back to building a normal library. Note,
1365 // however, that for MUSL if the library is built with `force_host` then
1366 // it's ok to be a dylib as the host should always support dylibs.
1367 if (config.target.contains("musl") && !aux_props.force_host) ||
1368 config.target.contains("emscripten")
1370 vec!("--crate-type=lib".to_owned())
1372 vec!("--crate-type=dylib".to_owned())
1375 crate_type.extend(extra_link_args.clone());
1377 make_compile_args(config,
1381 let f = make_lib_name(a, &b.file, testpaths);
1382 let parent = f.parent().unwrap();
1383 TargetLocation::ThisDirectory(parent.to_path_buf())
1386 let auxres = compose_and_run(config,
1390 &config.compile_lib_path,
1391 Some(aux_dir.to_str().unwrap()),
1393 if !auxres.status.success() {
1396 &format!("auxiliary build of {:?} failed to compile: ",
1397 aux_testpaths.file.display()),
1401 match &*config.target {
1402 "arm-linux-androideabi" | "aarch64-linux-android" => {
1403 _arm_push_aux_shared_library(config, testpaths);
1409 compose_and_run(config,
1412 props.rustc_env.clone(),
1413 &config.compile_lib_path,
1414 Some(aux_dir.to_str().unwrap()),
1418 fn ensure_dir(path: &Path) {
1419 if path.is_dir() { return; }
1420 fs::create_dir_all(path).unwrap();
1423 fn compose_and_run(config: &Config,
1424 testpaths: &TestPaths,
1425 ProcArgs{ args, prog }: ProcArgs,
1426 procenv: Vec<(String, String)> ,
1428 aux_path: Option<&str>,
1429 input: Option<String>) -> ProcRes {
1430 return program_output(config, testpaths, lib_path,
1431 prog, aux_path, args, procenv, input);
1434 enum TargetLocation {
1436 ThisDirectory(PathBuf),
1439 fn make_compile_args<F>(config: &Config,
1441 extras: Vec<String> ,
1443 testpaths: &TestPaths)
1445 F: FnOnce(&Config, &TestPaths) -> TargetLocation,
1447 let xform_file = xform(config, testpaths);
1448 let target = if props.force_host {
1453 // FIXME (#9639): This needs to handle non-utf8 paths
1454 let mut args = vec!(testpaths.file.to_str().unwrap().to_owned(),
1456 config.build_base.to_str().unwrap().to_owned(),
1457 format!("--target={}", target));
1458 args.extend_from_slice(&extras);
1459 if !props.no_prefer_dynamic {
1460 args.push("-C".to_owned());
1461 args.push("prefer-dynamic".to_owned());
1463 let path = match xform_file {
1464 TargetLocation::ThisFile(path) => {
1465 args.push("-o".to_owned());
1468 TargetLocation::ThisDirectory(path) => {
1469 args.push("--out-dir".to_owned());
1473 args.push(path.to_str().unwrap().to_owned());
1474 if props.force_host {
1475 args.extend(split_maybe_args(&config.host_rustcflags));
1477 args.extend(split_maybe_args(&config.target_rustcflags));
1479 args.extend(props.compile_flags.iter().cloned());
1481 prog: config.rustc_path.to_str().unwrap().to_owned(),
1486 fn make_lib_name(config: &Config, auxfile: &Path, testpaths: &TestPaths) -> PathBuf {
1487 // what we return here is not particularly important, as it
1488 // happens; rustc ignores everything except for the directory.
1489 let auxname = output_testname(auxfile);
1490 aux_output_dir_name(config, testpaths).join(&auxname)
1493 fn make_exe_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1494 let mut f = output_base_name(config, testpaths);
1495 // FIXME: This is using the host architecture exe suffix, not target!
1496 if config.target == "asmjs-unknown-emscripten" {
1497 let mut fname = f.file_name().unwrap().to_os_string();
1499 f.set_file_name(&fname);
1500 } else if !env::consts::EXE_SUFFIX.is_empty() {
1501 let mut fname = f.file_name().unwrap().to_os_string();
1502 fname.push(env::consts::EXE_SUFFIX);
1503 f.set_file_name(&fname);
1508 fn make_run_args(config: &Config, props: &TestProps, testpaths: &TestPaths)
1510 // If we've got another tool to run under (valgrind),
1511 // then split apart its command
1512 let mut args = split_maybe_args(&config.runtool);
1514 // If this is emscripten, then run tests under nodejs
1515 if config.target == "asmjs-unknown-emscripten" {
1516 args.push("nodejs".to_owned());
1519 let exe_file = make_exe_name(config, testpaths);
1521 // FIXME (#9639): This needs to handle non-utf8 paths
1522 args.push(exe_file.to_str().unwrap().to_owned());
1524 // Add the arguments in the run_flags directive
1525 args.extend(split_maybe_args(&props.run_flags));
1527 let prog = args.remove(0);
1534 fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
1540 if s.chars().all(|c| c.is_whitespace()) {
1551 fn program_output(config: &Config, testpaths: &TestPaths, lib_path: &str, prog: String,
1552 aux_path: Option<&str>, args: Vec<String>,
1553 env: Vec<(String, String)>,
1554 input: Option<String>) -> ProcRes {
1557 let cmdline = make_cmdline(lib_path,
1560 logv(config, format!("executing {}", cmdline));
1563 let procsrv::Result {
1567 } = procsrv::run(lib_path,
1572 input).expect(&format!("failed to exec `{}`", prog));
1573 dump_output(config, testpaths, &out, &err);
1575 status: Status::Normal(status),
1582 fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
1585 // Linux and mac don't require adjusting the library search path
1587 format!("{} {}", prog, args.join(" "))
1589 // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1590 // for diagnostic purposes
1591 fn lib_path_cmd_prefix(path: &str) -> String {
1592 format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
1595 format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
1599 fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) {
1600 dump_output_file(config, testpaths, out, "out");
1601 dump_output_file(config, testpaths, err, "err");
1602 maybe_dump_to_stdout(config, out, err);
1605 fn dump_output_file(config: &Config,
1606 testpaths: &TestPaths,
1609 let outfile = make_out_name(config, testpaths, extension);
1610 File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1613 fn make_out_name(config: &Config, testpaths: &TestPaths, extension: &str) -> PathBuf {
1614 output_base_name(config, testpaths).with_extension(extension)
1617 fn aux_output_dir_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1618 let f = output_base_name(config, testpaths);
1619 let mut fname = f.file_name().unwrap().to_os_string();
1620 fname.push(&format!(".{}.libaux", config.mode));
1621 f.with_file_name(&fname)
1624 fn output_testname(filepath: &Path) -> PathBuf {
1625 PathBuf::from(filepath.file_stem().unwrap())
1628 fn output_base_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1629 let dir = config.build_base.join(&testpaths.relative_dir);
1631 // Note: The directory `dir` is created during `collect_tests_from_dir`
1633 .join(&output_testname(&testpaths.file))
1634 .with_extension(&config.stage_id)
1637 fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
1639 println!("------{}------------------------------", "stdout");
1640 println!("{}", out);
1641 println!("------{}------------------------------", "stderr");
1642 println!("{}", err);
1643 println!("------------------------------------------");
1647 fn error(revision: Option<&str>, err: &str) {
1649 Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1650 None => println!("\nerror: {}", err)
1654 fn fatal(revision: Option<&str>, err: &str) -> ! {
1655 error(revision, err); panic!();
1658 fn fatal_proc_rec(revision: Option<&str>, err: &str, proc_res: &ProcRes) -> ! {
1659 error(revision, err);
1664 ------------------------------------------\n\
1666 ------------------------------------------\n\
1668 ------------------------------------------\n\
1670 ------------------------------------------\n\
1672 proc_res.status, proc_res.cmdline, proc_res.stdout,
1677 fn _arm_exec_compiled_test(config: &Config,
1679 testpaths: &TestPaths,
1680 env: Vec<(String, String)>)
1682 let args = make_run_args(config, props, testpaths);
1683 let cmdline = make_cmdline("",
1687 // get bare program string
1688 let mut tvec: Vec<String> = args.prog
1692 let prog_short = tvec.pop().unwrap();
1695 let copy_result = procsrv::run("",
1701 config.adb_test_dir.clone()
1703 vec!(("".to_owned(), "".to_owned())),
1704 Some("".to_owned()))
1705 .expect(&format!("failed to exec `{}`", config.adb_path));
1708 println!("push ({}) {} {} {}",
1715 logv(config, format!("executing ({}) {}", config.target, cmdline));
1717 let mut runargs = Vec::new();
1719 // run test via adb_run_wrapper
1720 runargs.push("shell".to_owned());
1721 for (key, val) in env {
1722 runargs.push(format!("{}={}", key, val));
1724 runargs.push(format!("{}/../adb_run_wrapper.sh", config.adb_test_dir));
1725 runargs.push(format!("{}", config.adb_test_dir));
1726 runargs.push(format!("{}", prog_short));
1728 for tv in &args.args {
1729 runargs.push(tv.to_owned());
1735 vec!(("".to_owned(), "".to_owned())), Some("".to_owned()))
1736 .expect(&format!("failed to exec `{}`", config.adb_path));
1738 // get exitcode of result
1739 runargs = Vec::new();
1740 runargs.push("shell".to_owned());
1741 runargs.push("cat".to_owned());
1742 runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
1744 let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
1749 vec!(("".to_owned(), "".to_owned())),
1750 Some("".to_owned()))
1751 .expect(&format!("failed to exec `{}`", config.adb_path));
1753 let mut exitcode: i32 = 0;
1754 for c in exitcode_out.chars() {
1755 if !c.is_numeric() { break; }
1756 exitcode = exitcode * 10 + match c {
1757 '0' ... '9' => c as i32 - ('0' as i32),
1762 // get stdout of result
1763 runargs = Vec::new();
1764 runargs.push("shell".to_owned());
1765 runargs.push("cat".to_owned());
1766 runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
1768 let procsrv::Result{ out: stdout_out, err: _, status: _ } =
1773 vec!(("".to_owned(), "".to_owned())),
1774 Some("".to_owned()))
1775 .expect(&format!("failed to exec `{}`", config.adb_path));
1777 // get stderr of result
1778 runargs = Vec::new();
1779 runargs.push("shell".to_owned());
1780 runargs.push("cat".to_owned());
1781 runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
1783 let procsrv::Result{ out: stderr_out, err: _, status: _ } =
1788 vec!(("".to_owned(), "".to_owned())),
1789 Some("".to_owned()))
1790 .expect(&format!("failed to exec `{}`", config.adb_path));
1798 status: Status::Parsed(exitcode),
1805 fn _arm_push_aux_shared_library(config: &Config, testpaths: &TestPaths) {
1806 let tdir = aux_output_dir_name(config, testpaths);
1808 let dirs = fs::read_dir(&tdir).unwrap();
1810 let file = file.unwrap().path();
1811 if file.extension().and_then(|s| s.to_str()) == Some("so") {
1812 // FIXME (#9639): This needs to handle non-utf8 paths
1813 let copy_result = procsrv::run("",
1821 config.adb_test_dir.to_owned(),
1823 vec!(("".to_owned(),
1825 Some("".to_owned()))
1826 .expect(&format!("failed to exec `{}`", config.adb_path));
1829 println!("push ({}) {:?} {} {}",
1830 config.target, file.display(),
1831 copy_result.out, copy_result.err);
1837 // codegen tests (using FileCheck)
1839 fn compile_test_and_save_ir(config: &Config, props: &TestProps,
1840 testpaths: &TestPaths) -> ProcRes {
1841 let aux_dir = aux_output_dir_name(config, testpaths);
1842 // FIXME (#9639): This needs to handle non-utf8 paths
1843 let mut link_args = vec!("-L".to_owned(),
1844 aux_dir.to_str().unwrap().to_owned());
1845 let llvm_args = vec!("--emit=llvm-ir".to_owned(),);
1846 link_args.extend(llvm_args);
1847 let args = make_compile_args(config,
1850 |a, b| TargetLocation::ThisDirectory(
1851 output_base_name(a, b).parent()
1852 .unwrap().to_path_buf()),
1854 compose_and_run_compiler(config, props, testpaths, args, None)
1857 fn check_ir_with_filecheck(config: &Config, testpaths: &TestPaths) -> ProcRes {
1858 let irfile = output_base_name(config, testpaths).with_extension("ll");
1859 let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck");
1860 let proc_args = ProcArgs {
1861 // FIXME (#9639): This needs to handle non-utf8 paths
1862 prog: prog.to_str().unwrap().to_owned(),
1863 args: vec!(format!("-input-file={}", irfile.to_str().unwrap()),
1864 testpaths.file.to_str().unwrap().to_owned())
1866 compose_and_run(config, testpaths, proc_args, Vec::new(), "", None, None)
1869 fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1870 assert!(props.revisions.is_empty(), "revisions not relevant here");
1872 if config.llvm_bin_path.is_none() {
1873 fatal(None, "missing --llvm-bin-path");
1876 let mut proc_res = compile_test_and_save_ir(config, props, testpaths);
1877 if !proc_res.status.success() {
1878 fatal_proc_rec(None, "compilation failed!", &proc_res);
1881 proc_res = check_ir_with_filecheck(config, testpaths);
1882 if !proc_res.status.success() {
1883 fatal_proc_rec(None,
1884 "verification with 'FileCheck' failed",
1889 fn charset() -> &'static str {
1890 // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1891 if cfg!(target_os = "bitrig") {
1893 } else if cfg!(target_os = "freebsd") {
1900 fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1901 assert!(props.revisions.is_empty(), "revisions not relevant here");
1903 let out_dir = output_base_name(config, testpaths);
1904 let _ = fs::remove_dir_all(&out_dir);
1905 ensure_dir(&out_dir);
1907 let proc_res = document(config, props, testpaths, &out_dir);
1908 if !proc_res.status.success() {
1909 fatal_proc_rec(None, "rustdoc failed!", &proc_res);
1911 let root = find_rust_src_root(config).unwrap();
1913 let res = cmd2procres(config,
1915 Command::new(&config.python)
1916 .arg(root.join("src/etc/htmldocck.py"))
1918 .arg(&testpaths.file));
1919 if !res.status.success() {
1920 fatal_proc_rec(None, "htmldocck failed!", &res);
1924 fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1925 assert!(props.revisions.is_empty(), "revisions not relevant here");
1927 let proc_res = compile_test(config, props, testpaths);
1929 if !proc_res.status.success() {
1930 fatal_proc_rec(None, "compilation failed!", &proc_res);
1933 check_no_compiler_crash(None, &proc_res);
1935 let prefix = "TRANS_ITEM ";
1937 let actual: HashSet<String> = proc_res
1940 .filter(|line| line.starts_with(prefix))
1941 .map(|s| (&s[prefix.len()..]).to_string())
1944 let expected: HashSet<String> = errors::load_errors(&testpaths.file, None)
1946 .map(|e| e.msg.trim().to_string())
1949 if actual != expected {
1950 let mut missing: Vec<_> = expected.difference(&actual).collect();
1953 let mut too_much: Vec<_> = actual.difference(&expected).collect();
1956 println!("Expected and actual sets of codegen-items differ.\n\
1957 These items should have been contained but were not:\n\n\
1959 These items were contained but should not have been:\n\n\
1961 missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
1962 too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));