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.
11 use self::TargetLocation
::*;
14 use common
::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind, DebugInfoGdb}
;
15 use common
::{Codegen, DebugInfoLldb}
;
17 use header
::TestProps
;
21 #[cfg(target_os = "windows")]
24 #[cfg(target_os = "windows")]
25 use std
::ascii
::AsciiExt
;
26 use std
::old_io
::File
;
27 use std
::old_io
::fs
::PathExtensions
;
29 use std
::old_io
::net
::tcp
;
30 use std
::old_io
::process
::ProcessExit
;
31 use std
::old_io
::process
;
32 use std
::old_io
::timer
;
35 use std
::iter
::repeat
;
37 use std
::string
::String
;
39 use std
::time
::Duration
;
42 pub fn run(config
: Config
, testfile
: String
) {
43 match &*config
.target
{
45 "arm-linux-androideabi" | "aarch64-linux-android" => {
46 if !config
.adb_device_status
{
47 panic
!("android device not available");
54 let mut _mm
= MetricMap
::new();
55 run_metrics(config
, testfile
, &mut _mm
);
58 pub fn run_metrics(config
: Config
, testfile
: String
, mm
: &mut MetricMap
) {
60 // We're going to be dumping a lot of info. Start on a new line.
63 let testfile
= Path
::new(testfile
);
64 debug
!("running {:?}", testfile
.display());
65 let props
= header
::load_props(&testfile
);
66 debug
!("loaded props");
68 CompileFail
=> run_cfail_test(&config
, &props
, &testfile
),
69 ParseFail
=> run_cfail_test(&config
, &props
, &testfile
),
70 RunFail
=> run_rfail_test(&config
, &props
, &testfile
),
71 RunPass
=> run_rpass_test(&config
, &props
, &testfile
),
72 RunPassValgrind
=> run_valgrind_test(&config
, &props
, &testfile
),
73 Pretty
=> run_pretty_test(&config
, &props
, &testfile
),
74 DebugInfoGdb
=> run_debuginfo_gdb_test(&config
, &props
, &testfile
),
75 DebugInfoLldb
=> run_debuginfo_lldb_test(&config
, &props
, &testfile
),
76 Codegen
=> run_codegen_test(&config
, &props
, &testfile
, mm
),
80 fn get_output(props
: &TestProps
, proc_res
: &ProcRes
) -> String
{
81 if props
.check_stdout
{
82 format
!("{}{}", proc_res
.stdout
, proc_res
.stderr
)
84 proc_res
.stderr
.clone()
88 fn run_cfail_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
89 let proc_res
= compile_test(config
, props
, testfile
);
91 if proc_res
.status
.success() {
92 fatal_proc_rec(&format
!("{} test compiled successfully!", config
.mode
)[],
96 check_correct_failure_status(&proc_res
);
98 if proc_res
.status
.success() {
99 fatal("process did not return an error status");
102 let output_to_check
= get_output(props
, &proc_res
);
103 let expected_errors
= errors
::load_errors(testfile
);
104 if !expected_errors
.is_empty() {
105 if !props
.error_patterns
.is_empty() {
106 fatal("both error pattern and expected errors specified");
108 check_expected_errors(expected_errors
, testfile
, &proc_res
);
110 check_error_patterns(props
, testfile
, &output_to_check
, &proc_res
);
112 check_no_compiler_crash(&proc_res
);
113 check_forbid_output(props
, &output_to_check
, &proc_res
);
116 fn run_rfail_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
117 let proc_res
= if !config
.jit
{
118 let proc_res
= compile_test(config
, props
, testfile
);
120 if !proc_res
.status
.success() {
121 fatal_proc_rec("compilation failed!", &proc_res
);
124 exec_compiled_test(config
, props
, testfile
)
126 jit_test(config
, props
, testfile
)
129 // The value our Makefile configures valgrind to return on failure
130 static VALGRIND_ERR
: int
= 100;
131 if proc_res
.status
.matches_exit_status(VALGRIND_ERR
) {
132 fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res
);
135 let output_to_check
= get_output(props
, &proc_res
);
136 check_correct_failure_status(&proc_res
);
137 check_error_patterns(props
, testfile
, &output_to_check
, &proc_res
);
140 fn check_correct_failure_status(proc_res
: &ProcRes
) {
141 // The value the rust runtime returns on failure
142 static RUST_ERR
: int
= 101;
143 if !proc_res
.status
.matches_exit_status(RUST_ERR
) {
145 &format
!("failure produced the wrong error: {:?}",
151 fn run_rpass_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
153 let mut proc_res
= compile_test(config
, props
, testfile
);
155 if !proc_res
.status
.success() {
156 fatal_proc_rec("compilation failed!", &proc_res
);
159 proc_res
= exec_compiled_test(config
, props
, testfile
);
161 if !proc_res
.status
.success() {
162 fatal_proc_rec("test run failed!", &proc_res
);
165 let proc_res
= jit_test(config
, props
, testfile
);
167 if !proc_res
.status
.success() {
168 fatal_proc_rec("jit failed!", &proc_res
);
173 fn run_valgrind_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
174 if config
.valgrind_path
.is_none() {
175 assert
!(!config
.force_valgrind
);
176 return run_rpass_test(config
, props
, testfile
);
179 let mut proc_res
= compile_test(config
, props
, testfile
);
181 if !proc_res
.status
.success() {
182 fatal_proc_rec("compilation failed!", &proc_res
);
185 let mut new_config
= config
.clone();
186 new_config
.runtool
= new_config
.valgrind_path
.clone();
187 proc_res
= exec_compiled_test(&new_config
, props
, testfile
);
189 if !proc_res
.status
.success() {
190 fatal_proc_rec("test run failed!", &proc_res
);
194 fn run_pretty_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
195 if props
.pp_exact
.is_some() {
196 logv(config
, "testing for exact pretty-printing".to_string());
198 logv(config
, "testing for converging pretty-printing".to_string());
202 match props
.pp_exact { Some(_) => 1, None => 2 }
;
204 let src
= File
::open(testfile
).read_to_end().unwrap();
205 let src
= String
::from_utf8(src
.clone()).unwrap();
206 let mut srcs
= vec
!(src
);
209 while round
< rounds
{
210 logv(config
, format
!("pretty-printing round {}", round
));
211 let proc_res
= print_source(config
,
214 srcs
[round
].to_string(),
217 if !proc_res
.status
.success() {
218 fatal_proc_rec(&format
!("pretty-printing failed in round {}", round
),
222 let ProcRes{ stdout, .. }
= proc_res
;
227 let mut expected
= match props
.pp_exact
{
229 let filepath
= testfile
.dir_path().join(file
);
230 let s
= File
::open(&filepath
).read_to_end().unwrap();
231 String
::from_utf8(s
).unwrap()
233 None
=> { srcs[srcs.len() - 2].clone() }
235 let mut actual
= srcs
[srcs
.len() - 1].clone();
237 if props
.pp_exact
.is_some() {
238 // Now we have to care about line endings
239 let cr
= "\r".to_string();
240 actual
= actual
.replace(&cr
, "").to_string();
241 expected
= expected
.replace(&cr
, "").to_string();
244 compare_source(&expected
, &actual
);
246 // If we're only making sure that the output matches then just stop here
247 if props
.pretty_compare_only { return; }
249 // Finally, let's make sure it actually appears to remain valid code
250 let proc_res
= typecheck_source(config
, props
, testfile
, actual
);
252 if !proc_res
.status
.success() {
253 fatal_proc_rec("pretty-printed source does not typecheck", &proc_res
);
255 if props
.no_pretty_expanded { return }
257 // additionally, run `--pretty expanded` and try to build it.
258 let proc_res
= print_source(config
, props
, testfile
, srcs
[round
].clone(), "expanded");
259 if !proc_res
.status
.success() {
260 fatal_proc_rec("pretty-printing (expanded) failed", &proc_res
);
263 let ProcRes{ stdout: expanded_src, .. }
= proc_res
;
264 let proc_res
= typecheck_source(config
, props
, testfile
, expanded_src
);
265 if !proc_res
.status
.success() {
266 fatal_proc_rec("pretty-printed source (expanded) does not typecheck",
272 fn print_source(config
: &Config
,
276 pretty_type
: &str) -> ProcRes
{
277 let aux_dir
= aux_output_dir_name(config
, testfile
);
278 compose_and_run(config
,
283 pretty_type
.to_string()),
284 props
.exec_env
.clone(),
285 &config
.compile_lib_path
,
286 Some(aux_dir
.as_str().unwrap()),
290 fn make_pp_args(config
: &Config
,
293 pretty_type
: String
) -> ProcArgs
{
294 let aux_dir
= aux_output_dir_name(config
, testfile
);
295 // FIXME (#9639): This needs to handle non-utf8 paths
296 let mut args
= vec
!("-".to_string(),
297 "-Zunstable-options".to_string(),
298 "--pretty".to_string(),
300 format
!("--target={}", config
.target
),
302 aux_dir
.as_str().unwrap().to_string());
303 args
.extend(split_maybe_args(&config
.target_rustcflags
).into_iter());
304 args
.extend(split_maybe_args(&props
.compile_flags
).into_iter());
306 prog
: config
.rustc_path
.as_str().unwrap().to_string(),
311 fn compare_source(expected
: &str, actual
: &str) {
312 if expected
!= actual
{
313 error("pretty-printed source does not match expected source");
316 ------------------------------------------\n\
318 ------------------------------------------\n\
320 ------------------------------------------\n\
322 ------------------------------------------\n\
329 fn typecheck_source(config
: &Config
, props
: &TestProps
,
330 testfile
: &Path
, src
: String
) -> ProcRes
{
331 let args
= make_typecheck_args(config
, props
, testfile
);
332 compose_and_run_compiler(config
, props
, testfile
, args
, Some(src
))
335 fn make_typecheck_args(config
: &Config
, props
: &TestProps
, testfile
: &Path
) -> ProcArgs
{
336 let aux_dir
= aux_output_dir_name(config
, testfile
);
337 let target
= if props
.force_host
{
342 // FIXME (#9639): This needs to handle non-utf8 paths
343 let mut args
= vec
!("-".to_string(),
344 "-Zno-trans".to_string(),
345 "--crate-type=lib".to_string(),
346 format
!("--target={}", target
),
348 config
.build_base
.as_str().unwrap().to_string(),
350 aux_dir
.as_str().unwrap().to_string());
351 args
.extend(split_maybe_args(&config
.target_rustcflags
).into_iter());
352 args
.extend(split_maybe_args(&props
.compile_flags
).into_iter());
353 // FIXME (#9639): This needs to handle non-utf8 paths
355 prog
: config
.rustc_path
.as_str().unwrap().to_string(),
361 fn run_debuginfo_gdb_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
362 let mut config
= Config
{
363 target_rustcflags
: cleanup_debug_info_options(&config
.target_rustcflags
),
364 host_rustcflags
: cleanup_debug_info_options(&config
.host_rustcflags
),
368 let config
= &mut config
;
369 let DebuggerCommands
{
373 } = parse_debugger_commands(testfile
, "gdb");
374 let mut cmds
= commands
.connect("\n");
376 // compile test file (it should have 'compile-flags:-g' in the header)
377 let compiler_run_result
= compile_test(config
, props
, testfile
);
378 if !compiler_run_result
.status
.success() {
379 fatal_proc_rec("compilation failed!", &compiler_run_result
);
382 let exe_file
= make_exe_name(config
, testfile
);
384 let debugger_run_result
;
385 match &*config
.target
{
386 "arm-linux-androideabi" | "aarch64-linux-android" => {
388 cmds
= cmds
.replace("run", "continue");
390 // write debugger script
391 let mut script_str
= String
::with_capacity(2048);
392 script_str
.push_str("set charset UTF-8\n");
393 script_str
.push_str(&format
!("file {}\n", exe_file
.as_str().unwrap()));
394 script_str
.push_str("target remote :5039\n");
395 script_str
.push_str(&format
!("set solib-search-path \
396 ./{}/stage2/lib/rustlib/{}/lib/\n",
397 config
.host
, config
.target
));
398 for line
in breakpoint_lines
.iter() {
399 script_str
.push_str(&format
!("break {:?}:{}\n",
400 testfile
.filename_display(),
403 script_str
.push_str(&cmds
);
404 script_str
.push_str("quit\n");
406 debug
!("script_str = {}", script_str
);
407 dump_output_file(config
,
418 exe_file
.as_str().unwrap().to_string(),
419 config
.adb_test_dir
.clone()
421 vec
!(("".to_string(), "".to_string())),
422 Some("".to_string()))
423 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
429 "forward".to_string(),
430 "tcp:5039".to_string(),
431 "tcp:5039".to_string()
433 vec
!(("".to_string(), "".to_string())),
434 Some("".to_string()))
435 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
437 let adb_arg
= format
!("export LD_LIBRARY_PATH={}; \
438 gdbserver{} :5039 {}/{}",
439 config
.adb_test_dir
.clone(),
440 if config
.target
.contains("aarch64")
442 config
.adb_test_dir
.clone(),
445 .unwrap()).unwrap());
447 let mut process
= procsrv
::run_background("",
455 vec
!(("".to_string(),
457 Some("".to_string()))
458 .expect(&format
!("failed to exec `{:?}`", config
.adb_path
));
460 //waiting 1 second for gdbserver start
461 timer
::sleep(Duration
::milliseconds(1000));
462 let result
= thread
::spawn(move || {
463 tcp
::TcpStream
::connect("127.0.0.1:5039").unwrap();
471 let tool_path
= match config
.android_cross_path
.as_str() {
472 Some(x
) => x
.to_string(),
473 None
=> fatal("cannot find android cross path")
476 let debugger_script
= make_out_name(config
, testfile
, "debugger.script");
477 // FIXME (#9639): This needs to handle non-utf8 paths
479 vec
!("-quiet".to_string(),
480 "-batch".to_string(),
482 format
!("-command={}", debugger_script
.as_str().unwrap()));
484 let mut gdb_path
= tool_path
;
485 gdb_path
.push_str(&format
!("/bin/{}-gdb", config
.target
));
486 let procsrv
::Result
{
494 vec
!(("".to_string(), "".to_string())),
496 .expect(&format
!("failed to exec `{:?}`", gdb_path
));
498 let cmdline
= make_cmdline("",
499 &format
!("{}-gdb", config
.target
),
501 logv(config
, format
!("executing {}", cmdline
));
505 debugger_run_result
= ProcRes
{
511 if process
.signal_kill().is_err() {
512 println
!("Adb process is already finished.");
517 let rust_src_root
= find_rust_src_root(config
)
518 .expect("Could not find Rust source root");
519 let rust_pp_module_rel_path
= Path
::new("./src/etc");
520 let rust_pp_module_abs_path
= rust_src_root
.join(rust_pp_module_rel_path
)
524 // write debugger script
525 let mut script_str
= String
::with_capacity(2048);
527 script_str
.push_str("set charset UTF-8\n");
528 script_str
.push_str("show version\n");
530 match config
.gdb_version
{
531 Some(ref version
) => {
532 println
!("NOTE: compiletest thinks it is using GDB version {}",
535 if header
::gdb_version_to_int(version
) >
536 header
::gdb_version_to_int("7.4") {
537 // Add the directory containing the pretty printers to
538 // GDB's script auto loading safe path
540 &format
!("add-auto-load-safe-path {}\n",
541 rust_pp_module_abs_path
.replace("\\", "\\\\"))
546 println
!("NOTE: compiletest does not know which version of \
551 // The following line actually doesn't have to do anything with
552 // pretty printing, it just tells GDB to print values on one line:
553 script_str
.push_str("set print pretty off\n");
555 // Add the pretty printer directory to GDB's source-file search path
556 script_str
.push_str(&format
!("directory {}\n", rust_pp_module_abs_path
)[]);
558 // Load the target executable
559 script_str
.push_str(&format
!("file {}\n",
560 exe_file
.as_str().unwrap().replace("\\", "\\\\"))[]);
562 // Add line breakpoints
563 for line
in &breakpoint_lines
{
564 script_str
.push_str(&format
!("break '{}':{}\n",
565 testfile
.filename_display(),
569 script_str
.push_str(&cmds
);
570 script_str
.push_str("quit\n");
572 debug
!("script_str = {}", script_str
);
573 dump_output_file(config
,
578 // run debugger script with gdb
580 fn debugger() -> String
{
581 "gdb.exe".to_string()
584 fn debugger() -> String
{
588 let debugger_script
= make_out_name(config
, testfile
, "debugger.script");
590 // FIXME (#9639): This needs to handle non-utf8 paths
592 vec
!("-quiet".to_string(),
593 "-batch".to_string(),
595 format
!("-command={}", debugger_script
.as_str().unwrap()));
597 let proc_args
= ProcArgs
{
602 let environment
= vec
![("PYTHONPATH".to_string(), rust_pp_module_abs_path
)];
604 debugger_run_result
= compose_and_run(config
,
608 &config
.run_lib_path
,
614 if !debugger_run_result
.status
.success() {
615 fatal("gdb failed to execute");
618 check_debugger_output(&debugger_run_result
, &check_lines
);
621 fn find_rust_src_root(config
: &Config
) -> Option
<Path
> {
622 let mut path
= config
.src_base
.clone();
623 let path_postfix
= Path
::new("src/etc/lldb_batchmode.py");
626 if path
.join(&path_postfix
).is_file() {
634 fn run_debuginfo_lldb_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) {
635 use std
::old_io
::process
::{Command, ProcessOutput}
;
637 if config
.lldb_python_dir
.is_none() {
638 fatal("Can't run LLDB test because LLDB's python path is not set.");
641 let mut config
= Config
{
642 target_rustcflags
: cleanup_debug_info_options(&config
.target_rustcflags
),
643 host_rustcflags
: cleanup_debug_info_options(&config
.host_rustcflags
),
647 let config
= &mut config
;
649 // compile test file (it should have 'compile-flags:-g' in the header)
650 let compile_result
= compile_test(config
, props
, testfile
);
651 if !compile_result
.status
.success() {
652 fatal_proc_rec("compilation failed!", &compile_result
);
655 let exe_file
= make_exe_name(config
, testfile
);
657 match config
.lldb_version
{
658 Some(ref version
) => {
659 println
!("NOTE: compiletest thinks it is using LLDB version {}",
663 println
!("NOTE: compiletest does not know which version of \
668 // Parse debugger commands etc from test files
669 let DebuggerCommands
{
674 } = parse_debugger_commands(testfile
, "lldb");
676 // Write debugger script:
677 // We don't want to hang when calling `quit` while the process is still running
678 let mut script_str
= String
::from_str("settings set auto-confirm true\n");
680 // Make LLDB emit its version, so we have it documented in the test output
681 script_str
.push_str("version\n");
683 // Switch LLDB into "Rust mode"
684 let rust_src_root
= find_rust_src_root(config
)
685 .expect("Could not find Rust source root");
686 let rust_pp_module_rel_path
= Path
::new("./src/etc/lldb_rust_formatters.py");
687 let rust_pp_module_abs_path
= rust_src_root
.join(rust_pp_module_rel_path
)
692 script_str
.push_str(&format
!("command script import {}\n", &rust_pp_module_abs_path
[..])[]);
693 script_str
.push_str("type summary add --no-value ");
694 script_str
.push_str("--python-function lldb_rust_formatters.print_val ");
695 script_str
.push_str("-x \".*\" --category Rust\n");
696 script_str
.push_str("type category enable Rust\n");
698 // Set breakpoints on every line that contains the string "#break"
699 for line
in &breakpoint_lines
{
700 script_str
.push_str(&format
!("breakpoint set --line {}\n", line
));
703 // Append the other commands
704 for line
in &commands
{
705 script_str
.push_str(line
);
706 script_str
.push_str("\n");
709 // Finally, quit the debugger
710 script_str
.push_str("quit\n");
712 // Write the script into a file
713 debug
!("script_str = {}", script_str
);
714 dump_output_file(config
,
718 let debugger_script
= make_out_name(config
, testfile
, "debugger.script");
720 // Let LLDB execute the script via lldb_batchmode.py
721 let debugger_run_result
= run_lldb(config
,
726 if !debugger_run_result
.status
.success() {
727 fatal_proc_rec("Error while running LLDB", &debugger_run_result
);
730 check_debugger_output(&debugger_run_result
, &check_lines
);
732 fn run_lldb(config
: &Config
,
733 test_executable
: &Path
,
734 debugger_script
: &Path
,
735 rust_src_root
: &Path
)
737 // Prepare the lldb_batchmode which executes the debugger script
738 let lldb_script_path
= rust_src_root
.join(Path
::new("./src/etc/lldb_batchmode.py"));
740 let mut cmd
= Command
::new("python");
741 cmd
.arg(lldb_script_path
)
742 .arg(test_executable
)
743 .arg(debugger_script
)
744 .env_set_all(&[("PYTHONPATH", config
.lldb_python_dir
.clone().unwrap())]);
746 let (status
, out
, err
) = match cmd
.spawn() {
748 let ProcessOutput { status, output, error }
=
749 process
.wait_with_output().unwrap();
752 String
::from_utf8(output
).unwrap(),
753 String
::from_utf8(error
).unwrap())
756 fatal(&format
!("Failed to setup Python process for \
757 LLDB script: {}", e
))
761 dump_output(config
, test_executable
, &out
, &err
);
766 cmdline
: format
!("{:?}", cmd
)
771 struct DebuggerCommands
{
772 commands
: Vec
<String
>,
773 check_lines
: Vec
<String
>,
774 breakpoint_lines
: Vec
<uint
>,
777 fn parse_debugger_commands(file_path
: &Path
, debugger_prefix
: &str)
778 -> DebuggerCommands
{
779 use std
::old_io
::{BufferedReader, File}
;
781 let command_directive
= format
!("{}-command", debugger_prefix
);
782 let check_directive
= format
!("{}-check", debugger_prefix
);
784 let mut breakpoint_lines
= vec
!();
785 let mut commands
= vec
!();
786 let mut check_lines
= vec
!();
788 let mut reader
= BufferedReader
::new(File
::open(file_path
).unwrap());
789 for line
in reader
.lines() {
792 if line
.contains("#break") {
793 breakpoint_lines
.push(counter
);
796 header
::parse_name_value_directive(
798 &command_directive
).map(|cmd
| {
802 header
::parse_name_value_directive(
804 &check_directive
).map(|cmd
| {
805 check_lines
.push(cmd
)
809 fatal(&format
!("Error while parsing debugger commands: {}", e
))
817 check_lines
: check_lines
,
818 breakpoint_lines
: breakpoint_lines
,
822 fn cleanup_debug_info_options(options
: &Option
<String
>) -> Option
<String
> {
823 if options
.is_none() {
827 // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
828 let options_to_remove
= [
831 "--debuginfo".to_string()
834 split_maybe_args(options
).into_iter()
835 .filter(|x
| !options_to_remove
.contains(x
))
836 .collect
::<Vec
<String
>>()
841 fn check_debugger_output(debugger_run_result
: &ProcRes
, check_lines
: &[String
]) {
842 let num_check_lines
= check_lines
.len();
843 if num_check_lines
> 0 {
844 // Allow check lines to leave parts unspecified (e.g., uninitialized
845 // bits in the wrong case of an enum) with the notation "[...]".
846 let check_fragments
: Vec
<Vec
<String
>> =
847 check_lines
.iter().map(|s
| {
851 .map(|x
| x
.to_string())
854 // check if each line in props.check_lines appears in the
857 for line
in debugger_run_result
.stdout
.lines() {
858 let mut rest
= line
.trim();
859 let mut first
= true;
860 let mut failed
= false;
861 for frag
in &check_fragments
[i
] {
862 let found
= if first
{
863 if rest
.starts_with(frag
) {
877 rest
= &rest
[(i
+ frag
.len())..];
882 if !failed
&& rest
.len() == 0 {
885 if i
== num_check_lines
{
890 if i
!= num_check_lines
{
891 fatal_proc_rec(&format
!("line not found in debugger output: {}",
892 check_lines
.get(i
).unwrap()),
893 debugger_run_result
);
898 fn check_error_patterns(props
: &TestProps
,
900 output_to_check
: &str,
901 proc_res
: &ProcRes
) {
902 if props
.error_patterns
.is_empty() {
903 fatal(&format
!("no error pattern specified in {:?}", testfile
.display()));
905 let mut next_err_idx
= 0;
906 let mut next_err_pat
= &props
.error_patterns
[next_err_idx
];
907 let mut done
= false;
908 for line
in output_to_check
.lines() {
909 if line
.contains(next_err_pat
) {
910 debug
!("found error pattern {}", next_err_pat
);
912 if next_err_idx
== props
.error_patterns
.len() {
913 debug
!("found all error patterns");
917 next_err_pat
= &props
.error_patterns
[next_err_idx
];
922 let missing_patterns
= &props
.error_patterns
[next_err_idx
..];
923 if missing_patterns
.len() == 1 {
924 fatal_proc_rec(&format
!("error pattern '{}' not found!", missing_patterns
[0]),
927 for pattern
in missing_patterns
{
928 error(&format
!("error pattern '{}' not found!", *pattern
));
930 fatal_proc_rec("multiple error patterns not found", proc_res
);
934 fn check_no_compiler_crash(proc_res
: &ProcRes
) {
935 for line
in proc_res
.stderr
.lines() {
936 if line
.starts_with("error: internal compiler error:") {
937 fatal_proc_rec("compiler encountered internal error",
943 fn check_forbid_output(props
: &TestProps
,
944 output_to_check
: &str,
945 proc_res
: &ProcRes
) {
946 for pat
in &props
.forbid_output
{
947 if output_to_check
.contains(pat
) {
948 fatal_proc_rec("forbidden pattern found in compiler output", proc_res
);
953 fn check_expected_errors(expected_errors
: Vec
<errors
::ExpectedError
> ,
955 proc_res
: &ProcRes
) {
957 // true if we found the error in question
958 let mut found_flags
: Vec
<_
> = repeat(false).take(expected_errors
.len()).collect();
960 if proc_res
.status
.success() {
961 fatal("process did not return an error status");
964 let prefixes
= expected_errors
.iter().map(|ee
| {
965 format
!("{}:{}:", testfile
.display(), ee
.line
)
966 }).collect
::<Vec
<String
> >();
969 fn prefix_matches( line
: &str, prefix
: &str ) -> bool
{
970 line
.to_ascii_lowercase().starts_with(&prefix
.to_ascii_lowercase())
974 fn prefix_matches( line
: &str, prefix
: &str ) -> bool
{
975 line
.starts_with( prefix
)
978 // A multi-line error will have followup lines which will always
979 // start with one of these strings.
980 fn continuation( line
: &str) -> bool
{
981 line
.starts_with(" expected") ||
982 line
.starts_with(" found") ||
984 // Should have 4 spaces: see issue 18946
985 line
.starts_with("(")
988 // Scan and extract our error/warning messages,
990 // filename:line1:col1: line2:col2: *error:* msg
991 // filename:line1:col1: line2:col2: *warning:* msg
992 // where line1:col1: is the starting point, line2:col2:
993 // is the ending point, and * represents ANSI color codes.
994 for line
in proc_res
.stderr
.lines() {
995 let mut was_expected
= false;
996 for (i
, ee
) in expected_errors
.iter().enumerate() {
998 debug
!("prefix={} ee.kind={} ee.msg={} line={}",
1003 if (prefix_matches(line
, &prefixes
[i
]) || continuation(line
)) &&
1004 line
.contains(&ee
.kind
) &&
1005 line
.contains(&ee
.msg
) {
1006 found_flags
[i
] = true;
1007 was_expected
= true;
1013 // ignore this msg which gets printed at the end
1014 if line
.contains("aborting due to") {
1015 was_expected
= true;
1018 if !was_expected
&& is_compiler_error_or_warning(line
) {
1019 fatal_proc_rec(&format
!("unexpected compiler error or warning: '{}'",
1025 for (i
, &flag
) in found_flags
.iter().enumerate() {
1027 let ee
= &expected_errors
[i
];
1028 fatal_proc_rec(&format
!("expected {} on line {} not found: {}",
1029 ee
.kind
, ee
.line
, ee
.msg
),
1035 fn is_compiler_error_or_warning(line
: &str) -> bool
{
1038 scan_until_char(line
, '
:'
, &mut i
) &&
1039 scan_char(line
, '
:'
, &mut i
) &&
1040 scan_integer(line
, &mut i
) &&
1041 scan_char(line
, '
:'
, &mut i
) &&
1042 scan_integer(line
, &mut i
) &&
1043 scan_char(line
, '
:'
, &mut i
) &&
1044 scan_char(line
, ' '
, &mut i
) &&
1045 scan_integer(line
, &mut i
) &&
1046 scan_char(line
, '
:'
, &mut i
) &&
1047 scan_integer(line
, &mut i
) &&
1048 scan_char(line
, ' '
, &mut i
) &&
1049 (scan_string(line
, "error", &mut i
) ||
1050 scan_string(line
, "warning", &mut i
));
1053 fn scan_until_char(haystack
: &str, needle
: char, idx
: &mut uint
) -> bool
{
1054 if *idx
>= haystack
.len() {
1057 let opt
= haystack
[(*idx
)..].find(needle
);
1061 *idx
= opt
.unwrap();
1065 fn scan_char(haystack
: &str, needle
: char, idx
: &mut uint
) -> bool
{
1066 if *idx
>= haystack
.len() {
1069 let range
= haystack
.char_range_at(*idx
);
1070 if range
.ch
!= needle
{
1077 fn scan_integer(haystack
: &str, idx
: &mut uint
) -> bool
{
1079 while i
< haystack
.len() {
1080 let range
= haystack
.char_range_at(i
);
1081 if range
.ch
< '
0'
|| '
9'
< range
.ch
{
1093 fn scan_string(haystack
: &str, needle
: &str, idx
: &mut uint
) -> bool
{
1094 let mut haystack_i
= *idx
;
1095 let mut needle_i
= 0;
1096 while needle_i
< needle
.len() {
1097 if haystack_i
>= haystack
.len() {
1100 let range
= haystack
.char_range_at(haystack_i
);
1101 haystack_i
= range
.next
;
1102 if !scan_char(needle
, range
.ch
, &mut needle_i
) {
1116 status
: ProcessExit
,
1122 fn compile_test(config
: &Config
, props
: &TestProps
,
1123 testfile
: &Path
) -> ProcRes
{
1124 compile_test_(config
, props
, testfile
, &[])
1127 fn jit_test(config
: &Config
, props
: &TestProps
, testfile
: &Path
) -> ProcRes
{
1128 compile_test_(config
, props
, testfile
, &["--jit".to_string()])
1131 fn compile_test_(config
: &Config
, props
: &TestProps
,
1132 testfile
: &Path
, extra_args
: &[String
]) -> ProcRes
{
1133 let aux_dir
= aux_output_dir_name(config
, testfile
);
1134 // FIXME (#9639): This needs to handle non-utf8 paths
1135 let mut link_args
= vec
!("-L".to_string(),
1136 aux_dir
.as_str().unwrap().to_string());
1137 link_args
.extend(extra_args
.iter().cloned());
1138 let args
= make_compile_args(config
,
1141 |a
, b
| TargetLocation
::ThisFile(make_exe_name(a
, b
)), testfile
);
1142 compose_and_run_compiler(config
, props
, testfile
, args
, None
)
1145 fn exec_compiled_test(config
: &Config
, props
: &TestProps
,
1146 testfile
: &Path
) -> ProcRes
{
1148 let env
= props
.exec_env
.clone();
1150 match &*config
.target
{
1152 "arm-linux-androideabi" | "aarch64-linux-android" => {
1153 _arm_exec_compiled_test(config
, props
, testfile
, env
)
1157 let aux_dir
= aux_output_dir_name(config
, testfile
);
1158 compose_and_run(config
,
1160 make_run_args(config
, props
, testfile
),
1162 &config
.run_lib_path
,
1163 Some(aux_dir
.as_str().unwrap()),
1169 fn compose_and_run_compiler(
1174 input
: Option
<String
>) -> ProcRes
{
1176 if !props
.aux_builds
.is_empty() {
1177 ensure_dir(&aux_output_dir_name(config
, testfile
));
1180 let aux_dir
= aux_output_dir_name(config
, testfile
);
1181 // FIXME (#9639): This needs to handle non-utf8 paths
1182 let extra_link_args
= vec
!("-L".to_string(), aux_dir
.as_str().unwrap().to_string());
1184 for rel_ab
in &props
.aux_builds
{
1185 let abs_ab
= config
.aux_base
.join(rel_ab
);
1186 let aux_props
= header
::load_props(&abs_ab
);
1187 let mut crate_type
= if aux_props
.no_prefer_dynamic
{
1190 vec
!("--crate-type=dylib".to_string())
1192 crate_type
.extend(extra_link_args
.clone().into_iter());
1194 make_compile_args(config
,
1198 let f
= make_lib_name(a
, b
, testfile
);
1199 TargetLocation
::ThisDirectory(f
.dir_path())
1202 let auxres
= compose_and_run(config
,
1206 &config
.compile_lib_path
,
1207 Some(aux_dir
.as_str().unwrap()),
1209 if !auxres
.status
.success() {
1211 &format
!("auxiliary build of {:?} failed to compile: ",
1216 match &*config
.target
{
1217 "arm-linux-androideabi" | "aarch64-linux-android" => {
1218 _arm_push_aux_shared_library(config
, testfile
);
1224 compose_and_run(config
,
1228 &config
.compile_lib_path
,
1229 Some(aux_dir
.as_str().unwrap()),
1233 fn ensure_dir(path
: &Path
) {
1234 if path
.is_dir() { return; }
1235 fs
::mkdir(path
, old_io
::USER_RWX
).unwrap();
1238 fn compose_and_run(config
: &Config
, testfile
: &Path
,
1239 ProcArgs{ args, prog }
: ProcArgs
,
1240 procenv
: Vec
<(String
, String
)> ,
1242 aux_path
: Option
<&str>,
1243 input
: Option
<String
>) -> ProcRes
{
1244 return program_output(config
, testfile
, lib_path
,
1245 prog
, aux_path
, args
, procenv
, input
);
1248 enum TargetLocation
{
1250 ThisDirectory(Path
),
1253 fn make_compile_args
<F
>(config
: &Config
,
1255 extras
: Vec
<String
> ,
1259 F
: FnOnce(&Config
, &Path
) -> TargetLocation
,
1261 let xform_file
= xform(config
, testfile
);
1262 let target
= if props
.force_host
{
1267 // FIXME (#9639): This needs to handle non-utf8 paths
1268 let mut args
= vec
!(testfile
.as_str().unwrap().to_string(),
1270 config
.build_base
.as_str().unwrap().to_string(),
1271 format
!("--target={}", target
));
1272 args
.push_all(&extras
);
1273 if !props
.no_prefer_dynamic
{
1274 args
.push("-C".to_string());
1275 args
.push("prefer-dynamic".to_string());
1277 let path
= match xform_file
{
1278 TargetLocation
::ThisFile(path
) => {
1279 args
.push("-o".to_string());
1282 TargetLocation
::ThisDirectory(path
) => {
1283 args
.push("--out-dir".to_string());
1287 args
.push(path
.as_str().unwrap().to_string());
1288 if props
.force_host
{
1289 args
.extend(split_maybe_args(&config
.host_rustcflags
).into_iter());
1291 args
.extend(split_maybe_args(&config
.target_rustcflags
).into_iter());
1293 args
.extend(split_maybe_args(&props
.compile_flags
).into_iter());
1295 prog
: config
.rustc_path
.as_str().unwrap().to_string(),
1300 fn make_lib_name(config
: &Config
, auxfile
: &Path
, testfile
: &Path
) -> Path
{
1301 // what we return here is not particularly important, as it
1302 // happens; rustc ignores everything except for the directory.
1303 let auxname
= output_testname(auxfile
);
1304 aux_output_dir_name(config
, testfile
).join(&auxname
)
1307 fn make_exe_name(config
: &Config
, testfile
: &Path
) -> Path
{
1308 let mut f
= output_base_name(config
, testfile
);
1309 if !env
::consts
::EXE_SUFFIX
.is_empty() {
1310 let mut fname
= f
.filename().unwrap().to_vec();
1311 fname
.extend(env
::consts
::EXE_SUFFIX
.bytes());
1312 f
.set_filename(fname
);
1317 fn make_run_args(config
: &Config
, props
: &TestProps
, testfile
: &Path
) ->
1319 // If we've got another tool to run under (valgrind),
1320 // then split apart its command
1321 let mut args
= split_maybe_args(&config
.runtool
);
1322 let exe_file
= make_exe_name(config
, testfile
);
1324 // FIXME (#9639): This needs to handle non-utf8 paths
1325 args
.push(exe_file
.as_str().unwrap().to_string());
1327 // Add the arguments in the run_flags directive
1328 args
.extend(split_maybe_args(&props
.run_flags
).into_iter());
1330 let prog
= args
.remove(0);
1337 fn split_maybe_args(argstr
: &Option
<String
>) -> Vec
<String
> {
1343 if s
.chars().all(|c
| c
.is_whitespace()) {
1354 fn program_output(config
: &Config
, testfile
: &Path
, lib_path
: &str, prog
: String
,
1355 aux_path
: Option
<&str>, args
: Vec
<String
>,
1356 env
: Vec
<(String
, String
)>,
1357 input
: Option
<String
>) -> ProcRes
{
1360 let cmdline
= make_cmdline(lib_path
,
1363 logv(config
, format
!("executing {}", cmdline
));
1366 let procsrv
::Result
{
1370 } = procsrv
::run(lib_path
,
1375 input
).expect(&format
!("failed to exec `{}`", prog
));
1376 dump_output(config
, testfile
, &out
, &err
);
1385 // Linux and mac don't require adjusting the library search path
1387 fn make_cmdline(_libpath
: &str, prog
: &str, args
: &[String
]) -> String
{
1388 format
!("{} {}", prog
, args
.connect(" "))
1392 fn make_cmdline(libpath
: &str, prog
: &str, args
: &[String
]) -> String
{
1394 // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1395 // for diagnostic purposes
1396 fn lib_path_cmd_prefix(path
: &str) -> String
{
1397 format
!("{}=\"{}\"", util
::lib_path_env_var(), util
::make_new_path(path
))
1400 format
!("{} {} {}", lib_path_cmd_prefix(libpath
), prog
, args
.connect(" "))
1403 fn dump_output(config
: &Config
, testfile
: &Path
, out
: &str, err
: &str) {
1404 dump_output_file(config
, testfile
, out
, "out");
1405 dump_output_file(config
, testfile
, err
, "err");
1406 maybe_dump_to_stdout(config
, out
, err
);
1409 fn dump_output_file(config
: &Config
, testfile
: &Path
,
1410 out
: &str, extension
: &str) {
1411 let outfile
= make_out_name(config
, testfile
, extension
);
1412 File
::create(&outfile
).write_all(out
.as_bytes()).unwrap();
1415 fn make_out_name(config
: &Config
, testfile
: &Path
, extension
: &str) -> Path
{
1416 output_base_name(config
, testfile
).with_extension(extension
)
1419 fn aux_output_dir_name(config
: &Config
, testfile
: &Path
) -> Path
{
1420 let f
= output_base_name(config
, testfile
);
1421 let mut fname
= f
.filename().unwrap().to_vec();
1422 fname
.extend("libaux".bytes());
1423 f
.with_filename(fname
)
1426 fn output_testname(testfile
: &Path
) -> Path
{
1427 Path
::new(testfile
.filestem().unwrap())
1430 fn output_base_name(config
: &Config
, testfile
: &Path
) -> Path
{
1432 .join(&output_testname(testfile
))
1433 .with_extension(&config
.stage_id
)
1436 fn maybe_dump_to_stdout(config
: &Config
, out
: &str, err
: &str) {
1438 println
!("------{}------------------------------", "stdout");
1439 println
!("{}", out
);
1440 println
!("------{}------------------------------", "stderr");
1441 println
!("{}", err
);
1442 println
!("------------------------------------------");
1446 fn error(err
: &str) { println!("\nerror: {}
", err); }
1448 fn fatal(err: &str) -> ! { error(err); panic!(); }
1450 fn fatal_proc_rec(err: &str, proc_res: &ProcRes) -> ! {
1456 ------------------------------------------\n\
1458 ------------------------------------------\n\
1460 ------------------------------------------\n\
1462 ------------------------------------------\n\
1464 err, proc_res.status, proc_res.cmdline, proc_res.stdout,
1469 fn _arm_exec_compiled_test(config: &Config,
1472 env: Vec<(String, String)>)
1474 let args = make_run_args(config, props, testfile);
1475 let cmdline = make_cmdline("",
1479 // get bare program string
1480 let mut tvec: Vec<String> = args.prog
1482 .map(|ts| ts.to_string())
1484 let prog_short = tvec.pop().unwrap();
1487 let copy_result = procsrv::run("",
1493 config.adb_test_dir.clone()
1495 vec!(("".to_string(), "".to_string())),
1496 Some("".to_string()))
1497 .expect(&format!("failed to exec `{}`
", config.adb_path));
1500 println!("push ({}
) {} {} {}
",
1507 logv(config, format!("executing ({}
) {}
", config.target, cmdline));
1509 let mut runargs = Vec::new();
1511 // run test via adb_run_wrapper
1512 runargs.push("shell
".to_string());
1513 for (key, val) in env {
1514 runargs.push(format!("{}
={}
", key, val));
1516 runargs.push(format!("{}
/../adb_run_wrapper
.sh
", config.adb_test_dir));
1517 runargs.push(format!("{}
", config.adb_test_dir));
1518 runargs.push(format!("{}
", prog_short));
1520 for tv in &args.args {
1521 runargs.push(tv.to_string());
1527 vec!(("".to_string(), "".to_string())), Some("".to_string()))
1528 .expect(&format!("failed to exec `{}`
", config.adb_path));
1530 // get exitcode of result
1531 runargs = Vec::new();
1532 runargs.push("shell
".to_string());
1533 runargs.push("cat
".to_string());
1534 runargs.push(format!("{}
/{}
.exitcode
", config.adb_test_dir, prog_short));
1536 let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
1541 vec!(("".to_string(), "".to_string())),
1542 Some("".to_string()))
1543 .expect(&format!("failed to exec `{}`
", config.adb_path));
1545 let mut exitcode: int = 0;
1546 for c in exitcode_out.chars() {
1547 if !c.is_numeric() { break; }
1548 exitcode = exitcode * 10 + match c {
1549 '0' ... '9' => c as int - ('0' as int),
1554 // get stdout of result
1555 runargs = Vec::new();
1556 runargs.push("shell
".to_string());
1557 runargs.push("cat
".to_string());
1558 runargs.push(format!("{}
/{}
.stdout
", config.adb_test_dir, prog_short));
1560 let procsrv::Result{ out: stdout_out, err: _, status: _ } =
1565 vec!(("".to_string(), "".to_string())),
1566 Some("".to_string()))
1567 .expect(&format!("failed to exec `{}`
", config.adb_path));
1569 // get stderr of result
1570 runargs = Vec::new();
1571 runargs.push("shell
".to_string());
1572 runargs.push("cat
".to_string());
1573 runargs.push(format!("{}
/{}
.stderr
", config.adb_test_dir, prog_short));
1575 let procsrv::Result{ out: stderr_out, err: _, status: _ } =
1580 vec!(("".to_string(), "".to_string())),
1581 Some("".to_string()))
1582 .expect(&format!("failed to exec `{}`
", config.adb_path));
1590 status: process::ProcessExit::ExitStatus(exitcode),
1597 fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
1598 let tdir = aux_output_dir_name(config, testfile);
1600 let dirs = fs::readdir(&tdir).unwrap();
1602 if file.extension_str() == Some("so
") {
1603 // FIXME (#9639): This needs to handle non-utf8 paths
1604 let copy_result = procsrv::run("",
1612 config.adb_test_dir.to_string(),
1614 vec!(("".to_string(),
1616 Some("".to_string()))
1617 .expect(&format!("failed to exec `{}`
", config.adb_path));
1620 println!("push ({}
) {:?} {} {}
",
1621 config.target, file.display(),
1622 copy_result.out, copy_result.err);
1628 // codegen tests (vs. clang)
1630 fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path {
1631 if suffix.len() == 0 {
1634 let mut stem = p.filestem().unwrap().to_vec();
1635 stem.extend("-".bytes());
1636 stem.extend(suffix.bytes());
1637 p.with_filename(stem)
1641 fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
1642 testfile: &Path) -> ProcRes {
1643 let aux_dir = aux_output_dir_name(config, testfile);
1644 // FIXME (#9639): This needs to handle non-utf8 paths
1645 let mut link_args = vec!("-L
".to_string(),
1646 aux_dir.as_str().unwrap().to_string());
1647 let llvm_args = vec!("--emit
=llvm
-bc
,obj
".to_string(),
1648 "--crate-type=lib
".to_string());
1649 link_args.extend(llvm_args.into_iter());
1650 let args = make_compile_args(config,
1653 |a, b| TargetLocation::ThisDirectory(
1654 output_base_name(a, b).dir_path()),
1656 compose_and_run_compiler(config, props, testfile, args, None)
1659 fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
1660 testfile: &Path) -> ProcRes {
1661 let bitcodefile = output_base_name(config, testfile).with_extension("bc
");
1662 let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang
");
1663 let testcc = testfile.with_extension("cc
");
1664 let proc_args = ProcArgs {
1665 // FIXME (#9639): This needs to handle non-utf8 paths
1666 prog: config.clang_path.as_ref().unwrap().as_str().unwrap().to_string(),
1667 args: vec!("-c
".to_string(),
1668 "-emit
-llvm
".to_string(),
1670 bitcodefile.as_str().unwrap().to_string(),
1671 testcc.as_str().unwrap().to_string())
1673 compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
1676 fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
1677 fname: &str, testfile: &Path,
1678 suffix: &str) -> ProcRes {
1679 let bitcodefile = output_base_name(config, testfile).with_extension("bc
");
1680 let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
1681 let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract
");
1682 let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm
-extract
");
1683 let proc_args = ProcArgs {
1684 // FIXME (#9639): This needs to handle non-utf8 paths
1685 prog: prog.as_str().unwrap().to_string(),
1686 args: vec!(format!("-func
={}
", fname),
1687 format!("-o
={}
", extracted_bc.as_str().unwrap()),
1688 bitcodefile.as_str().unwrap().to_string())
1690 compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
1693 fn disassemble_extract(config: &Config, _props: &TestProps,
1694 testfile: &Path, suffix: &str) -> ProcRes {
1695 let bitcodefile = output_base_name(config, testfile).with_extension("bc
");
1696 let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
1697 let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract
");
1698 let extracted_ll = extracted_bc.with_extension("ll
");
1699 let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm
-dis
");
1700 let proc_args = ProcArgs {
1701 // FIXME (#9639): This needs to handle non-utf8 paths
1702 prog: prog.as_str().unwrap().to_string(),
1703 args: vec!(format!("-o
={}
", extracted_ll.as_str().unwrap()),
1704 extracted_bc.as_str().unwrap().to_string())
1706 compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
1710 fn count_extracted_lines(p: &Path) -> uint {
1711 let x = File::open(&p.with_extension("ll
")).read_to_end().unwrap();
1712 let x = str::from_utf8(&x).unwrap();
1717 fn run_codegen_test(config: &Config, props: &TestProps,
1718 testfile: &Path, mm: &mut MetricMap) {
1720 if config.llvm_bin_path.is_none() {
1721 fatal("missing
--llvm
-bin
-path
");
1724 if config.clang_path.is_none() {
1725 fatal("missing
--clang
-path
");
1728 let mut proc_res = compile_test_and_save_bitcode(config, props, testfile);
1729 if !proc_res.status.success() {
1730 fatal_proc_rec("compilation failed
!", &proc_res);
1733 proc_res = extract_function_from_bitcode(config, props, "test
", testfile, "");
1734 if !proc_res.status.success() {
1735 fatal_proc_rec("extracting 'test' function failed
",
1739 proc_res = disassemble_extract(config, props, testfile, "");
1740 if !proc_res.status.success() {
1741 fatal_proc_rec("disassembling extract failed
", &proc_res);
1745 let mut proc_res = compile_cc_with_clang_and_save_bitcode(config, props, testfile);
1746 if !proc_res.status.success() {
1747 fatal_proc_rec("compilation failed
!", &proc_res);
1750 proc_res = extract_function_from_bitcode(config, props, "test
", testfile, "clang
");
1751 if !proc_res.status.success() {
1752 fatal_proc_rec("extracting 'test' function failed
",
1756 proc_res = disassemble_extract(config, props, testfile, "clang
");
1757 if !proc_res.status.success() {
1758 fatal_proc_rec("disassembling extract failed
", &proc_res);
1761 let base = output_base_name(config, testfile);
1762 let base_extract = append_suffix_to_stem(&base, "extract
");
1764 let base_clang = append_suffix_to_stem(&base, "clang
");
1765 let base_clang_extract = append_suffix_to_stem(&base_clang, "extract
");
1767 let base_lines = count_extracted_lines(&base_extract);
1768 let clang_lines = count_extracted_lines(&base_clang_extract);
1770 mm.insert_metric("clang
-codegen
-ratio
",
1771 (base_lines as f64) / (clang_lines as f64),