mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 13:04:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1213 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			1213 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::build;
 | |
| use crate::config::{Channel, ConfigInfo};
 | |
| use crate::utils::{
 | |
|     get_toolchain, git_clone, git_clone_root_dir, remove_file, run_command, run_command_with_env,
 | |
|     run_command_with_output_and_env, rustc_version_info, split_args, walk_dir,
 | |
| };
 | |
| 
 | |
| use std::collections::{BTreeSet, HashMap};
 | |
| use std::ffi::OsStr;
 | |
| use std::fs::{create_dir_all, remove_dir_all, File};
 | |
| use std::io::{BufRead, BufReader};
 | |
| use std::path::{Path, PathBuf};
 | |
| use std::str::FromStr;
 | |
| 
 | |
| type Env = HashMap<String, String>;
 | |
| type Runner = fn(&Env, &TestArg) -> Result<(), String>;
 | |
| type Runners = HashMap<&'static str, (&'static str, Runner)>;
 | |
| 
 | |
| fn get_runners() -> Runners {
 | |
|     let mut runners = HashMap::new();
 | |
| 
 | |
|     runners.insert(
 | |
|         "--test-rustc",
 | |
|         ("Run all rustc tests", test_rustc as Runner),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--test-successful-rustc",
 | |
|         ("Run successful rustc tests", test_successful_rustc),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--test-failing-rustc",
 | |
|         ("Run failing rustc tests", test_failing_rustc),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--projects",
 | |
|         ("Run the tests of popular crates", test_projects),
 | |
|     );
 | |
|     runners.insert("--test-libcore", ("Run libcore tests", test_libcore));
 | |
|     runners.insert("--clean", ("Empty cargo target directory", clean));
 | |
|     runners.insert("--build-sysroot", ("Build sysroot", build_sysroot));
 | |
|     runners.insert("--std-tests", ("Run std tests", std_tests));
 | |
|     runners.insert("--asm-tests", ("Run asm tests", asm_tests));
 | |
|     runners.insert(
 | |
|         "--extended-tests",
 | |
|         ("Run extended sysroot tests", extended_sysroot_tests),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--extended-rand-tests",
 | |
|         ("Run extended rand tests", extended_rand_tests),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--extended-regex-example-tests",
 | |
|         (
 | |
|             "Run extended regex example tests",
 | |
|             extended_regex_example_tests,
 | |
|         ),
 | |
|     );
 | |
|     runners.insert(
 | |
|         "--extended-regex-tests",
 | |
|         ("Run extended regex tests", extended_regex_tests),
 | |
|     );
 | |
|     runners.insert("--mini-tests", ("Run mini tests", mini_tests));
 | |
| 
 | |
|     runners
 | |
| }
 | |
| 
 | |
| fn get_number_after_arg(
 | |
|     args: &mut impl Iterator<Item = String>,
 | |
|     option: &str,
 | |
| ) -> Result<usize, String> {
 | |
|     match args.next() {
 | |
|         Some(nb) if !nb.is_empty() => match usize::from_str(&nb) {
 | |
|             Ok(nb) => Ok(nb),
 | |
|             Err(_) => Err(format!(
 | |
|                 "Expected a number after `{}`, found `{}`",
 | |
|                 option, nb
 | |
|             )),
 | |
|         },
 | |
|         _ => Err(format!(
 | |
|             "Expected a number after `{}`, found nothing",
 | |
|             option
 | |
|         )),
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn show_usage() {
 | |
|     println!(
 | |
|         r#"
 | |
| `test` command help:
 | |
| 
 | |
|     --release              : Build codegen in release mode
 | |
|     --sysroot-panic-abort  : Build the sysroot without unwinding support.
 | |
|     --features [arg]       : Add a new feature [arg]
 | |
|     --use-system-gcc       : Use system installed libgccjit
 | |
|     --build-only           : Only build rustc_codegen_gcc then exits
 | |
|     --nb-parts             : Used to split rustc_tests (for CI needs)
 | |
|     --current-part         : Used with `--nb-parts`, allows you to specify which parts to test"#
 | |
|     );
 | |
|     ConfigInfo::show_usage();
 | |
|     for (option, (doc, _)) in get_runners() {
 | |
|         // FIXME: Instead of using the hard-coded `23` value, better to compute it instead.
 | |
|         let needed_spaces = 23_usize.saturating_sub(option.len());
 | |
|         let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect();
 | |
|         println!("    {}{}: {}", option, spaces, doc);
 | |
|     }
 | |
|     println!("    --help                 : Show this help");
 | |
| }
 | |
| 
 | |
| #[derive(Default, Debug)]
 | |
| struct TestArg {
 | |
|     build_only: bool,
 | |
|     use_system_gcc: bool,
 | |
|     runners: BTreeSet<String>,
 | |
|     flags: Vec<String>,
 | |
|     nb_parts: Option<usize>,
 | |
|     current_part: Option<usize>,
 | |
|     sysroot_panic_abort: bool,
 | |
|     config_info: ConfigInfo,
 | |
| }
 | |
| 
 | |
| impl TestArg {
 | |
|     fn new() -> Result<Option<Self>, String> {
 | |
|         let mut test_arg = Self::default();
 | |
| 
 | |
|         // We skip binary name and the `test` command.
 | |
|         let mut args = std::env::args().skip(2);
 | |
|         let runners = get_runners();
 | |
| 
 | |
|         while let Some(arg) = args.next() {
 | |
|             match arg.as_str() {
 | |
|                 "--features" => match args.next() {
 | |
|                     Some(feature) if !feature.is_empty() => {
 | |
|                         test_arg
 | |
|                             .flags
 | |
|                             .extend_from_slice(&["--features".into(), feature]);
 | |
|                     }
 | |
|                     _ => {
 | |
|                         return Err("Expected an argument after `--features`, found nothing".into())
 | |
|                     }
 | |
|                 },
 | |
|                 "--use-system-gcc" => {
 | |
|                     println!("Using system GCC");
 | |
|                     test_arg.use_system_gcc = true;
 | |
|                 }
 | |
|                 "--build-only" => test_arg.build_only = true,
 | |
|                 "--nb-parts" => {
 | |
|                     test_arg.nb_parts = Some(get_number_after_arg(&mut args, "--nb-parts")?);
 | |
|                 }
 | |
|                 "--current-part" => {
 | |
|                     test_arg.current_part =
 | |
|                         Some(get_number_after_arg(&mut args, "--current-part")?);
 | |
|                 }
 | |
|                 "--sysroot-panic-abort" => {
 | |
|                     test_arg.sysroot_panic_abort = true;
 | |
|                 }
 | |
|                 "--help" => {
 | |
|                     show_usage();
 | |
|                     return Ok(None);
 | |
|                 }
 | |
|                 x if runners.contains_key(x) => {
 | |
|                     test_arg.runners.insert(x.into());
 | |
|                 }
 | |
|                 arg => {
 | |
|                     if !test_arg.config_info.parse_argument(arg, &mut args)? {
 | |
|                         return Err(format!("Unknown option {}", arg));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         match (test_arg.current_part, test_arg.nb_parts) {
 | |
|             (Some(_), Some(_)) | (None, None) => {}
 | |
|             _ => {
 | |
|                 return Err(
 | |
|                     "If either `--current-part` or `--nb-parts` is specified, the other one \
 | |
|                             needs to be specified as well!"
 | |
|                         .to_string(),
 | |
|                 );
 | |
|             }
 | |
|         }
 | |
|         if test_arg.config_info.no_default_features {
 | |
|             test_arg.flags.push("--no-default-features".into());
 | |
|         }
 | |
|         Ok(Some(test_arg))
 | |
|     }
 | |
| 
 | |
|     pub fn is_using_gcc_master_branch(&self) -> bool {
 | |
|         !self.config_info.no_default_features
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     if args.config_info.backend.is_some() {
 | |
|         return Ok(());
 | |
|     }
 | |
|     let mut command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"rustc"];
 | |
|     let mut tmp_env;
 | |
|     let env = if args.config_info.channel == Channel::Release {
 | |
|         tmp_env = env.clone();
 | |
|         tmp_env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string());
 | |
|         command.push(&"--release");
 | |
|         &tmp_env
 | |
|     } else {
 | |
|         &env
 | |
|     };
 | |
|     for flag in args.flags.iter() {
 | |
|         command.push(flag);
 | |
|     }
 | |
|     run_command_with_output_and_env(&command, None, Some(env))
 | |
| }
 | |
| 
 | |
| fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     let _ = std::fs::remove_dir_all(&args.config_info.cargo_target_dir);
 | |
|     let path = Path::new(&args.config_info.cargo_target_dir).join("gccjit");
 | |
|     std::fs::create_dir_all(&path)
 | |
|         .map_err(|error| format!("failed to create folder `{}`: {:?}", path.display(), error))
 | |
| }
 | |
| 
 | |
| fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[BUILD] mini_core");
 | |
|     let crate_types = if args.config_info.host_triple != args.config_info.target_triple {
 | |
|         "lib"
 | |
|     } else {
 | |
|         "lib,dylib"
 | |
|     }
 | |
|     .to_string();
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/mini_core.rs",
 | |
|         &"--crate-name",
 | |
|         &"mini_core",
 | |
|         &"--crate-type",
 | |
|         &crate_types,
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_output_and_env(&command, None, Some(&env))?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[BUILD] example");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/example.rs",
 | |
|         &"--crate-type",
 | |
|         &"lib",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_output_and_env(&command, None, Some(&env))?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] mini_core_hello_world");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/mini_core_hello_world.rs",
 | |
|         &"--crate-name",
 | |
|         &"mini_core_hello_world",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"-g",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_output_and_env(&command, None, Some(&env))?;
 | |
| 
 | |
|     let command: &[&dyn AsRef<OsStr>] = &[
 | |
|         &Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"),
 | |
|         &"abc",
 | |
|         &"bcd",
 | |
|     ];
 | |
|     maybe_run_command_in_vm(&command, env, args)?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[BUILD] sysroot");
 | |
|     build::build_sysroot(env, &args.config_info)?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| // TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible.
 | |
| fn maybe_run_command_in_vm(
 | |
|     command: &[&dyn AsRef<OsStr>],
 | |
|     env: &Env,
 | |
|     args: &TestArg,
 | |
| ) -> Result<(), String> {
 | |
|     if !args.config_info.run_in_vm {
 | |
|         run_command_with_output_and_env(command, None, Some(env))?;
 | |
|         return Ok(());
 | |
|     }
 | |
|     let vm_parent_dir = match env.get("CG_GCC_VM_DIR") {
 | |
|         Some(dir) if !dir.is_empty() => PathBuf::from(dir.clone()),
 | |
|         _ => std::env::current_dir().unwrap(),
 | |
|     };
 | |
|     let vm_dir = "vm";
 | |
|     let exe_to_run = command.first().unwrap();
 | |
|     let exe = Path::new(&exe_to_run);
 | |
|     let exe_filename = exe.file_name().unwrap();
 | |
|     let vm_home_dir = vm_parent_dir.join(vm_dir).join("home");
 | |
|     let vm_exe_path = vm_home_dir.join(exe_filename);
 | |
|     let inside_vm_exe_path = Path::new("/home").join(exe_filename);
 | |
| 
 | |
|     let sudo_command: &[&dyn AsRef<OsStr>] = &[&"sudo", &"cp", &exe, &vm_exe_path];
 | |
|     run_command_with_env(sudo_command, None, Some(env))?;
 | |
| 
 | |
|     let mut vm_command: Vec<&dyn AsRef<OsStr>> = vec![
 | |
|         &"sudo",
 | |
|         &"chroot",
 | |
|         &vm_dir,
 | |
|         &"qemu-m68k-static",
 | |
|         &inside_vm_exe_path,
 | |
|     ];
 | |
|     vm_command.extend_from_slice(command);
 | |
|     run_command_with_output_and_env(&vm_command, Some(&vm_parent_dir), Some(env))?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     let cargo_target_dir = Path::new(&args.config_info.cargo_target_dir);
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] arbitrary_self_types_pointers_and_wrappers");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/arbitrary_self_types_pointers_and_wrappers.rs",
 | |
|         &"--crate-name",
 | |
|         &"arbitrary_self_types_pointers_and_wrappers",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     maybe_run_command_in_vm(
 | |
|         &[&cargo_target_dir.join("arbitrary_self_types_pointers_and_wrappers")],
 | |
|         env,
 | |
|         args,
 | |
|     )?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] alloc_system");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/alloc_system.rs",
 | |
|         &"--crate-type",
 | |
|         &"lib",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     if args.is_using_gcc_master_branch() {
 | |
|         command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]);
 | |
|     }
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
| 
 | |
|     // FIXME: doesn't work on m68k.
 | |
|     if args.config_info.host_triple == args.config_info.target_triple {
 | |
|         // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|         println!("[AOT] alloc_example");
 | |
|         let mut command = args.config_info.rustc_command_vec();
 | |
|         command.extend_from_slice(&[
 | |
|             &"example/alloc_example.rs",
 | |
|             &"--crate-type",
 | |
|             &"bin",
 | |
|             &"--target",
 | |
|             &args.config_info.target_triple,
 | |
|         ]);
 | |
|         run_command_with_env(&command, None, Some(env))?;
 | |
|         maybe_run_command_in_vm(&[&cargo_target_dir.join("alloc_example")], env, args)?;
 | |
|     }
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] dst_field_align");
 | |
|     // FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/dst-field-align.rs",
 | |
|         &"--crate-name",
 | |
|         &"dst_field_align",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     maybe_run_command_in_vm(&[&cargo_target_dir.join("dst_field_align")], env, args)?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] std_example");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/std_example.rs",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     if args.is_using_gcc_master_branch() {
 | |
|         command.extend_from_slice(&[&"--cfg", &"feature=\"master\""]);
 | |
|     }
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     maybe_run_command_in_vm(
 | |
|         &[
 | |
|             &cargo_target_dir.join("std_example"),
 | |
|             &"--target",
 | |
|             &args.config_info.target_triple,
 | |
|         ],
 | |
|         env,
 | |
|         args,
 | |
|     )?;
 | |
| 
 | |
|     let test_flags = if let Some(test_flags) = env.get("TEST_FLAGS") {
 | |
|         split_args(test_flags)?
 | |
|     } else {
 | |
|         Vec::new()
 | |
|     };
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] subslice-patterns-const-eval");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/subslice-patterns-const-eval.rs",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     for test_flag in &test_flags {
 | |
|         command.push(test_flag);
 | |
|     }
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     maybe_run_command_in_vm(
 | |
|         &[&cargo_target_dir.join("subslice-patterns-const-eval")],
 | |
|         env,
 | |
|         args,
 | |
|     )?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] track-caller-attribute");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/track-caller-attribute.rs",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     for test_flag in &test_flags {
 | |
|         command.push(test_flag);
 | |
|     }
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     maybe_run_command_in_vm(
 | |
|         &[&cargo_target_dir.join("track-caller-attribute")],
 | |
|         env,
 | |
|         args,
 | |
|     )?;
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[AOT] mod_bench");
 | |
|     let mut command = args.config_info.rustc_command_vec();
 | |
|     command.extend_from_slice(&[
 | |
|         &"example/mod_bench.rs",
 | |
|         &"--crate-type",
 | |
|         &"bin",
 | |
|         &"--target",
 | |
|         &args.config_info.target_triple,
 | |
|     ]);
 | |
|     run_command_with_env(&command, None, Some(env))?;
 | |
|     // FIXME: the compiled binary is not run.
 | |
| 
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
 | |
|     let toolchain = format!(
 | |
|         "+{channel}-{host}",
 | |
|         channel = get_toolchain()?, // May also include date
 | |
|         host = args.config_info.host_triple
 | |
|     );
 | |
|     let rust_dir_path = Path::new(crate::BUILD_DIR).join("rust");
 | |
|     // If the repository was already cloned, command will fail, so doesn't matter.
 | |
|     let _ = git_clone(
 | |
|         "https://github.com/rust-lang/rust.git",
 | |
|         Some(&rust_dir_path),
 | |
|         false,
 | |
|     );
 | |
|     let rust_dir: Option<&Path> = Some(&rust_dir_path);
 | |
|     run_command(&[&"git", &"checkout", &"--", &"tests/"], rust_dir)?;
 | |
|     run_command_with_output_and_env(&[&"git", &"fetch"], rust_dir, Some(env))?;
 | |
|     let rustc_commit = match rustc_version_info(env.get("RUSTC").map(|s| s.as_str()))?.commit_hash {
 | |
|         Some(commit_hash) => commit_hash,
 | |
|         None => return Err("Couldn't retrieve rustc commit hash".to_string()),
 | |
|     };
 | |
|     if rustc_commit != "unknown" {
 | |
|         run_command_with_output_and_env(
 | |
|             &[&"git", &"checkout", &rustc_commit],
 | |
|             rust_dir,
 | |
|             Some(env),
 | |
|         )?;
 | |
|     } else {
 | |
|         run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?;
 | |
|     }
 | |
|     let cargo = String::from_utf8(
 | |
|         run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout,
 | |
|     )
 | |
|     .map_err(|error| format!("Failed to retrieve cargo path: {:?}", error))
 | |
|     .and_then(|cargo| {
 | |
|         let cargo = cargo.trim().to_owned();
 | |
|         if cargo.is_empty() {
 | |
|             Err(format!("`cargo` path is empty"))
 | |
|         } else {
 | |
|             Ok(cargo)
 | |
|         }
 | |
|     })?;
 | |
|     let rustc = String::from_utf8(
 | |
|         run_command_with_env(
 | |
|             &[&"rustup", &toolchain, &"which", &"rustc"],
 | |
|             rust_dir,
 | |
|             Some(env),
 | |
|         )?
 | |
|         .stdout,
 | |
|     )
 | |
|     .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error))
 | |
|     .and_then(|rustc| {
 | |
|         let rustc = rustc.trim().to_owned();
 | |
|         if rustc.is_empty() {
 | |
|             Err(format!("`rustc` path is empty"))
 | |
|         } else {
 | |
|             Ok(rustc)
 | |
|         }
 | |
|     })?;
 | |
|     let llvm_filecheck = match run_command_with_env(
 | |
|         &[
 | |
|             &"bash",
 | |
|             &"-c",
 | |
|             &"which FileCheck-10 || \
 | |
|           which FileCheck-11 || \
 | |
|           which FileCheck-12 || \
 | |
|           which FileCheck-13 || \
 | |
|           which FileCheck-14",
 | |
|         ],
 | |
|         rust_dir,
 | |
|         Some(env),
 | |
|     ) {
 | |
|         Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(),
 | |
|         Err(_) => {
 | |
|             eprintln!("Failed to retrieve LLVM FileCheck, ignoring...");
 | |
|             String::new()
 | |
|         }
 | |
|     };
 | |
|     let file_path = rust_dir_path.join("config.toml");
 | |
|     std::fs::write(
 | |
|         &file_path,
 | |
|         &format!(
 | |
|             r#"change-id = 115898
 | |
| 
 | |
| [rust]
 | |
| codegen-backends = []
 | |
| deny-warnings = false
 | |
| verbose-tests = true
 | |
| 
 | |
| [build]
 | |
| cargo = "{cargo}"
 | |
| local-rebuild = true
 | |
| rustc = "{rustc}"
 | |
| 
 | |
| [target.x86_64-unknown-linux-gnu]
 | |
| llvm-filecheck = "{llvm_filecheck}"
 | |
| 
 | |
| [llvm]
 | |
| download-ci-llvm = false
 | |
| "#,
 | |
|             cargo = cargo,
 | |
|             rustc = rustc,
 | |
|             llvm_filecheck = llvm_filecheck.trim(),
 | |
|         ),
 | |
|     )
 | |
|     .map_err(|error| {
 | |
|         format!(
 | |
|             "Failed to write into `{}`: {:?}",
 | |
|             file_path.display(),
 | |
|             error
 | |
|         )
 | |
|     })?;
 | |
|     Ok(rust_dir_path)
 | |
| }
 | |
| 
 | |
| fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     let mut env = env.clone();
 | |
|     let rust_dir = setup_rustc(&mut env, args)?;
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rustc asm test suite");
 | |
| 
 | |
|     env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
 | |
| 
 | |
|     let extra = if args.is_using_gcc_master_branch() {
 | |
|         ""
 | |
|     } else {
 | |
|         " -Csymbol-mangling-version=v0"
 | |
|     };
 | |
| 
 | |
|     let rustc_args = &format!(
 | |
|         r#"-Zpanic-abort-tests \
 | |
|             -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \
 | |
|             --sysroot "{pwd}/build_sysroot/sysroot" -Cpanic=abort{extra}"#,
 | |
|         pwd = std::env::current_dir()
 | |
|             .map_err(|error| format!("`current_dir` failed: {:?}", error))?
 | |
|             .display(),
 | |
|         channel = args.config_info.channel.as_str(),
 | |
|         dylib_ext = args.config_info.dylib_ext,
 | |
|         extra = extra,
 | |
|     );
 | |
| 
 | |
|     run_command_with_env(
 | |
|         &[
 | |
|             &"./x.py",
 | |
|             &"test",
 | |
|             &"--run",
 | |
|             &"always",
 | |
|             &"--stage",
 | |
|             &"0",
 | |
|             &"tests/assembly/asm",
 | |
|             &"--rustc-args",
 | |
|             &rustc_args,
 | |
|         ],
 | |
|         Some(&rust_dir),
 | |
|         Some(&env),
 | |
|     )?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn run_cargo_command(
 | |
|     command: &[&dyn AsRef<OsStr>],
 | |
|     cwd: Option<&Path>,
 | |
|     env: &Env,
 | |
|     args: &TestArg,
 | |
| ) -> Result<(), String> {
 | |
|     run_cargo_command_with_callback(command, cwd, env, args, |cargo_command, cwd, env| {
 | |
|         run_command_with_output_and_env(cargo_command, cwd, Some(env))?;
 | |
|         Ok(())
 | |
|     })
 | |
| }
 | |
| 
 | |
| fn run_cargo_command_with_callback<F>(
 | |
|     command: &[&dyn AsRef<OsStr>],
 | |
|     cwd: Option<&Path>,
 | |
|     env: &Env,
 | |
|     args: &TestArg,
 | |
|     callback: F,
 | |
| ) -> Result<(), String>
 | |
| where
 | |
|     F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>,
 | |
| {
 | |
|     let toolchain = get_toolchain()?;
 | |
|     let toolchain_arg = format!("+{}", toolchain);
 | |
|     let rustc_version = String::from_utf8(
 | |
|         run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout,
 | |
|     )
 | |
|     .map_err(|error| format!("Failed to retrieve rustc version: {:?}", error))?;
 | |
|     let rustc_toolchain_version = String::from_utf8(
 | |
|         run_command_with_env(
 | |
|             &[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"],
 | |
|             cwd,
 | |
|             Some(env),
 | |
|         )?
 | |
|         .stdout,
 | |
|     )
 | |
|     .map_err(|error| format!("Failed to retrieve rustc +toolchain version: {:?}", error))?;
 | |
| 
 | |
|     if rustc_version != rustc_toolchain_version {
 | |
|         eprintln!(
 | |
|             "rustc_codegen_gcc is built for `{}` but the default rustc version is `{}`.",
 | |
|             rustc_toolchain_version, rustc_version,
 | |
|         );
 | |
|         eprintln!("Using `{}`.", rustc_toolchain_version);
 | |
|     }
 | |
|     let mut env = env.clone();
 | |
|     let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
 | |
|     env.insert("RUSTDOCFLAGS".to_string(), rustflags);
 | |
|     let mut cargo_command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &toolchain_arg];
 | |
|     cargo_command.extend_from_slice(&command);
 | |
|     callback(&cargo_command, cwd, &env)
 | |
| }
 | |
| 
 | |
| // FIXME(antoyo): linker gives multiple definitions error on Linux
 | |
| // echo "[BUILD] sysroot in release mode"
 | |
| // ./build_sysroot/build_sysroot.sh --release
 | |
| 
 | |
| fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     let projects = [
 | |
|         //"https://gitlab.gnome.org/GNOME/librsvg", // FIXME: doesn't compile in the CI since the
 | |
|         // version of cairo and other libraries is too old.
 | |
|         "https://github.com/rust-random/getrandom",
 | |
|         "https://github.com/BurntSushi/memchr",
 | |
|         "https://github.com/dtolnay/itoa",
 | |
|         "https://github.com/rust-lang/cfg-if",
 | |
|         "https://github.com/rust-lang-nursery/lazy-static.rs",
 | |
|         //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed.
 | |
|         // TODO: ignore the base64 test that is OOM-killed.
 | |
|         "https://github.com/time-rs/time",
 | |
|         "https://github.com/rust-lang/log",
 | |
|         "https://github.com/bitflags/bitflags",
 | |
|         //"https://github.com/serde-rs/serde", // FIXME: one test fails.
 | |
|         //"https://github.com/rayon-rs/rayon", // TODO: very slow, only run on master?
 | |
|         //"https://github.com/rust-lang/cargo", // TODO: very slow, only run on master?
 | |
|     ];
 | |
| 
 | |
|     let run_tests = |projects_path, iter: &mut dyn Iterator<Item = &&str>| -> Result<(), String> {
 | |
|         for project in iter {
 | |
|             let clone_result = git_clone_root_dir(project, projects_path, true)?;
 | |
|             let repo_path = Path::new(&clone_result.repo_dir);
 | |
|             run_cargo_command(&[&"build", &"--release"], Some(repo_path), env, args)?;
 | |
|             run_cargo_command(&[&"test"], Some(repo_path), env, args)?;
 | |
|         }
 | |
| 
 | |
|         Ok(())
 | |
|     };
 | |
| 
 | |
|     let projects_path = Path::new("projects");
 | |
|     create_dir_all(projects_path)
 | |
|         .map_err(|err| format!("Failed to create directory `projects`: {}", err))?;
 | |
| 
 | |
|     let nb_parts = args.nb_parts.unwrap_or(0);
 | |
|     if nb_parts > 0 {
 | |
|         // We increment the number of tests by one because if this is an odd number, we would skip
 | |
|         // one test.
 | |
|         let count = projects.len() / nb_parts + 1;
 | |
|         let current_part = args.current_part.unwrap();
 | |
|         let start = current_part * count;
 | |
|         // We remove the projects we don't want to test.
 | |
|         run_tests(projects_path, &mut projects.iter().skip(start).take(count))?;
 | |
|     } else {
 | |
|         run_tests(projects_path, &mut projects.iter())?;
 | |
|     }
 | |
| 
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] libcore");
 | |
|     let path = Path::new("build_sysroot/sysroot_src/library/core/tests");
 | |
|     let _ = remove_dir_all(path.join("target"));
 | |
|     run_cargo_command(&[&"test"], Some(path), env, args)?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| // echo "[BENCH COMPILE] mod_bench"
 | |
| //
 | |
| // COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
 | |
| // COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort"
 | |
| // COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort"
 | |
| // COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort"
 | |
| // COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort"
 | |
| //
 | |
| // Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
 | |
| // hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
 | |
| // echo "[BENCH RUN] mod_bench"
 | |
| // hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_*
 | |
| 
 | |
| fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     if !args.is_using_gcc_master_branch() {
 | |
|         println!("Not using GCC master branch. Skipping `extended_rand_tests`.");
 | |
|         return Ok(());
 | |
|     }
 | |
|     let mut env = env.clone();
 | |
|     // newer aho_corasick versions throw a deprecation warning
 | |
|     let rustflags = format!(
 | |
|         "{} --cap-lints warn",
 | |
|         env.get("RUSTFLAGS").cloned().unwrap_or_default()
 | |
|     );
 | |
|     env.insert("RUSTFLAGS".to_string(), rustflags);
 | |
| 
 | |
|     let path = Path::new(crate::BUILD_DIR).join("rand");
 | |
|     run_cargo_command(&[&"clean"], Some(&path), &env, args)?;
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rust-random/rand");
 | |
|     run_cargo_command(&[&"test", &"--workspace"], Some(&path), &env, args)?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn extended_regex_example_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     if !args.is_using_gcc_master_branch() {
 | |
|         println!("Not using GCC master branch. Skipping `extended_regex_example_tests`.");
 | |
|         return Ok(());
 | |
|     }
 | |
|     let path = Path::new(crate::BUILD_DIR).join("regex");
 | |
|     run_cargo_command(&[&"clean"], Some(&path), env, args)?;
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rust-lang/regex example shootout-regex-dna");
 | |
|     let mut env = env.clone();
 | |
|     // newer aho_corasick versions throw a deprecation warning
 | |
|     let rustflags = format!(
 | |
|         "{} --cap-lints warn",
 | |
|         env.get("RUSTFLAGS").cloned().unwrap_or_default()
 | |
|     );
 | |
|     env.insert("RUSTFLAGS".to_string(), rustflags);
 | |
|     // Make sure `[codegen mono items] start` doesn't poison the diff
 | |
|     run_cargo_command(
 | |
|         &[&"build", &"--example", &"shootout-regex-dna"],
 | |
|         Some(&path),
 | |
|         &env,
 | |
|         args,
 | |
|     )?;
 | |
| 
 | |
|     run_cargo_command_with_callback(
 | |
|         &[&"run", &"--example", &"shootout-regex-dna"],
 | |
|         Some(&path),
 | |
|         &env,
 | |
|         args,
 | |
|         |cargo_command, cwd, env| {
 | |
|             // FIXME: rewrite this with `child.stdin.write_all()` because
 | |
|             // `examples/regexdna-input.txt` is very small.
 | |
|             let mut command: Vec<&dyn AsRef<OsStr>> = vec![&"bash", &"-c"];
 | |
|             let cargo_args = cargo_command
 | |
|                 .iter()
 | |
|                 .map(|s| s.as_ref().to_str().unwrap())
 | |
|                 .collect::<Vec<_>>();
 | |
|             let bash_command = format!(
 | |
|                 "cat examples/regexdna-input.txt | {} | grep -v 'Spawned thread' > res.txt",
 | |
|                 cargo_args.join(" "),
 | |
|             );
 | |
|             command.push(&bash_command);
 | |
|             run_command_with_output_and_env(&command, cwd, Some(env))?;
 | |
|             run_command_with_output_and_env(
 | |
|                 &[&"diff", &"-u", &"res.txt", &"examples/regexdna-output.txt"],
 | |
|                 cwd,
 | |
|                 Some(env),
 | |
|             )?;
 | |
|             Ok(())
 | |
|         },
 | |
|     )?;
 | |
| 
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn extended_regex_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     if !args.is_using_gcc_master_branch() {
 | |
|         println!("Not using GCC master branch. Skipping `extended_regex_tests`.");
 | |
|         return Ok(());
 | |
|     }
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rust-lang/regex tests");
 | |
|     let mut env = env.clone();
 | |
|     // newer aho_corasick versions throw a deprecation warning
 | |
|     let rustflags = format!(
 | |
|         "{} --cap-lints warn",
 | |
|         env.get("RUSTFLAGS").cloned().unwrap_or_default()
 | |
|     );
 | |
|     env.insert("RUSTFLAGS".to_string(), rustflags);
 | |
|     let path = Path::new(crate::BUILD_DIR).join("regex");
 | |
|     run_cargo_command(
 | |
|         &[
 | |
|             &"test",
 | |
|             &"--tests",
 | |
|             &"--",
 | |
|             // FIXME: try removing `--exclude-should-panic` argument
 | |
|             &"--exclude-should-panic",
 | |
|             &"--test-threads",
 | |
|             &"1",
 | |
|             &"-Zunstable-options",
 | |
|             &"-q",
 | |
|         ],
 | |
|         Some(&path),
 | |
|         &env,
 | |
|         args,
 | |
|     )?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn extended_sysroot_tests(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     // pushd simple-raytracer
 | |
|     // echo "[BENCH COMPILE] ebobby/simple-raytracer"
 | |
|     // hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \
 | |
|     // "RUSTC=rustc RUSTFLAGS='' cargo build" \
 | |
|     // "../y.sh cargo build"
 | |
| 
 | |
|     // echo "[BENCH RUN] ebobby/simple-raytracer"
 | |
|     // cp ./target/debug/main ./raytracer_cg_gcc
 | |
|     // hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_gcc
 | |
|     // popd
 | |
|     extended_rand_tests(env, args)?;
 | |
|     extended_regex_example_tests(env, args)?;
 | |
|     extended_regex_tests(env, args)?;
 | |
| 
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn should_not_remove_test(file: &str) -> bool {
 | |
|     // contains //~ERROR, but shouldn't be removed
 | |
|     [
 | |
|         "issues/auxiliary/issue-3136-a.rs",
 | |
|         "type-alias-impl-trait/auxiliary/cross_crate_ice.rs",
 | |
|         "type-alias-impl-trait/auxiliary/cross_crate_ice2.rs",
 | |
|         "macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs",
 | |
|         "imports/ambiguous-1.rs",
 | |
|         "imports/ambiguous-4-extern.rs",
 | |
|         "entry-point/auxiliary/bad_main_functions.rs",
 | |
|     ]
 | |
|     .iter()
 | |
|     .any(|to_ignore| file.ends_with(to_ignore))
 | |
| }
 | |
| 
 | |
| fn should_remove_test(file_path: &Path) -> Result<bool, String> {
 | |
|     // Tests generating errors.
 | |
|     let file = File::open(file_path)
 | |
|         .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
 | |
|     for line in BufReader::new(file).lines().filter_map(|line| line.ok()) {
 | |
|         let line = line.trim();
 | |
|         if line.is_empty() {
 | |
|             continue;
 | |
|         }
 | |
|         if [
 | |
|             "//@ error-pattern:",
 | |
|             "//@ build-fail",
 | |
|             "//@ run-fail",
 | |
|             "-Cllvm-args",
 | |
|             "//~",
 | |
|             "thread",
 | |
|         ]
 | |
|         .iter()
 | |
|         .any(|check| line.contains(check))
 | |
|         {
 | |
|             return Ok(true);
 | |
|         }
 | |
|         if line.contains("//[") && line.contains("]~") {
 | |
|             return Ok(true);
 | |
|         }
 | |
|     }
 | |
|     if file_path
 | |
|         .display()
 | |
|         .to_string()
 | |
|         .contains("ambiguous-4-extern.rs")
 | |
|     {
 | |
|         eprintln!("nothing found for {file_path:?}");
 | |
|     }
 | |
|     Ok(false)
 | |
| }
 | |
| 
 | |
| fn test_rustc_inner<F>(env: &Env, args: &TestArg, prepare_files_callback: F) -> Result<(), String>
 | |
| where
 | |
|     F: Fn(&Path) -> Result<bool, String>,
 | |
| {
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rust-lang/rust");
 | |
|     let mut env = env.clone();
 | |
|     let rust_path = setup_rustc(&mut env, args)?;
 | |
| 
 | |
|     walk_dir(
 | |
|         rust_path.join("tests/ui"),
 | |
|         |dir| {
 | |
|             let dir_name = dir.file_name().and_then(|name| name.to_str()).unwrap_or("");
 | |
|             if [
 | |
|                 "abi",
 | |
|                 "extern",
 | |
|                 "unsized-locals",
 | |
|                 "proc-macro",
 | |
|                 "threads-sendsync",
 | |
|                 "borrowck",
 | |
|                 "test-attrs",
 | |
|             ]
 | |
|             .iter()
 | |
|             .any(|name| *name == dir_name)
 | |
|             {
 | |
|                 std::fs::remove_dir_all(dir).map_err(|error| {
 | |
|                     format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
 | |
|                 })?;
 | |
|             }
 | |
|             Ok(())
 | |
|         },
 | |
|         |_| Ok(()),
 | |
|     )?;
 | |
| 
 | |
|     // These two functions are used to remove files that are known to not be working currently
 | |
|     // with the GCC backend to reduce noise.
 | |
|     fn dir_handling(dir: &Path) -> Result<(), String> {
 | |
|         if dir
 | |
|             .file_name()
 | |
|             .map(|name| name == "auxiliary")
 | |
|             .unwrap_or(true)
 | |
|         {
 | |
|             return Ok(());
 | |
|         }
 | |
|         walk_dir(dir, dir_handling, file_handling)
 | |
|     }
 | |
|     fn file_handling(file_path: &Path) -> Result<(), String> {
 | |
|         if !file_path
 | |
|             .extension()
 | |
|             .map(|extension| extension == "rs")
 | |
|             .unwrap_or(false)
 | |
|         {
 | |
|             return Ok(());
 | |
|         }
 | |
|         let path_str = file_path.display().to_string().replace("\\", "/");
 | |
|         if should_not_remove_test(&path_str) {
 | |
|             return Ok(());
 | |
|         } else if should_remove_test(file_path)? {
 | |
|             return remove_file(&file_path);
 | |
|         }
 | |
|         Ok(())
 | |
|     }
 | |
| 
 | |
|     remove_file(&rust_path.join("tests/ui/consts/const_cmp_type_id.rs"))?;
 | |
|     remove_file(&rust_path.join("tests/ui/consts/issue-73976-monomorphic.rs"))?;
 | |
|     // this test is oom-killed in the CI.
 | |
|     remove_file(&rust_path.join("tests/ui/consts/issue-miri-1910.rs"))?;
 | |
|     // Tests generating errors.
 | |
|     remove_file(&rust_path.join("tests/ui/consts/issue-94675.rs"))?;
 | |
|     remove_file(&rust_path.join("tests/ui/mir/mir_heavy_promoted.rs"))?;
 | |
|     remove_file(&rust_path.join("tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs"))?;
 | |
|     remove_file(&rust_path.join("tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs"))?;
 | |
| 
 | |
|     walk_dir(rust_path.join("tests/ui"), dir_handling, file_handling)?;
 | |
| 
 | |
|     if !prepare_files_callback(&rust_path)? {
 | |
|         // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|         println!("Keeping all UI tests");
 | |
|     }
 | |
| 
 | |
|     let nb_parts = args.nb_parts.unwrap_or(0);
 | |
|     if nb_parts > 0 {
 | |
|         let current_part = args.current_part.unwrap();
 | |
|         // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|         println!(
 | |
|             "Splitting ui_test into {} parts (and running part {})",
 | |
|             nb_parts, current_part
 | |
|         );
 | |
|         let out = String::from_utf8(
 | |
|             run_command(
 | |
|                 &[
 | |
|                     &"find",
 | |
|                     &"tests/ui",
 | |
|                     &"-type",
 | |
|                     &"f",
 | |
|                     &"-name",
 | |
|                     &"*.rs",
 | |
|                     &"-not",
 | |
|                     &"-path",
 | |
|                     &"*/auxiliary/*",
 | |
|                 ],
 | |
|                 Some(&rust_path),
 | |
|             )?
 | |
|             .stdout,
 | |
|         )
 | |
|         .map_err(|error| format!("Failed to retrieve output of find command: {:?}", error))?;
 | |
|         let mut files = out
 | |
|             .split('\n')
 | |
|             .map(|line| line.trim())
 | |
|             .filter(|line| !line.is_empty())
 | |
|             .collect::<Vec<_>>();
 | |
|         // To ensure it'll be always the same sub files, we sort the content.
 | |
|         files.sort();
 | |
|         // We increment the number of tests by one because if this is an odd number, we would skip
 | |
|         // one test.
 | |
|         let count = files.len() / nb_parts + 1;
 | |
|         let start = current_part * count;
 | |
|         // We remove the files we don't want to test.
 | |
|         for path in files.iter().skip(start).take(count) {
 | |
|             remove_file(&rust_path.join(path))?;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // FIXME: create a function "display_if_not_quiet" or something along the line.
 | |
|     println!("[TEST] rustc test suite");
 | |
|     env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
 | |
| 
 | |
|     let extra = if args.is_using_gcc_master_branch() {
 | |
|         ""
 | |
|     } else {
 | |
|         " -Csymbol-mangling-version=v0"
 | |
|     };
 | |
| 
 | |
|     let rustc_args = format!(
 | |
|         "{} -Zcodegen-backend={} --sysroot {}{}",
 | |
|         env.get("TEST_FLAGS").unwrap_or(&String::new()),
 | |
|         args.config_info.cg_backend_path,
 | |
|         args.config_info.sysroot_path,
 | |
|         extra,
 | |
|     );
 | |
| 
 | |
|     env.get_mut("RUSTFLAGS").unwrap().clear();
 | |
|     run_command_with_output_and_env(
 | |
|         &[
 | |
|             &"./x.py",
 | |
|             &"test",
 | |
|             &"--run",
 | |
|             &"always",
 | |
|             &"--stage",
 | |
|             &"0",
 | |
|             &"tests/ui",
 | |
|             &"--rustc-args",
 | |
|             &rustc_args,
 | |
|         ],
 | |
|         Some(&rust_path),
 | |
|         Some(&env),
 | |
|     )?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     test_rustc_inner(env, args, |_| Ok(false))
 | |
| }
 | |
| 
 | |
| fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     test_rustc_inner(env, args, |rust_path| {
 | |
|         // Removing all tests.
 | |
|         run_command(
 | |
|             &[
 | |
|                 &"find",
 | |
|                 &"tests/ui",
 | |
|                 &"-type",
 | |
|                 &"f",
 | |
|                 &"-name",
 | |
|                 &"*.rs",
 | |
|                 &"-not",
 | |
|                 &"-path",
 | |
|                 &"*/auxiliary/*",
 | |
|                 &"-delete",
 | |
|             ],
 | |
|             Some(rust_path),
 | |
|         )?;
 | |
|         // Putting back only the failing ones.
 | |
|         let path = "tests/failing-ui-tests.txt";
 | |
|         if let Ok(files) = std::fs::read_to_string(path) {
 | |
|             for file in files
 | |
|                 .split('\n')
 | |
|                 .map(|line| line.trim())
 | |
|                 .filter(|line| !line.is_empty())
 | |
|             {
 | |
|                 run_command(&[&"git", &"checkout", &"--", &file], Some(&rust_path))?;
 | |
|             }
 | |
|         } else {
 | |
|             println!(
 | |
|                 "Failed to read `{}`, not putting back failing ui tests",
 | |
|                 path
 | |
|             );
 | |
|         }
 | |
|         Ok(true)
 | |
|     })
 | |
| }
 | |
| 
 | |
| fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     test_rustc_inner(env, args, |rust_path| {
 | |
|         // Removing the failing tests.
 | |
|         let path = "tests/failing-ui-tests.txt";
 | |
|         if let Ok(files) = std::fs::read_to_string(path) {
 | |
|             for file in files
 | |
|                 .split('\n')
 | |
|                 .map(|line| line.trim())
 | |
|                 .filter(|line| !line.is_empty())
 | |
|             {
 | |
|                 let path = rust_path.join(file);
 | |
|                 remove_file(&path)?;
 | |
|             }
 | |
|         } else {
 | |
|             println!(
 | |
|                 "Failed to read `{}`, not putting back failing ui tests",
 | |
|                 path
 | |
|             );
 | |
|         }
 | |
|         Ok(true)
 | |
|     })
 | |
| }
 | |
| 
 | |
| fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
 | |
|     clean(env, args)?;
 | |
|     mini_tests(env, args)?;
 | |
|     build_sysroot(env, args)?;
 | |
|     std_tests(env, args)?;
 | |
|     // asm_tests(env, args)?;
 | |
|     test_libcore(env, args)?;
 | |
|     extended_sysroot_tests(env, args)?;
 | |
|     test_rustc(env, args)?;
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| pub fn run() -> Result<(), String> {
 | |
|     let mut args = match TestArg::new()? {
 | |
|         Some(args) => args,
 | |
|         None => return Ok(()),
 | |
|     };
 | |
|     let mut env: HashMap<String, String> = std::env::vars().collect();
 | |
| 
 | |
|     if !args.use_system_gcc {
 | |
|         args.config_info.setup_gcc_path()?;
 | |
|         env.insert(
 | |
|             "LIBRARY_PATH".to_string(),
 | |
|             args.config_info.gcc_path.clone(),
 | |
|         );
 | |
|         env.insert(
 | |
|             "LD_LIBRARY_PATH".to_string(),
 | |
|             args.config_info.gcc_path.clone(),
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     build_if_no_backend(&env, &args)?;
 | |
|     if args.build_only {
 | |
|         println!("Since it's build only, exiting...");
 | |
|         return Ok(());
 | |
|     }
 | |
| 
 | |
|     args.config_info.setup(&mut env, args.use_system_gcc)?;
 | |
| 
 | |
|     if args.runners.is_empty() {
 | |
|         run_all(&env, &args)?;
 | |
|     } else {
 | |
|         let runners = get_runners();
 | |
|         for runner in args.runners.iter() {
 | |
|             runners.get(runner.as_str()).unwrap().1(&env, &args)?;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Ok(())
 | |
| }
 | 
