Merge commit 'fda0bb9588912a3e0606e880ca9f6e913cf8a5a4' into subtree-update_cg_gcc_2025-06-18

This commit is contained in:
Guillaume Gomez
2025-06-18 15:11:44 +02:00
54 changed files with 11917 additions and 10357 deletions

View File

@@ -9,8 +9,8 @@ use crate::build;
use crate::config::{Channel, ConfigInfo};
use crate::utils::{
create_dir, get_sysroot_dir, 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,
run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env,
rustc_version_info, split_args, walk_dir,
};
type Env = HashMap<String, String>;
@@ -42,7 +42,7 @@ fn get_runners() -> Runners {
);
runners.insert("--extended-regex-tests", ("Run extended regex tests", extended_regex_tests));
runners.insert("--mini-tests", ("Run mini tests", mini_tests));
runners.insert("--cargo-tests", ("Run cargo tests", cargo_tests));
runners
}
@@ -53,9 +53,9 @@ fn get_number_after_arg(
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(_) => Err(format!("Expected a number after `{option}`, found `{nb}`")),
},
_ => Err(format!("Expected a number after `{}`, found nothing", option)),
_ => Err(format!("Expected a number after `{option}`, found nothing")),
}
}
@@ -76,8 +76,8 @@ fn 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);
let spaces: String = std::iter::repeat_n(' ', needed_spaces).collect();
println!(" {option}{spaces}: {doc}");
}
println!(" --help : Show this help");
}
@@ -88,6 +88,8 @@ struct TestArg {
use_system_gcc: bool,
runners: Vec<String>,
flags: Vec<String>,
/// Additional arguments, to be passed to commands like `cargo test`.
test_args: Vec<String>,
nb_parts: Option<usize>,
current_part: Option<usize>,
sysroot_panic_abort: bool,
@@ -137,13 +139,14 @@ impl TestArg {
test_arg.sysroot_features.push(feature);
}
_ => {
return Err(format!("Expected an argument after `{}`, found nothing", arg));
return Err(format!("Expected an argument after `{arg}`, found nothing"));
}
},
"--help" => {
show_usage();
return Ok(None);
}
"--" => test_arg.test_args.extend(&mut args),
x if runners.contains_key(x)
&& !test_arg.runners.iter().any(|runner| runner == x) =>
{
@@ -151,7 +154,7 @@ impl TestArg {
}
arg => {
if !test_arg.config_info.parse_argument(arg, &mut args)? {
return Err(format!("Unknown option {}", arg));
return Err(format!("Unknown option {arg}"));
}
}
}
@@ -189,7 +192,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
command.push(&"--release");
&tmp_env
} else {
&env
env
};
for flag in args.flags.iter() {
command.push(flag);
@@ -203,6 +206,33 @@ fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
create_dir(&path)
}
fn cargo_tests(test_env: &Env, test_args: &TestArg) -> Result<(), String> {
// First, we call `mini_tests` to build minicore for us. This ensures we are testing with a working `minicore`,
// and that any changes we have made affect `minicore`(since it would get rebuilt).
mini_tests(test_env, test_args)?;
// Then, we copy some of the env vars from `test_env`
// We don't want to pass things like `RUSTFLAGS`, since they contain the -Zcodegen-backend flag.
// That would force `cg_gcc` to *rebuild itself* and only then run tests, which is undesirable.
let mut env = HashMap::new();
env.insert(
"LD_LIBRARY_PATH".into(),
test_env.get("LD_LIBRARY_PATH").expect("LD_LIBRARY_PATH missing!").to_string(),
);
env.insert(
"LIBRARY_PATH".into(),
test_env.get("LIBRARY_PATH").expect("LIBRARY_PATH missing!").to_string(),
);
env.insert(
"CG_RUSTFLAGS".into(),
test_env.get("CG_RUSTFLAGS").map(|s| s.as_str()).unwrap_or("").to_string(),
);
// Pass all the default args + the user-specified ones.
let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"test"];
args.extend(test_args.test_args.iter().map(|s| s as &dyn AsRef<OsStr>));
run_command_with_output_and_env(&args, None, Some(&env))?;
Ok(())
}
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");
@@ -222,7 +252,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target",
&args.config_info.target_triple,
]);
run_command_with_output_and_env(&command, None, Some(&env))?;
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");
@@ -234,7 +264,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target",
&args.config_info.target_triple,
]);
run_command_with_output_and_env(&command, None, Some(&env))?;
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");
@@ -249,14 +279,14 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"--target",
&args.config_info.target_triple,
]);
run_command_with_output_and_env(&command, None, Some(&env))?;
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)?;
maybe_run_command_in_vm(command, env, args)?;
Ok(())
}
@@ -454,22 +484,47 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
} else {
run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?;
}
let mut patches = Vec::new();
walk_dir(
"patches/tests",
&mut |_| Ok(()),
&mut |file_path: &Path| {
patches.push(file_path.to_path_buf());
Ok(())
},
false,
)?;
patches.sort();
// TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils
// module.
for file_path in patches {
println!("[GIT] apply `{}`", file_path.display());
let path = Path::new("../..").join(file_path);
run_command_with_output(&[&"git", &"apply", &path], rust_dir)?;
run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?;
run_command_with_output(
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
rust_dir,
)?;
}
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))
.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) }
if cargo.is_empty() { Err("`cargo` path is empty".to_string()) } 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))
.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) }
if rustc.is_empty() { Err("`rustc` path is empty".to_string()) } else { Ok(rustc) }
})?;
let llvm_filecheck = match run_command_with_env(
&[
@@ -479,7 +534,8 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
which FileCheck-11 || \
which FileCheck-12 || \
which FileCheck-13 || \
which FileCheck-14",
which FileCheck-14 || \
which FileCheck",
],
rust_dir,
Some(env),
@@ -487,13 +543,15 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(),
Err(_) => {
eprintln!("Failed to retrieve LLVM FileCheck, ignoring...");
// FIXME: the test tests/run-make/no-builtins-attribute will fail if we cannot find
// FileCheck.
String::new()
}
};
let file_path = rust_dir_path.join("config.toml");
std::fs::write(
&file_path,
&format!(
format!(
r#"change-id = 115898
[rust]
@@ -532,7 +590,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
let codegen_backend_path = format!(
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
pwd = std::env::current_dir()
.map_err(|error| format!("`current_dir` failed: {:?}", error))?
.map_err(|error| format!("`current_dir` failed: {error:?}"))?
.display(),
channel = args.config_info.channel.as_str(),
dylib_ext = args.config_info.dylib_ext,
@@ -587,11 +645,11 @@ where
F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>,
{
let toolchain = get_toolchain()?;
let toolchain_arg = format!("+{}", 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))?;
.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"],
@@ -600,20 +658,19 @@ where
)?
.stdout,
)
.map_err(|error| format!("Failed to retrieve rustc +toolchain version: {:?}", error))?;
.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,
"rustc_codegen_gcc is built for `{rustc_toolchain_version}` but the default rustc version is `{rustc_version}`.",
);
eprintln!("Using `{}`.", rustc_toolchain_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);
cargo_command.extend_from_slice(command);
callback(&cargo_command, cwd, &env)
}
@@ -680,7 +737,15 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
println!("[TEST] libcore");
let path = get_sysroot_dir().join("sysroot_src/library/coretests");
let _ = remove_dir_all(path.join("target"));
run_cargo_command(&[&"test"], Some(&path), env, args)?;
// TODO(antoyo): run in release mode when we fix the failures.
// TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed:
// https://github.com/rust-lang/rust/issues/141503
run_cargo_command(
&[&"test", &"--", &"--skip", &"f16::test_total_cmp"],
Some(&path),
env,
args,
)?;
Ok(())
}
@@ -818,7 +883,7 @@ fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<
// 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()) {
for line in BufReader::new(file).lines().map_while(Result::ok) {
let line = line.trim();
if line.is_empty() {
continue;
@@ -887,7 +952,7 @@ where
if !prepare_files_callback(&rust_path)? {
// FIXME: create a function "display_if_not_quiet" or something along the line.
println!("Keeping all {} tests", test_type);
println!("Keeping all {test_type} tests");
}
if test_type == "ui" {
@@ -919,8 +984,7 @@ where
"borrowck",
"test-attrs",
]
.iter()
.any(|name| *name == dir_name)
.contains(&dir_name)
{
remove_dir_all(dir).map_err(|error| {
format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
@@ -975,10 +1039,7 @@ where
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
);
println!("Splitting ui_test into {nb_parts} parts (and running part {current_part})");
let out = String::from_utf8(
run_command(
&[
@@ -996,7 +1057,7 @@ where
)?
.stdout,
)
.map_err(|error| format!("Failed to retrieve output of find command: {:?}", error))?;
.map_err(|error| format!("Failed to retrieve output of find command: {error:?}"))?;
let mut files = out
.split('\n')
.map(|line| line.trim())
@@ -1016,7 +1077,7 @@ where
}
// FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[TEST] rustc {} test suite", test_type);
println!("[TEST] rustc {test_type} test suite");
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
let extra =
@@ -1040,7 +1101,7 @@ where
&"always",
&"--stage",
&"0",
&format!("tests/{}", test_type),
&format!("tests/{test_type}"),
&"--compiletest-rustc-args",
&rustc_args,
],
@@ -1051,19 +1112,18 @@ where
}
fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
//test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
test_rustc_inner(env, args, |_| Ok(false), false, "ui")
}
fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
let result1 = Ok(());
/*test_rustc_inner(
let result1 = test_rustc_inner(
env,
args,
retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
false,
"run-make",
)*/
);
let result2 = test_rustc_inner(
env,
@@ -1084,14 +1144,13 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
false,
"ui",
)?;
Ok(())
/*test_rustc_inner(
test_rustc_inner(
env,
args,
remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
false,
"run-make",
)*/
)
}
fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String> {
@@ -1118,7 +1177,7 @@ fn retain_files_callback<'a>(
run_command(
&[
&"find",
&format!("tests/{}", test_type),
&format!("tests/{test_type}"),
&"-mindepth",
&"1",
&"-type",
@@ -1137,7 +1196,7 @@ fn retain_files_callback<'a>(
run_command(
&[
&"find",
&format!("tests/{}", test_type),
&format!("tests/{test_type}"),
&"-type",
&"f",
&"-name",
@@ -1152,15 +1211,12 @@ fn retain_files_callback<'a>(
}
// Putting back only the failing ones.
if let Ok(files) = std::fs::read_to_string(&file_path) {
if let Ok(files) = std::fs::read_to_string(file_path) {
for file in files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty()) {
run_command(&[&"git", &"checkout", &"--", &file], Some(&rust_path))?;
run_command(&[&"git", &"checkout", &"--", &file], Some(rust_path))?;
}
} else {
println!(
"Failed to read `{}`, not putting back failing {} tests",
file_path, test_type
);
println!("Failed to read `{file_path}`, not putting back failing {test_type} tests");
}
Ok(true)
@@ -1188,8 +1244,7 @@ fn remove_files_callback<'a>(
}
} else {
println!(
"Failed to read `{}`, not putting back failing {} tests",
file_path, test_type
"Failed to read `{file_path}`, not putting back failing {test_type} tests"
);
}
} else {
@@ -1202,7 +1257,7 @@ fn remove_files_callback<'a>(
remove_file(&path)?;
}
} else {
println!("Failed to read `{}`, not putting back failing ui tests", file_path);
println!("Failed to read `{file_path}`, not putting back failing ui tests");
}
}
Ok(true)
@@ -1217,7 +1272,9 @@ fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
// asm_tests(env, args)?;
test_libcore(env, args)?;
extended_sysroot_tests(env, args)?;
cargo_tests(env, args)?;
test_rustc(env, args)?;
Ok(())
}