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 common
::{Incremental}
;
15 use errors
::{self, ErrorKind}
;
16 use header
::TestProps
;
23 use std
::collections
::HashSet
;
25 use std
::fs
::{self, File}
;
26 use std
::io
::BufReader
;
27 use std
::io
::prelude
::*;
28 use std
::net
::TcpStream
;
29 use std
::path
::{Path, PathBuf, Component}
;
30 use std
::process
::{Command, Output, ExitStatus}
;
32 pub fn run(config
: Config
, testpaths
: &TestPaths
) {
33 match &*config
.target
{
35 "arm-linux-androideabi" | "aarch64-linux-android" => {
36 if !config
.adb_device_status
{
37 panic
!("android device not available");
45 // We're going to be dumping a lot of info. Start on a new line.
48 debug
!("running {:?}", testpaths
.file
.display());
49 let props
= header
::load_props(&testpaths
.file
);
50 debug
!("loaded props");
52 CompileFail
=> run_cfail_test(&config
, &props
, &testpaths
),
53 ParseFail
=> run_cfail_test(&config
, &props
, &testpaths
),
54 RunFail
=> run_rfail_test(&config
, &props
, &testpaths
),
55 RunPass
=> run_rpass_test(&config
, &props
, &testpaths
),
56 RunPassValgrind
=> run_valgrind_test(&config
, &props
, &testpaths
),
57 Pretty
=> run_pretty_test(&config
, &props
, &testpaths
),
58 DebugInfoGdb
=> run_debuginfo_gdb_test(&config
, &props
, &testpaths
),
59 DebugInfoLldb
=> run_debuginfo_lldb_test(&config
, &props
, &testpaths
),
60 Codegen
=> run_codegen_test(&config
, &props
, &testpaths
),
61 Rustdoc
=> run_rustdoc_test(&config
, &props
, &testpaths
),
62 CodegenUnits
=> run_codegen_units_test(&config
, &props
, &testpaths
),
63 Incremental
=> run_incremental_test(&config
, &props
, &testpaths
),
67 fn get_output(props
: &TestProps
, proc_res
: &ProcRes
) -> String
{
68 if props
.check_stdout
{
69 format
!("{}{}", proc_res
.stdout
, proc_res
.stderr
)
71 proc_res
.stderr
.clone()
76 fn for_each_revision
<OP
>(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
,
78 where OP
: FnMut(&Config
, &TestProps
, &TestPaths
, Option
<&str>)
80 if props
.revisions
.is_empty() {
81 op(config
, props
, testpaths
, None
)
83 for revision
in &props
.revisions
{
84 let mut revision_props
= props
.clone();
85 header
::load_props_into(&mut revision_props
,
88 revision_props
.compile_flags
.extend(vec
![
90 format
!("{}", revision
),
92 op(config
, &revision_props
, testpaths
, Some(revision
));
97 fn run_cfail_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
98 for_each_revision(config
, props
, testpaths
, run_cfail_test_revision
);
101 fn run_cfail_test_revision(config
: &Config
,
103 testpaths
: &TestPaths
,
104 revision
: Option
<&str>) {
105 let proc_res
= compile_test(config
, props
, testpaths
);
107 if proc_res
.status
.success() {
110 &format
!("{} test compiled successfully!", config
.mode
)[..],
114 check_correct_failure_status(revision
, &proc_res
);
116 if proc_res
.status
.success() {
117 fatal(revision
, "process did not return an error status");
120 let output_to_check
= get_output(props
, &proc_res
);
121 let expected_errors
= errors
::load_errors(&testpaths
.file
, revision
);
122 if !expected_errors
.is_empty() {
123 if !props
.error_patterns
.is_empty() {
124 fatal(revision
, "both error pattern and expected errors specified");
126 check_expected_errors(revision
, expected_errors
, testpaths
, &proc_res
);
128 check_error_patterns(revision
, props
, testpaths
, &output_to_check
, &proc_res
);
130 check_no_compiler_crash(revision
, &proc_res
);
131 check_forbid_output(revision
, props
, &output_to_check
, &proc_res
);
134 fn run_rfail_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
135 for_each_revision(config
, props
, testpaths
, run_rfail_test_revision
);
138 fn run_rfail_test_revision(config
: &Config
,
140 testpaths
: &TestPaths
,
141 revision
: Option
<&str>) {
142 let proc_res
= compile_test(config
, props
, testpaths
);
144 if !proc_res
.status
.success() {
145 fatal_proc_rec(revision
, "compilation failed!", &proc_res
);
148 let proc_res
= exec_compiled_test(config
, props
, testpaths
);
150 // The value our Makefile configures valgrind to return on failure
151 const VALGRIND_ERR
: i32 = 100;
152 if proc_res
.status
.code() == Some(VALGRIND_ERR
) {
153 fatal_proc_rec(revision
, "run-fail test isn't valgrind-clean!", &proc_res
);
156 let output_to_check
= get_output(props
, &proc_res
);
157 check_correct_failure_status(revision
, &proc_res
);
158 check_error_patterns(revision
, props
, testpaths
, &output_to_check
, &proc_res
);
161 fn check_correct_failure_status(revision
: Option
<&str>, proc_res
: &ProcRes
) {
162 // The value the rust runtime returns on failure
163 const RUST_ERR
: i32 = 101;
164 if proc_res
.status
.code() != Some(RUST_ERR
) {
167 &format
!("failure produced the wrong error: {}",
173 fn run_rpass_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
174 for_each_revision(config
, props
, testpaths
, run_rpass_test_revision
);
177 fn run_rpass_test_revision(config
: &Config
,
179 testpaths
: &TestPaths
,
180 revision
: Option
<&str>) {
181 let proc_res
= compile_test(config
, props
, testpaths
);
183 if !proc_res
.status
.success() {
184 fatal_proc_rec(revision
, "compilation failed!", &proc_res
);
187 let proc_res
= exec_compiled_test(config
, props
, testpaths
);
189 if !proc_res
.status
.success() {
190 fatal_proc_rec(revision
, "test run failed!", &proc_res
);
194 fn run_valgrind_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
195 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
197 if config
.valgrind_path
.is_none() {
198 assert
!(!config
.force_valgrind
);
199 return run_rpass_test(config
, props
, testpaths
);
202 let mut proc_res
= compile_test(config
, props
, testpaths
);
204 if !proc_res
.status
.success() {
205 fatal_proc_rec(None
, "compilation failed!", &proc_res
);
208 let mut new_config
= config
.clone();
209 new_config
.runtool
= new_config
.valgrind_path
.clone();
210 proc_res
= exec_compiled_test(&new_config
, props
, testpaths
);
212 if !proc_res
.status
.success() {
213 fatal_proc_rec(None
, "test run failed!", &proc_res
);
217 fn run_pretty_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
218 for_each_revision(config
, props
, testpaths
, run_pretty_test_revision
);
221 fn run_pretty_test_revision(config
: &Config
,
223 testpaths
: &TestPaths
,
224 revision
: Option
<&str>) {
225 if props
.pp_exact
.is_some() {
226 logv(config
, "testing for exact pretty-printing".to_owned());
228 logv(config
, "testing for converging pretty-printing".to_owned());
232 match props
.pp_exact { Some(_) => 1, None => 2 }
;
234 let mut src
= String
::new();
235 File
::open(&testpaths
.file
).unwrap().read_to_string(&mut src
).unwrap();
236 let mut srcs
= vec
!(src
);
239 while round
< rounds
{
240 logv(config
, format
!("pretty-printing round {} revision {:?}",
242 let proc_res
= print_source(config
,
245 srcs
[round
].to_owned(),
248 if !proc_res
.status
.success() {
249 fatal_proc_rec(revision
,
250 &format
!("pretty-printing failed in round {} revision {:?}",
255 let ProcRes{ stdout, .. }
= proc_res
;
260 let mut expected
= match props
.pp_exact
{
262 let filepath
= testpaths
.file
.parent().unwrap().join(file
);
263 let mut s
= String
::new();
264 File
::open(&filepath
).unwrap().read_to_string(&mut s
).unwrap();
267 None
=> { srcs[srcs.len() - 2].clone() }
269 let mut actual
= srcs
[srcs
.len() - 1].clone();
271 if props
.pp_exact
.is_some() {
272 // Now we have to care about line endings
273 let cr
= "\r".to_owned();
274 actual
= actual
.replace(&cr
, "").to_owned();
275 expected
= expected
.replace(&cr
, "").to_owned();
278 compare_source(revision
, &expected
, &actual
);
280 // If we're only making sure that the output matches then just stop here
281 if props
.pretty_compare_only { return; }
283 // Finally, let's make sure it actually appears to remain valid code
284 let proc_res
= typecheck_source(config
, props
, testpaths
, actual
);
285 if !proc_res
.status
.success() {
286 fatal_proc_rec(revision
, "pretty-printed source does not typecheck", &proc_res
);
289 if !props
.pretty_expanded { return }
291 // additionally, run `--pretty expanded` and try to build it.
292 let proc_res
= print_source(config
, props
, testpaths
, srcs
[round
].clone(), "expanded");
293 if !proc_res
.status
.success() {
294 fatal_proc_rec(revision
, "pretty-printing (expanded) failed", &proc_res
);
297 let ProcRes{ stdout: expanded_src, .. }
= proc_res
;
298 let proc_res
= typecheck_source(config
, props
, testpaths
, expanded_src
);
299 if !proc_res
.status
.success() {
302 "pretty-printed source (expanded) does not typecheck",
308 fn print_source(config
: &Config
,
310 testpaths
: &TestPaths
,
312 pretty_type
: &str) -> ProcRes
{
313 let aux_dir
= aux_output_dir_name(config
, testpaths
);
314 compose_and_run(config
,
319 pretty_type
.to_owned()),
320 props
.exec_env
.clone(),
321 config
.compile_lib_path
.to_str().unwrap(),
322 Some(aux_dir
.to_str().unwrap()),
326 fn make_pp_args(config
: &Config
,
328 testpaths
: &TestPaths
,
329 pretty_type
: String
) -> ProcArgs
{
330 let aux_dir
= aux_output_dir_name(config
, testpaths
);
331 // FIXME (#9639): This needs to handle non-utf8 paths
332 let mut args
= vec
!("-".to_owned(),
333 "-Zunstable-options".to_owned(),
334 "--unpretty".to_owned(),
336 format
!("--target={}", config
.target
),
338 aux_dir
.to_str().unwrap().to_owned());
339 args
.extend(split_maybe_args(&config
.target_rustcflags
));
340 args
.extend(props
.compile_flags
.iter().cloned());
342 prog
: config
.rustc_path
.to_str().unwrap().to_owned(),
347 fn compare_source(revision
: Option
<&str>, expected
: &str, actual
: &str) {
348 if expected
!= actual
{
349 error(revision
, "pretty-printed source does not match expected source");
352 ------------------------------------------\n\
354 ------------------------------------------\n\
356 ------------------------------------------\n\
358 ------------------------------------------\n\
365 fn typecheck_source(config
: &Config
, props
: &TestProps
,
366 testpaths
: &TestPaths
, src
: String
) -> ProcRes
{
367 let args
= make_typecheck_args(config
, props
, testpaths
);
368 compose_and_run_compiler(config
, props
, testpaths
, args
, Some(src
))
371 fn make_typecheck_args(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) -> ProcArgs
{
372 let aux_dir
= aux_output_dir_name(config
, testpaths
);
373 let target
= if props
.force_host
{
378 // FIXME (#9639): This needs to handle non-utf8 paths
379 let mut args
= vec
!("-".to_owned(),
380 "-Zno-trans".to_owned(),
381 format
!("--target={}", target
),
383 config
.build_base
.to_str().unwrap().to_owned(),
385 aux_dir
.to_str().unwrap().to_owned());
386 args
.extend(split_maybe_args(&config
.target_rustcflags
));
387 args
.extend(props
.compile_flags
.iter().cloned());
388 // FIXME (#9639): This needs to handle non-utf8 paths
390 prog
: config
.rustc_path
.to_str().unwrap().to_owned(),
396 fn run_debuginfo_gdb_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
397 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
399 let mut config
= Config
{
400 target_rustcflags
: cleanup_debug_info_options(&config
.target_rustcflags
),
401 host_rustcflags
: cleanup_debug_info_options(&config
.host_rustcflags
),
405 let config
= &mut config
;
406 let DebuggerCommands
{
410 } = parse_debugger_commands(testpaths
, "gdb");
411 let mut cmds
= commands
.join("\n");
413 // compile test file (it should have 'compile-flags:-g' in the header)
414 let compiler_run_result
= compile_test(config
, props
, testpaths
);
415 if !compiler_run_result
.status
.success() {
416 fatal_proc_rec(None
, "compilation failed!", &compiler_run_result
);
419 let exe_file
= make_exe_name(config
, testpaths
);
421 let debugger_run_result
;
422 match &*config
.target
{
423 "arm-linux-androideabi" | "aarch64-linux-android" => {
425 cmds
= cmds
.replace("run", "continue");
427 // write debugger script
428 let mut script_str
= String
::with_capacity(2048);
429 script_str
.push_str(&format
!("set charset {}\n", charset()));
430 script_str
.push_str(&format
!("file {}\n", exe_file
.to_str().unwrap()));
431 script_str
.push_str("target remote :5039\n");
432 script_str
.push_str(&format
!("set solib-search-path \
433 ./{}/stage2/lib/rustlib/{}/lib/\n",
434 config
.host
, config
.target
));
435 for line
in &breakpoint_lines
{
436 script_str
.push_str(&format
!("break {:?}:{}\n",
443 script_str
.push_str(&cmds
);
444 script_str
.push_str("\nquit\n");
446 debug
!("script_str = {}", script_str
);
447 dump_output_file(config
,
458 exe_file
.to_str().unwrap().to_owned(),
459 config
.adb_test_dir
.clone()
461 vec
!(("".to_owned(), "".to_owned())),
463 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
469 "forward".to_owned(),
470 "tcp:5039".to_owned(),
471 "tcp:5039".to_owned()
473 vec
!(("".to_owned(), "".to_owned())),
475 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
477 let adb_arg
= format
!("export LD_LIBRARY_PATH={}; \
478 gdbserver{} :5039 {}/{}",
479 config
.adb_test_dir
.clone(),
480 if config
.target
.contains("aarch64")
482 config
.adb_test_dir
.clone(),
483 exe_file
.file_name().unwrap().to_str()
486 let mut process
= procsrv
::run_background("",
497 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
499 //waiting 1 second for gdbserver start
500 ::std
::thread
::sleep(::std
::time
::Duration
::new(1,0));
501 if TcpStream
::connect("127.0.0.1:5039").is_ok() {
506 let tool_path
= match config
.android_cross_path
.to_str() {
507 Some(x
) => x
.to_owned(),
508 None
=> fatal(None
, "cannot find android cross path")
511 let debugger_script
= make_out_name(config
, testpaths
, "debugger.script");
512 // FIXME (#9639): This needs to handle non-utf8 paths
514 vec
!("-quiet".to_owned(),
517 format
!("-command={}", debugger_script
.to_str().unwrap()));
519 let mut gdb_path
= tool_path
;
520 gdb_path
.push_str(&format
!("/bin/{}-gdb", config
.target
));
521 let procsrv
::Result
{
529 vec
!(("".to_owned(), "".to_owned())),
531 .expect(&format
!("failed to exec `{:?}`", gdb_path
));
533 let cmdline
= make_cmdline("",
534 &format
!("{}-gdb", config
.target
),
536 logv(config
, format
!("executing {}", cmdline
));
540 debugger_run_result
= ProcRes
{
541 status
: Status
::Normal(status
),
546 if process
.kill().is_err() {
547 println
!("Adb process is already finished.");
552 let rust_src_root
= find_rust_src_root(config
)
553 .expect("Could not find Rust source root");
554 let rust_pp_module_rel_path
= Path
::new("./src/etc");
555 let rust_pp_module_abs_path
= rust_src_root
.join(rust_pp_module_rel_path
)
559 // write debugger script
560 let mut script_str
= String
::with_capacity(2048);
561 script_str
.push_str(&format
!("set charset {}\n", charset()));
562 script_str
.push_str("show version\n");
564 match config
.gdb_version
{
565 Some(ref version
) => {
566 println
!("NOTE: compiletest thinks it is using GDB version {}",
569 if header
::gdb_version_to_int(version
) >
570 header
::gdb_version_to_int("7.4") {
571 // Add the directory containing the pretty printers to
572 // GDB's script auto loading safe path
574 &format
!("add-auto-load-safe-path {}\n",
575 rust_pp_module_abs_path
.replace(r
"\", r
"\\"))
580 println
!("NOTE: compiletest does not know which version of \
585 // The following line actually doesn't have to do anything with
586 // pretty printing, it just tells GDB to print values on one line:
587 script_str
.push_str("set print pretty off\n");
589 // Add the pretty printer directory to GDB's source-file search path
590 script_str
.push_str(&format
!("directory {}\n",
591 rust_pp_module_abs_path
));
593 // Load the target executable
594 script_str
.push_str(&format
!("file {}\n",
595 exe_file
.to_str().unwrap()
596 .replace(r
"\", r
"\\")));
598 // Add line breakpoints
599 for line
in &breakpoint_lines
{
600 script_str
.push_str(&format
!("break '{}':{}\n",
601 testpaths
.file
.file_name().unwrap()
606 script_str
.push_str(&cmds
);
607 script_str
.push_str("\nquit\n");
609 debug
!("script_str = {}", script_str
);
610 dump_output_file(config
,
615 // run debugger script with gdb
616 fn debugger() -> &'
static str {
617 if cfg
!(windows
) {"gdb.exe"}
else {"gdb"}
620 let debugger_script
= make_out_name(config
, testpaths
, "debugger.script");
622 // FIXME (#9639): This needs to handle non-utf8 paths
624 vec
!("-quiet".to_owned(),
627 format
!("-command={}", debugger_script
.to_str().unwrap()));
629 let proc_args
= ProcArgs
{
630 prog
: debugger().to_owned(),
634 let environment
= vec
![("PYTHONPATH".to_owned(), rust_pp_module_abs_path
)];
636 debugger_run_result
= compose_and_run(config
,
640 config
.run_lib_path
.to_str().unwrap(),
646 if !debugger_run_result
.status
.success() {
647 fatal(None
, "gdb failed to execute");
650 check_debugger_output(&debugger_run_result
, &check_lines
);
653 fn find_rust_src_root(config
: &Config
) -> Option
<PathBuf
> {
654 let mut path
= config
.src_base
.clone();
655 let path_postfix
= Path
::new("src/etc/lldb_batchmode.py");
658 if path
.join(&path_postfix
).is_file() {
666 fn run_debuginfo_lldb_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
667 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
669 if config
.lldb_python_dir
.is_none() {
670 fatal(None
, "Can't run LLDB test because LLDB's python path is not set.");
673 let mut config
= Config
{
674 target_rustcflags
: cleanup_debug_info_options(&config
.target_rustcflags
),
675 host_rustcflags
: cleanup_debug_info_options(&config
.host_rustcflags
),
679 let config
= &mut config
;
681 // compile test file (it should have 'compile-flags:-g' in the header)
682 let compile_result
= compile_test(config
, props
, testpaths
);
683 if !compile_result
.status
.success() {
684 fatal_proc_rec(None
, "compilation failed!", &compile_result
);
687 let exe_file
= make_exe_name(config
, testpaths
);
689 match config
.lldb_version
{
690 Some(ref version
) => {
691 println
!("NOTE: compiletest thinks it is using LLDB version {}",
695 println
!("NOTE: compiletest does not know which version of \
700 // Parse debugger commands etc from test files
701 let DebuggerCommands
{
706 } = parse_debugger_commands(testpaths
, "lldb");
708 // Write debugger script:
709 // We don't want to hang when calling `quit` while the process is still running
710 let mut script_str
= String
::from("settings set auto-confirm true\n");
712 // Make LLDB emit its version, so we have it documented in the test output
713 script_str
.push_str("version\n");
715 // Switch LLDB into "Rust mode"
716 let rust_src_root
= find_rust_src_root(config
)
717 .expect("Could not find Rust source root");
718 let rust_pp_module_rel_path
= Path
::new("./src/etc/lldb_rust_formatters.py");
719 let rust_pp_module_abs_path
= rust_src_root
.join(rust_pp_module_rel_path
)
724 script_str
.push_str(&format
!("command script import {}\n",
725 &rust_pp_module_abs_path
[..])[..]);
726 script_str
.push_str("type summary add --no-value ");
727 script_str
.push_str("--python-function lldb_rust_formatters.print_val ");
728 script_str
.push_str("-x \".*\" --category Rust\n");
729 script_str
.push_str("type category enable Rust\n");
731 // Set breakpoints on every line that contains the string "#break"
732 let source_file_name
= testpaths
.file
.file_name().unwrap().to_string_lossy();
733 for line
in &breakpoint_lines
{
734 script_str
.push_str(&format
!("breakpoint set --file '{}' --line {}\n",
739 // Append the other commands
740 for line
in &commands
{
741 script_str
.push_str(line
);
742 script_str
.push_str("\n");
745 // Finally, quit the debugger
746 script_str
.push_str("\nquit\n");
748 // Write the script into a file
749 debug
!("script_str = {}", script_str
);
750 dump_output_file(config
,
754 let debugger_script
= make_out_name(config
, testpaths
, "debugger.script");
756 // Let LLDB execute the script via lldb_batchmode.py
757 let debugger_run_result
= run_lldb(config
,
763 if !debugger_run_result
.status
.success() {
764 fatal_proc_rec(None
, "Error while running LLDB", &debugger_run_result
);
767 check_debugger_output(&debugger_run_result
, &check_lines
);
769 fn run_lldb(config
: &Config
,
770 testpaths
: &TestPaths
,
771 test_executable
: &Path
,
772 debugger_script
: &Path
,
773 rust_src_root
: &Path
)
775 // Prepare the lldb_batchmode which executes the debugger script
776 let lldb_script_path
= rust_src_root
.join("src/etc/lldb_batchmode.py");
779 Command
::new(&config
.python
)
780 .arg(&lldb_script_path
)
781 .arg(test_executable
)
782 .arg(debugger_script
)
784 config
.lldb_python_dir
.as_ref().unwrap()))
788 fn cmd2procres(config
: &Config
, testpaths
: &TestPaths
, cmd
: &mut Command
)
790 let (status
, out
, err
) = match cmd
.output() {
791 Ok(Output { status, stdout, stderr }
) => {
793 String
::from_utf8(stdout
).unwrap(),
794 String
::from_utf8(stderr
).unwrap())
797 fatal(None
, &format
!("Failed to setup Python process for \
798 LLDB script: {}", e
))
802 dump_output(config
, testpaths
, &out
, &err
);
804 status
: Status
::Normal(status
),
807 cmdline
: format
!("{:?}", cmd
)
811 struct DebuggerCommands
{
812 commands
: Vec
<String
>,
813 check_lines
: Vec
<String
>,
814 breakpoint_lines
: Vec
<usize>,
817 fn parse_debugger_commands(testpaths
: &TestPaths
, debugger_prefix
: &str)
818 -> DebuggerCommands
{
819 let command_directive
= format
!("{}-command", debugger_prefix
);
820 let check_directive
= format
!("{}-check", debugger_prefix
);
822 let mut breakpoint_lines
= vec
!();
823 let mut commands
= vec
!();
824 let mut check_lines
= vec
!();
826 let reader
= BufReader
::new(File
::open(&testpaths
.file
).unwrap());
827 for line
in reader
.lines() {
830 if line
.contains("#break") {
831 breakpoint_lines
.push(counter
);
834 header
::parse_name_value_directive(
836 &command_directive
).map(|cmd
| {
840 header
::parse_name_value_directive(
842 &check_directive
).map(|cmd
| {
843 check_lines
.push(cmd
)
847 fatal(None
, &format
!("Error while parsing debugger commands: {}", e
))
855 check_lines
: check_lines
,
856 breakpoint_lines
: breakpoint_lines
,
860 fn cleanup_debug_info_options(options
: &Option
<String
>) -> Option
<String
> {
861 if options
.is_none() {
865 // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
866 let options_to_remove
= [
869 "--debuginfo".to_owned()
871 let mut new_options
=
872 split_maybe_args(options
).into_iter()
873 .filter(|x
| !options_to_remove
.contains(x
))
874 .collect
::<Vec
<String
>>();
877 while i
+ 1 < new_options
.len() {
878 if new_options
[i
] == "-Z" {
879 // FIXME #31005 MIR missing debuginfo currently.
880 if new_options
[i
+ 1] == "orbit" {
881 // Remove "-Z" and "orbit".
882 new_options
.remove(i
);
883 new_options
.remove(i
);
886 // Always skip over -Z's argument.
892 Some(new_options
.join(" "))
895 fn check_debugger_output(debugger_run_result
: &ProcRes
, check_lines
: &[String
]) {
896 let num_check_lines
= check_lines
.len();
897 if num_check_lines
> 0 {
898 // Allow check lines to leave parts unspecified (e.g., uninitialized
899 // bits in the wrong case of an enum) with the notation "[...]".
900 let check_fragments
: Vec
<Vec
<String
>> =
901 check_lines
.iter().map(|s
| {
908 // check if each line in props.check_lines appears in the
911 for line
in debugger_run_result
.stdout
.lines() {
912 let mut rest
= line
.trim();
913 let mut first
= true;
914 let mut failed
= false;
915 for frag
in &check_fragments
[i
] {
916 let found
= if first
{
917 if rest
.starts_with(frag
) {
931 rest
= &rest
[(i
+ frag
.len())..];
936 if !failed
&& rest
.is_empty() {
939 if i
== num_check_lines
{
944 if i
!= num_check_lines
{
945 fatal_proc_rec(None
, &format
!("line not found in debugger output: {}",
946 check_lines
.get(i
).unwrap()),
947 debugger_run_result
);
952 fn check_error_patterns(revision
: Option
<&str>,
954 testpaths
: &TestPaths
,
955 output_to_check
: &str,
956 proc_res
: &ProcRes
) {
957 if props
.error_patterns
.is_empty() {
959 &format
!("no error pattern specified in {:?}",
960 testpaths
.file
.display()));
962 let mut next_err_idx
= 0;
963 let mut next_err_pat
= &props
.error_patterns
[next_err_idx
];
964 let mut done
= false;
965 for line
in output_to_check
.lines() {
966 if line
.contains(next_err_pat
) {
967 debug
!("found error pattern {}", next_err_pat
);
969 if next_err_idx
== props
.error_patterns
.len() {
970 debug
!("found all error patterns");
974 next_err_pat
= &props
.error_patterns
[next_err_idx
];
979 let missing_patterns
= &props
.error_patterns
[next_err_idx
..];
980 if missing_patterns
.len() == 1 {
983 &format
!("error pattern '{}' not found!", missing_patterns
[0]),
986 for pattern
in missing_patterns
{
987 error(revision
, &format
!("error pattern '{}' not found!", *pattern
));
989 fatal_proc_rec(revision
, "multiple error patterns not found", proc_res
);
993 fn check_no_compiler_crash(revision
: Option
<&str>, proc_res
: &ProcRes
) {
994 for line
in proc_res
.stderr
.lines() {
995 if line
.starts_with("error: internal compiler error:") {
996 fatal_proc_rec(revision
,
997 "compiler encountered internal error",
1003 fn check_forbid_output(revision
: Option
<&str>,
1005 output_to_check
: &str,
1006 proc_res
: &ProcRes
) {
1007 for pat
in &props
.forbid_output
{
1008 if output_to_check
.contains(pat
) {
1009 fatal_proc_rec(revision
,
1010 "forbidden pattern found in compiler output",
1016 fn check_expected_errors(revision
: Option
<&str>,
1017 expected_errors
: Vec
<errors
::ExpectedError
>,
1018 testpaths
: &TestPaths
,
1019 proc_res
: &ProcRes
) {
1020 // true if we found the error in question
1021 let mut found_flags
= vec
![false; expected_errors
.len()];
1023 if proc_res
.status
.success() {
1024 fatal_proc_rec(revision
, "process did not return an error status", proc_res
);
1027 let prefixes
= expected_errors
.iter().map(|ee
| {
1028 let expected
= format
!("{}:{}:", testpaths
.file
.display(), ee
.line_num
);
1029 // On windows just translate all '\' path separators to '/'
1030 expected
.replace(r
"\", "/")
1031 }).collect
::<Vec
<String
>>();
1033 // If the testcase being checked contains at least one expected "help"
1034 // message, then we'll ensure that all "help" messages are expected.
1035 // Otherwise, all "help" messages reported by the compiler will be ignored.
1036 // This logic also applies to "note" messages.
1037 let (expect_help
, expect_note
) =
1038 expected_errors
.iter()
1039 .fold((false, false),
1040 |(acc_help
, acc_note
), ee
|
1041 (acc_help
|| ee
.kind
== Some(ErrorKind
::Help
),
1042 acc_note
|| ee
.kind
== Some(ErrorKind
::Note
)));
1044 // Scan and extract our error/warning messages,
1046 // filename:line1:col1: line2:col2: *error:* msg
1047 // filename:line1:col1: line2:col2: *warning:* msg
1048 // where line1:col1: is the starting point, line2:col2:
1049 // is the ending point, and * represents ANSI color codes.
1051 // This pattern is ambiguous on windows, because filename may contain
1052 // a colon, so any path prefix must be detected and removed first.
1053 let mut unexpected
= 0;
1054 let mut not_found
= 0;
1055 for line
in proc_res
.stderr
.lines() {
1056 let mut was_expected
= false;
1058 for (i
, ee
) in expected_errors
.iter().enumerate() {
1059 if !found_flags
[i
] {
1060 debug
!("prefix={} ee.kind={:?} ee.msg={} line={}",
1065 // Suggestions have no line number in their output, so take on the line number of
1066 // the previous expected error
1067 if ee
.kind
== Some(ErrorKind
::Suggestion
) {
1068 assert
!(expected_errors
[prev
].kind
== Some(ErrorKind
::Help
),
1069 "SUGGESTIONs must be preceded by a HELP");
1070 if line
.contains(&ee
.msg
) {
1071 found_flags
[i
] = true;
1072 was_expected
= true;
1077 (prefix_matches(line
, &prefixes
[i
]) || continuation(line
)) &&
1078 (ee
.kind
.is_none() || line
.contains(&ee
.kind
.as_ref().unwrap().to_string())) &&
1079 line
.contains(&ee
.msg
)
1081 found_flags
[i
] = true;
1082 was_expected
= true;
1089 // ignore this msg which gets printed at the end
1090 if line
.contains("aborting due to") {
1091 was_expected
= true;
1094 if !was_expected
&& is_unexpected_compiler_message(line
, expect_help
, expect_note
) {
1095 error(revision
, &format
!("unexpected compiler message: '{}'", line
));
1100 for (i
, &flag
) in found_flags
.iter().enumerate() {
1102 let ee
= &expected_errors
[i
];
1103 error(revision
, &format
!("expected {} on line {} not found: {}",
1105 .map_or("message".into(),
1107 ee
.line_num
, ee
.msg
));
1112 if unexpected
> 0 || not_found
> 0 {
1115 &format
!("{} unexpected errors found, {} expected errors not found",
1116 unexpected
, not_found
),
1120 fn prefix_matches(line
: &str, prefix
: &str) -> bool
{
1121 use std
::ascii
::AsciiExt
;
1122 // On windows just translate all '\' path separators to '/'
1123 let line
= line
.replace(r
"\", "/");
1125 line
.to_ascii_lowercase().starts_with(&prefix
.to_ascii_lowercase())
1127 line
.starts_with(prefix
)
1131 // A multi-line error will have followup lines which start with a space
1133 fn continuation( line
: &str) -> bool
{
1134 line
.starts_with(" ") || line
.starts_with("(")
1138 fn is_unexpected_compiler_message(line
: &str, expect_help
: bool
, expect_note
: bool
) -> bool
{
1139 let mut c
= Path
::new(line
).components();
1140 let line
= match c
.next() {
1141 Some(Component
::Prefix(_
)) => c
.as_path().to_str().unwrap(),
1146 return scan_until_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_char(line
, ' '
, &mut i
) &&
1153 scan_integer(line
, &mut i
) &&
1154 scan_char(line
, '
:'
, &mut i
) &&
1155 scan_integer(line
, &mut i
) &&
1156 scan_char(line
, ' '
, &mut i
) &&
1157 (scan_string(line
, "error", &mut i
) ||
1158 scan_string(line
, "warning", &mut i
) ||
1159 (expect_help
&& scan_string(line
, "help", &mut i
)) ||
1160 (expect_note
&& scan_string(line
, "note", &mut i
))
1164 fn scan_until_char(haystack
: &str, needle
: char, idx
: &mut usize) -> bool
{
1165 if *idx
>= haystack
.len() {
1168 let opt
= haystack
[(*idx
)..].find(needle
);
1172 *idx
= opt
.unwrap();
1176 fn scan_char(haystack
: &str, needle
: char, idx
: &mut usize) -> bool
{
1177 if *idx
>= haystack
.len() {
1180 let ch
= haystack
[*idx
..].chars().next().unwrap();
1184 *idx
+= ch
.len_utf8();
1188 fn scan_integer(haystack
: &str, idx
: &mut usize) -> bool
{
1190 while i
< haystack
.len() {
1191 let ch
= haystack
[i
..].chars().next().unwrap();
1192 if ch
< '
0'
|| '
9'
< ch
{
1204 fn scan_string(haystack
: &str, needle
: &str, idx
: &mut usize) -> bool
{
1205 let mut haystack_i
= *idx
;
1206 let mut needle_i
= 0;
1207 while needle_i
< needle
.len() {
1208 if haystack_i
>= haystack
.len() {
1211 let ch
= haystack
[haystack_i
..].chars().next().unwrap();
1212 haystack_i
+= ch
.len_utf8();
1213 if !scan_char(needle
, ch
, &mut needle_i
) {
1239 fn code(&self) -> Option
<i32> {
1241 Status
::Parsed(i
) => Some(i
),
1242 Status
::Normal(ref e
) => e
.code(),
1246 fn success(&self) -> bool
{
1248 Status
::Parsed(i
) => i
== 0,
1249 Status
::Normal(ref e
) => e
.success(),
1254 impl fmt
::Display
for Status
{
1255 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1257 Status
::Parsed(i
) => write
!(f
, "exit code: {}", i
),
1258 Status
::Normal(ref e
) => e
.fmt(f
),
1263 fn compile_test(config
: &Config
, props
: &TestProps
,
1264 testpaths
: &TestPaths
) -> ProcRes
{
1265 let aux_dir
= aux_output_dir_name(config
, testpaths
);
1266 // FIXME (#9639): This needs to handle non-utf8 paths
1267 let link_args
= vec
!("-L".to_owned(),
1268 aux_dir
.to_str().unwrap().to_owned());
1269 let args
= make_compile_args(config
,
1272 |a
, b
| TargetLocation
::ThisFile(make_exe_name(a
, b
)), testpaths
);
1273 compose_and_run_compiler(config
, props
, testpaths
, args
, None
)
1276 fn document(config
: &Config
,
1278 testpaths
: &TestPaths
,
1281 if props
.build_aux_docs
{
1282 for rel_ab
in &props
.aux_builds
{
1283 let aux_testpaths
= compute_aux_test_paths(config
, testpaths
, rel_ab
);
1284 let aux_props
= header
::load_props(&aux_testpaths
.file
);
1285 let auxres
= document(config
, &aux_props
, &aux_testpaths
, out_dir
);
1286 if !auxres
.status
.success() {
1292 let aux_dir
= aux_output_dir_name(config
, testpaths
);
1293 let mut args
= vec
!["-L".to_owned(),
1294 aux_dir
.to_str().unwrap().to_owned(),
1296 out_dir
.to_str().unwrap().to_owned(),
1297 testpaths
.file
.to_str().unwrap().to_owned()];
1298 args
.extend(props
.compile_flags
.iter().cloned());
1299 let args
= ProcArgs
{
1300 prog
: config
.rustdoc_path
.to_str().unwrap().to_owned(),
1303 compose_and_run_compiler(config
, props
, testpaths
, args
, None
)
1306 fn exec_compiled_test(config
: &Config
, props
: &TestProps
,
1307 testpaths
: &TestPaths
) -> ProcRes
{
1309 let env
= props
.exec_env
.clone();
1311 match &*config
.target
{
1313 "arm-linux-androideabi" | "aarch64-linux-android" => {
1314 _arm_exec_compiled_test(config
, props
, testpaths
, env
)
1318 let aux_dir
= aux_output_dir_name(config
, testpaths
);
1319 compose_and_run(config
,
1321 make_run_args(config
, props
, testpaths
),
1323 config
.run_lib_path
.to_str().unwrap(),
1324 Some(aux_dir
.to_str().unwrap()),
1330 fn compute_aux_test_paths(config
: &Config
,
1331 testpaths
: &TestPaths
,
1335 let abs_ab
= config
.aux_base
.join(rel_ab
);
1338 base
: testpaths
.base
.clone(),
1339 relative_dir
: Path
::new(rel_ab
).parent()
1340 .map(|p
| p
.to_path_buf())
1341 .unwrap_or_else(|| PathBuf
::new())
1345 fn compose_and_run_compiler(config
: &Config
, props
: &TestProps
,
1346 testpaths
: &TestPaths
, args
: ProcArgs
,
1347 input
: Option
<String
>) -> ProcRes
{
1348 if !props
.aux_builds
.is_empty() {
1349 ensure_dir(&aux_output_dir_name(config
, testpaths
));
1352 let aux_dir
= aux_output_dir_name(config
, testpaths
);
1353 // FIXME (#9639): This needs to handle non-utf8 paths
1354 let extra_link_args
= vec
!["-L".to_owned(),
1355 aux_dir
.to_str().unwrap().to_owned()];
1357 for rel_ab
in &props
.aux_builds
{
1358 let aux_testpaths
= compute_aux_test_paths(config
, testpaths
, rel_ab
);
1359 let aux_props
= header
::load_props(&aux_testpaths
.file
);
1360 let mut crate_type
= if aux_props
.no_prefer_dynamic
{
1363 // We primarily compile all auxiliary libraries as dynamic libraries
1364 // to avoid code size bloat and large binaries as much as possible
1365 // for the test suite (otherwise including libstd statically in all
1366 // executables takes up quite a bit of space).
1368 // For targets like MUSL or Emscripten, however, there is no support for
1369 // dynamic libraries so we just go back to building a normal library. Note,
1370 // however, that for MUSL if the library is built with `force_host` then
1371 // it's ok to be a dylib as the host should always support dylibs.
1372 if (config
.target
.contains("musl") && !aux_props
.force_host
) ||
1373 config
.target
.contains("emscripten")
1375 vec
!("--crate-type=lib".to_owned())
1377 vec
!("--crate-type=dylib".to_owned())
1380 crate_type
.extend(extra_link_args
.clone());
1382 make_compile_args(config
,
1386 let f
= make_lib_name(a
, &b
.file
, testpaths
);
1387 let parent
= f
.parent().unwrap();
1388 TargetLocation
::ThisDirectory(parent
.to_path_buf())
1391 let auxres
= compose_and_run(config
,
1395 config
.compile_lib_path
.to_str().unwrap(),
1396 Some(aux_dir
.to_str().unwrap()),
1398 if !auxres
.status
.success() {
1401 &format
!("auxiliary build of {:?} failed to compile: ",
1402 aux_testpaths
.file
.display()),
1406 match &*config
.target
{
1407 "arm-linux-androideabi" | "aarch64-linux-android" => {
1408 _arm_push_aux_shared_library(config
, testpaths
);
1414 compose_and_run(config
,
1417 props
.rustc_env
.clone(),
1418 config
.compile_lib_path
.to_str().unwrap(),
1419 Some(aux_dir
.to_str().unwrap()),
1423 fn ensure_dir(path
: &Path
) {
1424 if path
.is_dir() { return; }
1425 fs
::create_dir_all(path
).unwrap();
1428 fn compose_and_run(config
: &Config
,
1429 testpaths
: &TestPaths
,
1430 ProcArgs{ args, prog }
: ProcArgs
,
1431 procenv
: Vec
<(String
, String
)> ,
1433 aux_path
: Option
<&str>,
1434 input
: Option
<String
>) -> ProcRes
{
1435 return program_output(config
, testpaths
, lib_path
,
1436 prog
, aux_path
, args
, procenv
, input
);
1439 enum TargetLocation
{
1441 ThisDirectory(PathBuf
),
1444 fn make_compile_args
<F
>(config
: &Config
,
1446 extras
: Vec
<String
> ,
1448 testpaths
: &TestPaths
)
1450 F
: FnOnce(&Config
, &TestPaths
) -> TargetLocation
,
1452 let xform_file
= xform(config
, testpaths
);
1453 let target
= if props
.force_host
{
1458 // FIXME (#9639): This needs to handle non-utf8 paths
1459 let mut args
= vec
!(testpaths
.file
.to_str().unwrap().to_owned(),
1461 config
.build_base
.to_str().unwrap().to_owned(),
1462 format
!("--target={}", target
));
1463 args
.extend_from_slice(&extras
);
1464 if !props
.no_prefer_dynamic
{
1465 args
.push("-C".to_owned());
1466 args
.push("prefer-dynamic".to_owned());
1468 let path
= match xform_file
{
1469 TargetLocation
::ThisFile(path
) => {
1470 args
.push("-o".to_owned());
1473 TargetLocation
::ThisDirectory(path
) => {
1474 args
.push("--out-dir".to_owned());
1478 args
.push(path
.to_str().unwrap().to_owned());
1479 if props
.force_host
{
1480 args
.extend(split_maybe_args(&config
.host_rustcflags
));
1482 args
.extend(split_maybe_args(&config
.target_rustcflags
));
1484 args
.extend(props
.compile_flags
.iter().cloned());
1486 prog
: config
.rustc_path
.to_str().unwrap().to_owned(),
1491 fn make_lib_name(config
: &Config
, auxfile
: &Path
, testpaths
: &TestPaths
) -> PathBuf
{
1492 // what we return here is not particularly important, as it
1493 // happens; rustc ignores everything except for the directory.
1494 let auxname
= output_testname(auxfile
);
1495 aux_output_dir_name(config
, testpaths
).join(&auxname
)
1498 fn make_exe_name(config
: &Config
, testpaths
: &TestPaths
) -> PathBuf
{
1499 let mut f
= output_base_name(config
, testpaths
);
1500 // FIXME: This is using the host architecture exe suffix, not target!
1501 if config
.target
== "asmjs-unknown-emscripten" {
1502 let mut fname
= f
.file_name().unwrap().to_os_string();
1504 f
.set_file_name(&fname
);
1505 } else if !env
::consts
::EXE_SUFFIX
.is_empty() {
1506 let mut fname
= f
.file_name().unwrap().to_os_string();
1507 fname
.push(env
::consts
::EXE_SUFFIX
);
1508 f
.set_file_name(&fname
);
1513 fn make_run_args(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
)
1515 // If we've got another tool to run under (valgrind),
1516 // then split apart its command
1517 let mut args
= split_maybe_args(&config
.runtool
);
1519 // If this is emscripten, then run tests under nodejs
1520 if config
.target
== "asmjs-unknown-emscripten" {
1521 args
.push("nodejs".to_owned());
1524 let exe_file
= make_exe_name(config
, testpaths
);
1526 // FIXME (#9639): This needs to handle non-utf8 paths
1527 args
.push(exe_file
.to_str().unwrap().to_owned());
1529 // Add the arguments in the run_flags directive
1530 args
.extend(split_maybe_args(&props
.run_flags
));
1532 let prog
= args
.remove(0);
1539 fn split_maybe_args(argstr
: &Option
<String
>) -> Vec
<String
> {
1545 if s
.chars().all(|c
| c
.is_whitespace()) {
1556 fn program_output(config
: &Config
, testpaths
: &TestPaths
, lib_path
: &str, prog
: String
,
1557 aux_path
: Option
<&str>, args
: Vec
<String
>,
1558 env
: Vec
<(String
, String
)>,
1559 input
: Option
<String
>) -> ProcRes
{
1562 let cmdline
= make_cmdline(lib_path
,
1565 logv(config
, format
!("executing {}", cmdline
));
1568 let procsrv
::Result
{
1572 } = procsrv
::run(lib_path
,
1577 input
).expect(&format
!("failed to exec `{}`", prog
));
1578 dump_output(config
, testpaths
, &out
, &err
);
1580 status
: Status
::Normal(status
),
1587 fn make_cmdline(libpath
: &str, prog
: &str, args
: &[String
]) -> String
{
1590 // Linux and mac don't require adjusting the library search path
1592 format
!("{} {}", prog
, args
.join(" "))
1594 // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1595 // for diagnostic purposes
1596 fn lib_path_cmd_prefix(path
: &str) -> String
{
1597 format
!("{}=\"{}\"", util
::lib_path_env_var(), util
::make_new_path(path
))
1600 format
!("{} {} {}", lib_path_cmd_prefix(libpath
), prog
, args
.join(" "))
1604 fn dump_output(config
: &Config
, testpaths
: &TestPaths
, out
: &str, err
: &str) {
1605 dump_output_file(config
, testpaths
, out
, "out");
1606 dump_output_file(config
, testpaths
, err
, "err");
1607 maybe_dump_to_stdout(config
, out
, err
);
1610 fn dump_output_file(config
: &Config
,
1611 testpaths
: &TestPaths
,
1614 let outfile
= make_out_name(config
, testpaths
, extension
);
1615 File
::create(&outfile
).unwrap().write_all(out
.as_bytes()).unwrap();
1618 fn make_out_name(config
: &Config
, testpaths
: &TestPaths
, extension
: &str) -> PathBuf
{
1619 output_base_name(config
, testpaths
).with_extension(extension
)
1622 fn aux_output_dir_name(config
: &Config
, testpaths
: &TestPaths
) -> PathBuf
{
1623 let f
= output_base_name(config
, testpaths
);
1624 let mut fname
= f
.file_name().unwrap().to_os_string();
1625 fname
.push(&format
!(".{}.libaux", config
.mode
));
1626 f
.with_file_name(&fname
)
1629 fn output_testname(filepath
: &Path
) -> PathBuf
{
1630 PathBuf
::from(filepath
.file_stem().unwrap())
1633 fn output_base_name(config
: &Config
, testpaths
: &TestPaths
) -> PathBuf
{
1634 let dir
= config
.build_base
.join(&testpaths
.relative_dir
);
1636 // Note: The directory `dir` is created during `collect_tests_from_dir`
1638 .join(&output_testname(&testpaths
.file
))
1639 .with_extension(&config
.stage_id
)
1642 fn maybe_dump_to_stdout(config
: &Config
, out
: &str, err
: &str) {
1644 println
!("------{}------------------------------", "stdout");
1645 println
!("{}", out
);
1646 println
!("------{}------------------------------", "stderr");
1647 println
!("{}", err
);
1648 println
!("------------------------------------------");
1652 fn error(revision
: Option
<&str>, err
: &str) {
1654 Some(rev
) => println
!("\nerror in revision `{}`: {}", rev
, err
),
1655 None
=> println
!("\nerror: {}", err
)
1659 fn fatal(revision
: Option
<&str>, err
: &str) -> ! {
1660 error(revision
, err
); panic
!();
1663 fn fatal_proc_rec(revision
: Option
<&str>, err
: &str, proc_res
: &ProcRes
) -> ! {
1664 error(revision
, err
);
1669 ------------------------------------------\n\
1671 ------------------------------------------\n\
1673 ------------------------------------------\n\
1675 ------------------------------------------\n\
1677 proc_res
.status
, proc_res
.cmdline
, proc_res
.stdout
,
1682 fn _arm_exec_compiled_test(config
: &Config
,
1684 testpaths
: &TestPaths
,
1685 env
: Vec
<(String
, String
)>)
1687 let args
= make_run_args(config
, props
, testpaths
);
1688 let cmdline
= make_cmdline("",
1692 // get bare program string
1693 let mut tvec
: Vec
<String
> = args
.prog
1697 let prog_short
= tvec
.pop().unwrap();
1700 let copy_result
= procsrv
::run("",
1706 config
.adb_test_dir
.clone()
1708 vec
!(("".to_owned(), "".to_owned())),
1709 Some("".to_owned()))
1710 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1713 println
!("push ({}) {} {} {}",
1720 logv(config
, format
!("executing ({}) {}", config
.target
, cmdline
));
1722 let mut runargs
= Vec
::new();
1724 // run test via adb_run_wrapper
1725 runargs
.push("shell".to_owned());
1726 for (key
, val
) in env
{
1727 runargs
.push(format
!("{}={}", key
, val
));
1729 runargs
.push(format
!("{}/../adb_run_wrapper.sh", config
.adb_test_dir
));
1730 runargs
.push(format
!("{}", config
.adb_test_dir
));
1731 runargs
.push(format
!("{}", prog_short
));
1733 for tv
in &args
.args
{
1734 runargs
.push(tv
.to_owned());
1740 vec
!(("".to_owned(), "".to_owned())), Some("".to_owned()))
1741 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1743 // get exitcode of result
1744 runargs
= Vec
::new();
1745 runargs
.push("shell".to_owned());
1746 runargs
.push("cat".to_owned());
1747 runargs
.push(format
!("{}/{}.exitcode", config
.adb_test_dir
, prog_short
));
1749 let procsrv
::Result{ out: exitcode_out, err: _, status: _ }
=
1754 vec
!(("".to_owned(), "".to_owned())),
1755 Some("".to_owned()))
1756 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1758 let mut exitcode
: i32 = 0;
1759 for c
in exitcode_out
.chars() {
1760 if !c
.is_numeric() { break; }
1761 exitcode
= exitcode
* 10 + match c
{
1762 '
0'
... '
9'
=> c
as i32 - ('
0'
as i32),
1767 // get stdout of result
1768 runargs
= Vec
::new();
1769 runargs
.push("shell".to_owned());
1770 runargs
.push("cat".to_owned());
1771 runargs
.push(format
!("{}/{}.stdout", config
.adb_test_dir
, prog_short
));
1773 let procsrv
::Result{ out: stdout_out, err: _, status: _ }
=
1778 vec
!(("".to_owned(), "".to_owned())),
1779 Some("".to_owned()))
1780 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1782 // get stderr of result
1783 runargs
= Vec
::new();
1784 runargs
.push("shell".to_owned());
1785 runargs
.push("cat".to_owned());
1786 runargs
.push(format
!("{}/{}.stderr", config
.adb_test_dir
, prog_short
));
1788 let procsrv
::Result{ out: stderr_out, err: _, status: _ }
=
1793 vec
!(("".to_owned(), "".to_owned())),
1794 Some("".to_owned()))
1795 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1803 status
: Status
::Parsed(exitcode
),
1810 fn _arm_push_aux_shared_library(config
: &Config
, testpaths
: &TestPaths
) {
1811 let tdir
= aux_output_dir_name(config
, testpaths
);
1813 let dirs
= fs
::read_dir(&tdir
).unwrap();
1815 let file
= file
.unwrap().path();
1816 if file
.extension().and_then(|s
| s
.to_str()) == Some("so") {
1817 // FIXME (#9639): This needs to handle non-utf8 paths
1818 let copy_result
= procsrv
::run("",
1826 config
.adb_test_dir
.to_owned(),
1828 vec
!(("".to_owned(),
1830 Some("".to_owned()))
1831 .expect(&format
!("failed to exec `{}`", config
.adb_path
));
1834 println
!("push ({}) {:?} {} {}",
1835 config
.target
, file
.display(),
1836 copy_result
.out
, copy_result
.err
);
1842 // codegen tests (using FileCheck)
1844 fn compile_test_and_save_ir(config
: &Config
, props
: &TestProps
,
1845 testpaths
: &TestPaths
) -> ProcRes
{
1846 let aux_dir
= aux_output_dir_name(config
, testpaths
);
1847 // FIXME (#9639): This needs to handle non-utf8 paths
1848 let mut link_args
= vec
!("-L".to_owned(),
1849 aux_dir
.to_str().unwrap().to_owned());
1850 let llvm_args
= vec
!("--emit=llvm-ir".to_owned(),);
1851 link_args
.extend(llvm_args
);
1852 let args
= make_compile_args(config
,
1855 |a
, b
| TargetLocation
::ThisDirectory(
1856 output_base_name(a
, b
).parent()
1857 .unwrap().to_path_buf()),
1859 compose_and_run_compiler(config
, props
, testpaths
, args
, None
)
1862 fn check_ir_with_filecheck(config
: &Config
, testpaths
: &TestPaths
) -> ProcRes
{
1863 let irfile
= output_base_name(config
, testpaths
).with_extension("ll");
1864 let prog
= config
.llvm_bin_path
.as_ref().unwrap().join("FileCheck");
1865 let proc_args
= ProcArgs
{
1866 // FIXME (#9639): This needs to handle non-utf8 paths
1867 prog
: prog
.to_str().unwrap().to_owned(),
1868 args
: vec
!(format
!("-input-file={}", irfile
.to_str().unwrap()),
1869 testpaths
.file
.to_str().unwrap().to_owned())
1871 compose_and_run(config
, testpaths
, proc_args
, Vec
::new(), "", None
, None
)
1874 fn run_codegen_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
1875 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
1877 if config
.llvm_bin_path
.is_none() {
1878 fatal(None
, "missing --llvm-bin-path");
1881 let mut proc_res
= compile_test_and_save_ir(config
, props
, testpaths
);
1882 if !proc_res
.status
.success() {
1883 fatal_proc_rec(None
, "compilation failed!", &proc_res
);
1886 proc_res
= check_ir_with_filecheck(config
, testpaths
);
1887 if !proc_res
.status
.success() {
1888 fatal_proc_rec(None
,
1889 "verification with 'FileCheck' failed",
1894 fn charset() -> &'
static str {
1895 // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1896 if cfg
!(target_os
= "bitrig") {
1898 } else if cfg
!(target_os
= "freebsd") {
1905 fn run_rustdoc_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
1906 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
1908 let out_dir
= output_base_name(config
, testpaths
);
1909 let _
= fs
::remove_dir_all(&out_dir
);
1910 ensure_dir(&out_dir
);
1912 let proc_res
= document(config
, props
, testpaths
, &out_dir
);
1913 if !proc_res
.status
.success() {
1914 fatal_proc_rec(None
, "rustdoc failed!", &proc_res
);
1916 let root
= find_rust_src_root(config
).unwrap();
1918 let res
= cmd2procres(config
,
1920 Command
::new(&config
.python
)
1921 .arg(root
.join("src/etc/htmldocck.py"))
1923 .arg(&testpaths
.file
));
1924 if !res
.status
.success() {
1925 fatal_proc_rec(None
, "htmldocck failed!", &res
);
1929 fn run_codegen_units_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
1930 assert
!(props
.revisions
.is_empty(), "revisions not relevant here");
1932 let proc_res
= compile_test(config
, props
, testpaths
);
1934 if !proc_res
.status
.success() {
1935 fatal_proc_rec(None
, "compilation failed!", &proc_res
);
1938 check_no_compiler_crash(None
, &proc_res
);
1940 let prefix
= "TRANS_ITEM ";
1942 let actual
: HashSet
<String
> = proc_res
1945 .filter(|line
| line
.starts_with(prefix
))
1946 .map(|s
| (&s
[prefix
.len()..]).to_string())
1949 let expected
: HashSet
<String
> = errors
::load_errors(&testpaths
.file
, None
)
1951 .map(|e
| e
.msg
.trim().to_string())
1954 if actual
!= expected
{
1955 let mut missing
: Vec
<_
> = expected
.difference(&actual
).collect();
1958 let mut too_much
: Vec
<_
> = actual
.difference(&expected
).collect();
1961 println
!("Expected and actual sets of codegen-items differ.\n\
1962 These items should have been contained but were not:\n\n\
1964 These items were contained but should not have been:\n\n\
1966 missing
.iter().fold("".to_string(), |s1
, s2
| s1
+ "\n" + s2
),
1967 too_much
.iter().fold("".to_string(), |s1
, s2
| s1
+ "\n" + s2
));
1972 fn run_incremental_test(config
: &Config
, props
: &TestProps
, testpaths
: &TestPaths
) {
1973 // Basic plan for a test incremental/foo/bar.rs:
1974 // - load list of revisions pass1, fail2, pass3
1975 // - each should begin with `rpass`, `rfail`, or `cfail`
1976 // - if `rpass`, expect compile and execution to succeed
1977 // - if `cfail`, expect compilation to fail
1978 // - if `rfail`, expect execution to fail
1979 // - create a directory build/foo/bar.incremental
1980 // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass1
1981 // - because name of revision starts with "pass", expect success
1982 // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C fail2
1983 // - because name of revision starts with "fail", expect an error
1984 // - load expected errors as usual, but filter for those that end in `[fail2]`
1985 // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass3
1986 // - because name of revision starts with "pass", expect success
1987 // - execute build/foo/bar.exe and save output
1989 // FIXME -- use non-incremental mode as an oracle? That doesn't apply
1990 // to #[rustc_dirty] and clean tests I guess
1992 assert
!(!props
.revisions
.is_empty(), "incremental tests require a list of revisions");
1994 let output_base_name
= output_base_name(config
, testpaths
);
1996 // Create the incremental workproduct directory.
1997 let incremental_dir
= output_base_name
.with_extension("incremental");
1998 if incremental_dir
.exists() {
1999 fs
::remove_dir_all(&incremental_dir
).unwrap();
2001 fs
::create_dir_all(&incremental_dir
).unwrap();
2004 print
!("incremental_dir={}", incremental_dir
.display());
2007 for revision
in &props
.revisions
{
2008 let mut revision_props
= props
.clone();
2009 header
::load_props_into(&mut revision_props
, &testpaths
.file
, Some(&revision
));
2011 revision_props
.compile_flags
.extend(vec
![
2013 format
!("incremental={}", incremental_dir
.display()),
2015 format
!("{}", revision
),
2019 print
!("revision={:?} revision_props={:#?}", revision
, revision_props
);
2022 if revision
.starts_with("rpass") {
2023 run_rpass_test_revision(config
, &revision_props
, testpaths
, Some(&revision
));
2024 } else if revision
.starts_with("rfail") {
2025 run_rfail_test_revision(config
, &revision_props
, testpaths
, Some(&revision
));
2026 } else if revision
.starts_with("cfail") {
2027 run_cfail_test_revision(config
, &revision_props
, testpaths
, Some(&revision
));
2031 "revision name must begin with rpass, rfail, or cfail");