From 893d81f1e219109d098309d9e3f435b9097da47f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Jan 2025 15:46:53 +0100 Subject: [PATCH 1/9] on s390x, use `PassMode::Direct` for vector types --- compiler/rustc_target/src/callconv/s390x.rs | 14 +- tests/codegen/s390x-simd.rs | 143 ++++++++++++++++++++ 2 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 tests/codegen/s390x-simd.rs diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index c99eb9226eff1..a73c1a0f46c2b 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -38,9 +38,17 @@ where } let size = arg.layout.size; - if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) { - arg.cast_to(Reg { kind: RegKind::Vector, size }); - return; + if size.bits() <= 128 { + if let BackendRepr::Vector { .. } = arg.layout.backend_repr { + // pass non-wrapped vector types using `PassMode::Direct` + return; + } + + if arg.layout.is_single_vector_element(cx, size) { + // pass non-transparant wrappers around a vector as `PassMode::Cast` + arg.cast_to(Reg { kind: RegKind::Vector, size }); + return; + } } if !arg.layout.is_aggregate() && size.bits() <= 64 { arg.extend_integer_width_to(64); diff --git a/tests/codegen/s390x-simd.rs b/tests/codegen/s390x-simd.rs new file mode 100644 index 0000000000000..23181e6a10308 --- /dev/null +++ b/tests/codegen/s390x-simd.rs @@ -0,0 +1,143 @@ +//! test that s390x vector types are passed using `PassMode::Direct` +//! see also https://github.com/rust-lang/rust/issues/135744 +//@ add-core-stubs +//@ compile-flags: --target s390x-unknown-linux-gnu -O +//@ needs-llvm-components: systemz + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +struct i8x16([i8; 16]); + +#[repr(simd)] +struct i16x8([i16; 8]); + +#[repr(simd)] +struct i32x4([i32; 4]); + +#[repr(simd)] +struct i64x2([i64; 2]); + +#[repr(simd)] +struct f32x4([f32; 4]); + +#[repr(simd)] +struct f64x2([f64; 2]); + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.smax.v16i8"] + fn vmxb(a: i8x16, b: i8x16) -> i8x16; + #[link_name = "llvm.smax.v8i16"] + fn vmxh(a: i16x8, b: i16x8) -> i16x8; + #[link_name = "llvm.smax.v4i32"] + fn vmxf(a: i32x4, b: i32x4) -> i32x4; + #[link_name = "llvm.smax.v2i64"] + fn vmxg(a: i64x2, b: i64x2) -> i64x2; +} + +// CHECK-LABEL: define <16 x i8> @max_i8x16 +// CHECK-SAME: <16 x i8> %a, <16 x i8> %b +// CHECK: call <16 x i8> @llvm.smax.v16i8(<16 x i8> %a, <16 x i8> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 { + vmxb(a, b) +} + +// CHECK-LABEL: define <8 x i16> @max_i16x8 +// CHECK-SAME: <8 x i16> %a, <8 x i16> %b +// CHECK: call <8 x i16> @llvm.smax.v8i16(<8 x i16> %a, <8 x i16> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 { + vmxh(a, b) +} + +// CHECK-LABEL: define <4 x i32> @max_i32x4 +// CHECK-SAME: <4 x i32> %a, <4 x i32> %b +// CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 { + vmxf(a, b) +} + +// CHECK-LABEL: define <2 x i64> @max_i64x2 +// CHECK-SAME: <2 x i64> %a, <2 x i64> %b +// CHECK: call <2 x i64> @llvm.smax.v2i64(<2 x i64> %a, <2 x i64> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 { + vmxg(a, b) +} + +// CHECK-LABEL: define <4 x float> @choose_f32x4 +// CHECK-SAME: <4 x float> %a, <4 x float> %b +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_f32x4(a: f32x4, b: f32x4, c: bool) -> f32x4 { + if c { a } else { b } +} + +// CHECK-LABEL: define <2 x double> @choose_f64x2 +// CHECK-SAME: <2 x double> %a, <2 x double> %b +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_f64x2(a: f64x2, b: f64x2, c: bool) -> f64x2 { + if c { a } else { b } +} + +#[repr(C)] +struct Wrapper(T); + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper, b: Wrapper) -> Wrapper { + // CHECK-LABEL: max_wrapper_i8x16 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + // CHECK: call <16 x i8> @llvm.smax.v16i8 + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + Wrapper(vmxb(a.0, b.0)) +} + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper, b: Wrapper) -> Wrapper { + // CHECK-LABEL: max_wrapper_i64x2 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + // CHECK: call <2 x i64> @llvm.smax.v2i64 + // CHECK-SAME: <2 x i64> + // CHECK-SAME: <2 x i64> + Wrapper(vmxg(a.0, b.0)) +} + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_wrapper_f64x2( + a: Wrapper, + b: Wrapper, + c: bool, +) -> Wrapper { + // CHECK-LABEL: choose_wrapper_f64x2 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + Wrapper(choose_f64x2(a.0, b.0, c)) +} + +// CHECK: declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>) From 9d6a1c980e7de879d6eb64c281aac3cdfdefce3f Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 18 Jan 2025 16:55:31 -0500 Subject: [PATCH 2/9] Shorten linker output even more when `--verbose` is not present - Don't show environment variables. Seeing PATH is almost never useful, and it can be extremely long. - For .rlibs in the sysroot, replace crate hashes with a `"-*"` string. This will expand to the full crate name when pasted into the shell. - Move `.rlib` to outside the glob. - Abbreviate the sysroot path to `` wherever it appears in the arguments. This also adds an example of the linker output as a run-make test. Currently it only runs on x86_64-unknown-linux-gnu, because each platform has its own linker arguments. So that it's stable across machines, pass BUILD_ROOT as an argument through compiletest through to run-make tests. --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 1 + .../rustc_codegen_ssa/src/back/command.rs | 17 ++++- compiler/rustc_codegen_ssa/src/back/link.rs | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 62 ++++++++++++++----- src/tools/compiletest/src/runtest/run_make.rs | 2 + src/tools/run-make-support/src/lib.rs | 2 +- .../run-make-support/src/path_helpers.rs | 6 ++ src/tools/tidy/src/deps.rs | 1 + tests/run-make/linker-warning/rmake.rs | 41 ++++++++---- tests/run-make/linker-warning/short-error.txt | 9 +++ 11 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 tests/run-make/linker-warning/short-error.txt diff --git a/Cargo.lock b/Cargo.lock index a08d43a014c06..2917b9ef5d91a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3536,6 +3536,7 @@ dependencies = [ "ar_archive_writer", "arrayvec", "bitflags", + "bstr", "cc", "either", "itertools", diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3254b5d38e7a4..904297b987268 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" +bstr = "1.11.3" # Pinned so `cargo update` bumps don't cause breakage. Please also update the # `cc` in `rustc_llvm` if you update the `cc` here. cc = "=1.2.7" diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index b3c5b86ccf430..63023fdba20fc 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -13,6 +13,7 @@ pub(crate) struct Command { args: Vec, env: Vec<(OsString, OsString)>, env_remove: Vec, + env_clear: bool, } #[derive(Clone)] @@ -36,7 +37,13 @@ impl Command { } fn _new(program: Program) -> Command { - Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() } + Command { + program, + args: Vec::new(), + env: Vec::new(), + env_remove: Vec::new(), + env_clear: false, + } } pub(crate) fn arg>(&mut self, arg: P) -> &mut Command { @@ -79,6 +86,11 @@ impl Command { self } + pub(crate) fn env_clear(&mut self) -> &mut Command { + self.env_clear = true; + self + } + fn _env_remove(&mut self, key: &OsStr) { self.env_remove.push(key.to_owned()); } @@ -106,6 +118,9 @@ impl Command { for k in &self.env_remove { ret.env_remove(k); } + if self.env_clear { + ret.env_clear(); + } ret } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index df35b5e8426f1..ba59bd1266af7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -991,6 +991,7 @@ fn link_natively( command: cmd, escaped_output, verbose: sess.opts.verbose, + sysroot_dir: sess.sysroot.clone(), }; sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index c7213bbc801f9..5e684632fb247 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> { pub command: Command, pub escaped_output: String, pub verbose: bool, + pub sysroot_dir: PathBuf, } impl Diagnostic<'_, G> for LinkingFailed<'_> { @@ -364,6 +365,8 @@ impl Diagnostic<'_, G> for LinkingFailed<'_> { if self.verbose { diag.note(format!("{:?}", self.command)); } else { + self.command.env_clear(); + enum ArgGroup { Regular(OsString), Objects(usize), @@ -398,26 +401,55 @@ impl Diagnostic<'_, G> for LinkingFailed<'_> { args.push(ArgGroup::Regular(arg)); } } - self.command.args(args.into_iter().map(|arg_group| match arg_group { - ArgGroup::Regular(arg) => arg, - ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), - ArgGroup::Rlibs(dir, rlibs) => { - let mut arg = dir.into_os_string(); - arg.push("/{"); - let mut first = true; - for rlib in rlibs { - if !first { - arg.push(","); + let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap(); + self.command.args(args.into_iter().map(|arg_group| { + match arg_group { + // SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid. + ArgGroup::Regular(arg) => unsafe { + use bstr::ByteSlice; + OsString::from_encoded_bytes_unchecked( + arg.as_encoded_bytes().replace( + self.sysroot_dir.as_os_str().as_encoded_bytes(), + b"", + ), + ) + }, + ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), + ArgGroup::Rlibs(mut dir, rlibs) => { + let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) { + Ok(short) => { + dir = Path::new("").join(short); + true + } + Err(_) => false, + }; + let mut arg = dir.into_os_string(); + arg.push("/{"); + let mut first = true; + for mut rlib in rlibs { + if !first { + arg.push(","); + } + first = false; + if is_sysroot_dir { + // SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii). + rlib = unsafe { + OsString::from_encoded_bytes_unchecked( + crate_hash + .replace(rlib.as_encoded_bytes(), b"-*") + .into_owned(), + ) + }; + } + arg.push(rlib); } - first = false; - arg.push(rlib); + arg.push("}.rlib"); + arg } - arg.push("}"); - arg } })); - diag.note(format!("{:?}", self.command)); + diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned()); diag.note("some arguments are omitted. use `--verbose` to show all linker arguments"); } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 8a49d63053521..7ef16e4a9667b 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -414,6 +414,8 @@ impl TestCx<'_> { // Provide path to checkout root. This is the top-level directory containing // rust-lang/rust checkout. .env("SOURCE_ROOT", &source_root) + // Path to the build directory. This is usually the same as `source_root.join("build").join("host")`. + .env("BUILD_ROOT", &build_root) // Provide path to stage-corresponding rustc. .env("RUSTC", &self.config.rustc_path) // Provide the directory to libraries that are needed to run the *compiler*. This is not diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index ffd4ca22a0086..7316244b3841d 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -90,7 +90,7 @@ pub use artifact_names::{ /// Path-related helpers. pub use path_helpers::{ cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix, - not_contains, path, shallow_find_files, source_root, + not_contains, path, shallow_find_files, build_root, source_root, }; /// Helpers for scoped test execution where certain properties are attempted to be maintained. diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 87901793a921e..1c59f2feea4c7 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -34,6 +34,12 @@ pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } +/// Path to the build directory root. +#[must_use] +pub fn build_root() -> PathBuf { + env_var("BUILD_ROOT").into() +} + /// Browse the directory `path` non-recursively and return all files which respect the parameters /// outlined by `closure`. #[track_caller] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d4cbc37f6d2b3..e9e2deb240f5f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -253,6 +253,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "bitflags", "blake3", "block-buffer", + "bstr", "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 4d21c5ea5690a..88e467e6cce3f 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -1,8 +1,16 @@ -use run_make_support::{Rustc, rustc}; +use run_make_support::{Rustc, diff, regex, rustc}; fn run_rustc() -> Rustc { let mut rustc = rustc(); - rustc.arg("main.rs").output("main").linker("./fake-linker"); + rustc + .arg("main.rs") + // NOTE: `link-self-contained` can vary depending on config.toml. + // Make sure we use a consistent value. + .arg("-Clink-self-contained=-linker") + .arg("-Clinker-flavor=gnu-cc") + .arg("-Zunstable-options") + .output("main") + .linker("./fake-linker"); rustc } @@ -11,18 +19,29 @@ fn main() { rustc().arg("fake-linker.rs").output("fake-linker").run(); // Make sure we don't show the linker args unless `--verbose` is passed - run_rustc() - .link_arg("run_make_error") - .verbose() - .run_fail() - .assert_stderr_contains_regex("fake-linker.*run_make_error") + let out = run_rustc().link_arg("run_make_error").verbose().run_fail(); + out.assert_stderr_contains_regex("fake-linker.*run_make_error") .assert_stderr_not_contains("object files omitted") + .assert_stderr_contains("PATH=\"") .assert_stderr_contains_regex(r"lib(/|\\\\)libstd"); - run_rustc() - .link_arg("run_make_error") - .run_fail() - .assert_stderr_contains("fake-linker") + + let out = run_rustc().link_arg("run_make_error").run_fail(); + out.assert_stderr_contains("fake-linker") .assert_stderr_contains("object files omitted") .assert_stderr_contains_regex(r"\{") + .assert_stderr_not_contains("PATH=\"") .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd"); + + // FIXME: we should have a version of this for mac and windows + if run_make_support::target() == "x86_64-unknown-linux-gnu" { + diff() + .expected_file("short-error.txt") + .actual_text("(linker error)", out.stderr()) + .normalize(r#"/rustc[^/]*/"#, "/rustc/") + .normalize( + regex::escape(run_make_support::build_root().to_str().unwrap()), + "/build-root", + ) + .run(); + } } diff --git a/tests/run-make/linker-warning/short-error.txt b/tests/run-make/linker-warning/short-error.txt new file mode 100644 index 0000000000000..dd3b742bbfd56 --- /dev/null +++ b/tests/run-make/linker-warning/short-error.txt @@ -0,0 +1,9 @@ +error: linking with `./fake-linker` failed: exit status: 1 + | + = note: "./fake-linker" "-m64" "/tmp/rustc/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: error: baz + + +error: aborting due to 1 previous error + From a745b602c352c84b852a9bd0d134691ebc7c7a2c Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 22 Jan 2025 18:13:53 -0500 Subject: [PATCH 3/9] Only use linker-flavor=gnu-cc if we're actually going to compare the output It doesn't exist on MacOS. It's strange to me why the flavor is platform specific; I would expect you to be able to use any userspace on any OS? But trying to do this outside of Linux is already kinda weird, so. --- tests/run-make/linker-warning/rmake.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 88e467e6cce3f..f1a97af75d8af 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -7,10 +7,13 @@ fn run_rustc() -> Rustc { // NOTE: `link-self-contained` can vary depending on config.toml. // Make sure we use a consistent value. .arg("-Clink-self-contained=-linker") - .arg("-Clinker-flavor=gnu-cc") .arg("-Zunstable-options") .output("main") .linker("./fake-linker"); + if run_make_support::target() == "x86_64-unknown-linux-gnu" { + // The value of `rust.lld` is different between CI and locally. Override it explicitly. + rustc.arg("-Clinker-flavor=gnu-cc"); + } rustc } From aaccb71da9f0954ee5433f61ae8274b29f6da1c5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 20 Jan 2025 11:38:48 +0100 Subject: [PATCH 4/9] Fix sparcv8plus test on LLVM 20 Split this into two tests, one for LLVM 19 and one for LLVM 20. --- tests/ui/abi/sparcv8plus-llvm19.rs | 43 +++++++++++++++++++ tests/ui/abi/sparcv8plus-llvm19.sparc.stderr | 8 ++++ .../sparcv8plus-llvm19.sparc_cpu_v9.stderr | 8 ++++ ...-llvm19.sparc_cpu_v9_feature_v8plus.stderr | 8 ++++ ...cv8plus-llvm19.sparc_feature_v8plus.stderr | 8 ++++ .../abi/sparcv8plus-llvm19.sparcv8plus.stderr | 8 ++++ tests/ui/abi/sparcv8plus.rs | 6 +-- tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr | 6 +-- ...cv8plus.sparc_cpu_v9_feature_v8plus.stderr | 2 +- .../sparcv8plus.sparc_feature_v8plus.stderr | 2 +- tests/ui/abi/sparcv8plus.sparcv8plus.stderr | 2 +- 11 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 tests/ui/abi/sparcv8plus-llvm19.rs create mode 100644 tests/ui/abi/sparcv8plus-llvm19.sparc.stderr create mode 100644 tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr create mode 100644 tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr create mode 100644 tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr create mode 100644 tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr diff --git a/tests/ui/abi/sparcv8plus-llvm19.rs b/tests/ui/abi/sparcv8plus-llvm19.rs new file mode 100644 index 0000000000000..a884e5ca06f10 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.rs @@ -0,0 +1,43 @@ +//@ revisions: sparc sparcv8plus sparc_cpu_v9 sparc_feature_v8plus sparc_cpu_v9_feature_v8plus +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc_cpu_v9] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 +//@[sparc_cpu_v9] needs-llvm-components: sparc +//@[sparc_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-feature=+v8plus +//@[sparc_feature_v8plus] needs-llvm-components: sparc +//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus +//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc +//@ exact-llvm-major-version: 19 + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[rustc_builtin_macro] +macro_rules! compile_error { + () => {}; +} + +#[cfg(all(not(target_feature = "v8plus"), not(target_feature = "v9")))] +compile_error!("-v8plus,-v9"); +//[sparc]~^ ERROR -v8plus,-v9 + +// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20) +#[cfg(all(target_feature = "v8plus", target_feature = "v9"))] +compile_error!("+v8plus,+v9"); +//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9 + +// FIXME: should be rejected +#[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))] +compile_error!("+v8plus,-v9 (FIXME)"); +//[sparc_feature_v8plus]~^ ERROR +v8plus,-v9 (FIXME) + +#[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))] +compile_error!("-v8plus,+v9"); diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr new file mode 100644 index 0000000000000..7eedf26135f54 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr @@ -0,0 +1,8 @@ +error: -v8plus,-v9 + --> $DIR/sparcv8plus-llvm19.rs:29:1 + | +LL | compile_error!("-v8plus,-v9"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr new file mode 100644 index 0000000000000..ac61df3567808 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr @@ -0,0 +1,8 @@ +error: +v8plus,+v9 + --> $DIR/sparcv8plus-llvm19.rs:34:1 + | +LL | compile_error!("+v8plus,+v9"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr new file mode 100644 index 0000000000000..ac61df3567808 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr @@ -0,0 +1,8 @@ +error: +v8plus,+v9 + --> $DIR/sparcv8plus-llvm19.rs:34:1 + | +LL | compile_error!("+v8plus,+v9"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr new file mode 100644 index 0000000000000..1bf7a3ad76a83 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr @@ -0,0 +1,8 @@ +error: +v8plus,-v9 (FIXME) + --> $DIR/sparcv8plus-llvm19.rs:39:1 + | +LL | compile_error!("+v8plus,-v9 (FIXME)"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr new file mode 100644 index 0000000000000..ac61df3567808 --- /dev/null +++ b/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr @@ -0,0 +1,8 @@ +error: +v8plus,+v9 + --> $DIR/sparcv8plus-llvm19.rs:34:1 + | +LL | compile_error!("+v8plus,+v9"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/sparcv8plus.rs b/tests/ui/abi/sparcv8plus.rs index 108279b34949b..a78ae0cd32889 100644 --- a/tests/ui/abi/sparcv8plus.rs +++ b/tests/ui/abi/sparcv8plus.rs @@ -9,7 +9,7 @@ //@[sparc_feature_v8plus] needs-llvm-components: sparc //@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus //@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc -//@ min-llvm-version: 19 +//@ min-llvm-version: 20 #![crate_type = "rlib"] #![feature(no_core, rustc_attrs, lang_items)] @@ -29,10 +29,9 @@ macro_rules! compile_error { compile_error!("-v8plus,-v9"); //[sparc]~^ ERROR -v8plus,-v9 -// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20) #[cfg(all(target_feature = "v8plus", target_feature = "v9"))] compile_error!("+v8plus,+v9"); -//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9 +//[sparcv8plus,sparc_cpu_v9_feature_v8plus]~^ ERROR +v8plus,+v9 // FIXME: should be rejected #[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))] @@ -41,3 +40,4 @@ compile_error!("+v8plus,-v9 (FIXME)"); #[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))] compile_error!("-v8plus,+v9"); +//[sparc_cpu_v9]~^ ERROR -v8plus,+v9 diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr index 5e1e1fa5c798f..00fd7ef4ea8fb 100644 --- a/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr @@ -1,7 +1,7 @@ -error: +v8plus,+v9 - --> $DIR/sparcv8plus.rs:34:1 +error: -v8plus,+v9 + --> $DIR/sparcv8plus.rs:42:1 | -LL | compile_error!("+v8plus,+v9"); +LL | compile_error!("-v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr index 5e1e1fa5c798f..a3c74e67f8f11 100644 --- a/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,+v9 - --> $DIR/sparcv8plus.rs:34:1 + --> $DIR/sparcv8plus.rs:33:1 | LL | compile_error!("+v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr index 8a5375a46bc05..84f560d158ca9 100644 --- a/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,-v9 (FIXME) - --> $DIR/sparcv8plus.rs:39:1 + --> $DIR/sparcv8plus.rs:38:1 | LL | compile_error!("+v8plus,-v9 (FIXME)"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparcv8plus.stderr b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr index 5e1e1fa5c798f..a3c74e67f8f11 100644 --- a/tests/ui/abi/sparcv8plus.sparcv8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,+v9 - --> $DIR/sparcv8plus.rs:34:1 + --> $DIR/sparcv8plus.rs:33:1 | LL | compile_error!("+v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 2718710d4a505019c46ccc7db42d890f230de25e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 20 Jan 2025 12:08:27 +0100 Subject: [PATCH 5/9] Fix x86_64-bigint-helpers test on LLVM 20 LLVM 20 choses a different unroll factor for the loop. --- tests/assembly/x86_64-bigint-helpers.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/assembly/x86_64-bigint-helpers.rs b/tests/assembly/x86_64-bigint-helpers.rs index 198e554353909..3ad253a2bd0fe 100644 --- a/tests/assembly/x86_64-bigint-helpers.rs +++ b/tests/assembly/x86_64-bigint-helpers.rs @@ -2,6 +2,9 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -O -C target-cpu=x86-64-v4 //@ compile-flags: -C llvm-args=-x86-asm-syntax=intel +//@ revisions: llvm-pre-20 llvm-20 +//@ [llvm-20] min-llvm-version: 20 +//@ [llvm-pre-20] max-llvm-major-version: 19 #![no_std] #![feature(bigint_helper_methods)] @@ -20,12 +23,16 @@ pub unsafe extern "sysv64" fn bigint_chain_carrying_add( n: usize, mut carry: bool, ) -> bool { - // CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] - // CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] - // CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] - // CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] - // CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] - // CHECK: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] + // llvm-pre-20: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] + // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] + // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] + // llvm-pre-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] + // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] + // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] + // llvm-20: adc [[TEMP:r..]], qword ptr [rdx + 8*[[IND:r..]]] + // llvm-20: mov qword ptr [rdi + 8*[[IND]]], [[TEMP]] + // llvm-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 8] + // llvm-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] for i in 0..n { (*dest.add(i), carry) = u64::carrying_add(*src1.add(i), *src2.add(i), carry); } From 7c885c104d7260d625bc54cdad615e74710e2376 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 19 Jan 2025 08:54:28 -0500 Subject: [PATCH 6/9] Compare object files, not PATH PATH is never printed on Windows. --- tests/run-make/linker-warning/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index f1a97af75d8af..3936d68276e16 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -25,14 +25,14 @@ fn main() { let out = run_rustc().link_arg("run_make_error").verbose().run_fail(); out.assert_stderr_contains_regex("fake-linker.*run_make_error") .assert_stderr_not_contains("object files omitted") - .assert_stderr_contains("PATH=\"") + .assert_stderr_contains(r".rcgu.o") .assert_stderr_contains_regex(r"lib(/|\\\\)libstd"); let out = run_rustc().link_arg("run_make_error").run_fail(); out.assert_stderr_contains("fake-linker") .assert_stderr_contains("object files omitted") .assert_stderr_contains_regex(r"\{") - .assert_stderr_not_contains("PATH=\"") + .assert_stderr_not_contains(r".rcgu.o") .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd"); // FIXME: we should have a version of this for mac and windows From 7786f7f38842d705f1d031c5ba08b10ef5638927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:01:49 +0800 Subject: [PATCH 7/9] run-make-support: add `sysroot` helper Convenience helper for `rustc --print=sysroot`. --- src/tools/run-make-support/src/external_deps/rustc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 8894ea7fb209b..b70db7130f677 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -1,5 +1,6 @@ use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::FromStr as _; use crate::command::Command; use crate::env::env_var; @@ -390,3 +391,10 @@ impl Rustc { self } } + +/// Query the sysroot path corresponding `rustc --print=sysroot`. +#[track_caller] +pub fn sysroot() -> PathBuf { + let path = rustc().print("sysroot").run().stdout_utf8(); + PathBuf::from_str(path.trim()).unwrap() +} From 1912d565a8c6aa6ebe82b7fc753b07a89ff2b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:03:21 +0800 Subject: [PATCH 8/9] run-make-support: improve docs for `assert_exit_code` --- src/tools/run-make-support/src/command.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index b4dc753ab5347..c31e79e167389 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -388,9 +388,15 @@ impl CompletedProcess { self } + /// Check the **exit status** of the process. On Unix, this is *not* the **wait status**. + /// + /// See [`std::process::ExitStatus::code`]. This is not to be confused with + /// [`std::process::ExitCode`]. #[track_caller] pub fn assert_exit_code(&self, code: i32) -> &Self { - assert!(self.output.status.code() == Some(code)); + // FIXME(jieyouxu): this should really be named `exit_status`, because std has an `ExitCode` + // that means a different thing. + assert_eq!(self.output.status.code(), Some(code)); self } } From 388a52f55151186731eec45f52a3786112ee3dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:03:18 +0800 Subject: [PATCH 9/9] tests: port `translation` to rmake.rs Co-authored-by: Oneirical --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/translation/Makefile | 78 -------- tests/run-make/translation/rmake.rs | 174 ++++++++++++++++++ 3 files changed, 174 insertions(+), 79 deletions(-) delete mode 100644 tests/run-make/translation/Makefile create mode 100644 tests/run-make/translation/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6f0fd09b353a5..e75d3dc2147bc 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,3 +1,2 @@ run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile -run-make/translation/Makefile diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile deleted file mode 100644 index 07e0547cfa090..0000000000000 --- a/tests/run-make/translation/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -include ../tools.mk - -# This test uses `ln -s` rather than copying to save testing time, but its -# usage doesn't work on Windows. -# ignore-windows - -SYSROOT:=$(shell $(RUSTC) --print sysroot) -FAKEROOT=$(TMPDIR)/fakeroot -RUSTC_LOG:=rustc_error_messages -export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1 - -all: normal custom missing broken sysroot sysroot-invalid sysroot-missing - -# Check that the test works normally, using the built-in fallback bundle. -normal: test.rs - $(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle can be loaded and will be preferentially used -# where possible. -custom: test.rs working.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message" - -# Check that a primary bundle with a broken message (e.g. a interpolated -# variable is missing) will use the fallback bundle. -missing: test.rs missing.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle without the desired message will use the fallback -# bundle. -broken: test.rs broken.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a locale can be loaded from the sysroot given a language -# identifier by making a local copy of the sysroot and adding the custom locale -# to it. -sysroot: test.rs working.ftl - rm -rf $(FAKEROOT) - mkdir $(FAKEROOT) - ln -s $(SYSROOT)/* $(FAKEROOT) - rm -f $(FAKEROOT)/lib - mkdir $(FAKEROOT)/lib - ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib - rm -f $(FAKEROOT)/lib/rustlib - mkdir $(FAKEROOT)/lib/rustlib - ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib - rm -f $(FAKEROOT)/lib/rustlib/src - mkdir $(FAKEROOT)/lib/rustlib/src - ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src - # When download-rustc is enabled, `$(SYSROOT)` will have a share directory. Delete the link to it. - rm -f $(FAKEROOT)/share - mkdir -p $(FAKEROOT)/share/locale/zh-CN/ - ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "this is a test message" - -# Check that the compiler errors out when the sysroot requested cannot be -# found. This test might start failing if there actually exists a Klingon -# translation of rustc's error messages. -sysroot-missing: - $(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | $(CGREP) "missing locale directory" - -# Check that the compiler errors out when the directory for the locale in the -# sysroot is actually a file. -sysroot-invalid: test.rs working.ftl - rm -rf $(FAKEROOT) - mkdir $(FAKEROOT) - ln -s $(SYSROOT)/* $(FAKEROOT) - rm -f $(FAKEROOT)/lib - mkdir $(FAKEROOT)/lib - ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib - rm -f $(FAKEROOT)/lib/rustlib - mkdir $(FAKEROOT)/lib/rustlib - ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib - rm -f $(FAKEROOT)/lib/rustlib/src - mkdir $(FAKEROOT)/lib/rustlib/src - ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src - mkdir -p $(FAKEROOT)/share/locale - touch $(FAKEROOT)/share/locale/zh-CN - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory" diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs new file mode 100644 index 0000000000000..79b9c0dd67896 --- /dev/null +++ b/tests/run-make/translation/rmake.rs @@ -0,0 +1,174 @@ +//! Smoke test for the rustc diagnostics translation infrastructure. +//! +//! # References +//! +//! - Current tracking issue: . +//! - Old tracking issue: +//! - Initial translation infra implementation: . + +// This test uses symbolic links to stub out a fake sysroot to save testing time. +//@ needs-symlink +//@ needs-subprocess + +#![deny(warnings)] + +use std::path::{Path, PathBuf}; + +use run_make_support::rustc::sysroot; +use run_make_support::{cwd, rfs, run_in_tmpdir, rustc}; + +fn main() { + builtin_fallback_bundle(); + additional_primary_bundle(); + missing_slug_prefers_fallback_bundle(); + broken_primary_bundle_prefers_fallback_bundle(); + locale_sysroot(); + missing_sysroot(); + file_sysroot(); +} + +/// Check that the test works normally, using the built-in fallback bundle. +fn builtin_fallback_bundle() { + rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle can be loaded and will be preferentially used where possible. +fn additional_primary_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=working.ftl") + .run_fail() + .assert_stderr_contains("this is a test message"); +} + +/// Check that a primary bundle without the desired message will use the fallback bundle. +fn missing_slug_prefers_fallback_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=missing.ftl") + .run_fail() + .assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not +/// provided) will use the fallback bundle. +fn broken_primary_bundle_prefers_fallback_bundle() { + // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional + // `broken.ftl`, even though the original intention seems to be that it should gracefully + // failover to the fallback bundle. + + rustc() + .env("RUSTC_ICE", "0") // disable ICE dump file, not needed + .input("test.rs") + .arg("-Ztranslate-additional-ftl=broken.ftl") + .run_fail() + .assert_exit_code(101); +} + +#[track_caller] +fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) { + for entry in rfs::read_dir(src_dir) { + let entry = entry.unwrap(); + let src_entry_path = entry.path(); + let src_filename = src_entry_path.file_name().unwrap(); + let meta = rfs::symlink_metadata(&src_entry_path); + + if meta.is_symlink() || meta.is_file() { + rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename)); + } else if meta.is_dir() { + rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename)); + } else { + unreachable!() + } + } +} + +#[track_caller] +fn shallow_symlink_dir_entries_materialize_single_dir( + src_dir: &Path, + dst_dir: &Path, + dir_filename: &str, +) { + shallow_symlink_dir_entries(src_dir, dst_dir); + rfs::remove_file(dst_dir.join(dir_filename)); + rfs::create_dir_all(dst_dir.join(dir_filename)); +} + +#[track_caller] +fn setup_fakeroot_parents() -> PathBuf { + let sysroot = sysroot(); + let fakeroot = cwd().join("fakeroot"); + rfs::create_dir_all(&fakeroot); + shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib"); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib"), + &fakeroot.join("lib"), + "rustlib", + ); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib").join("rustlib"), + &fakeroot.join("lib").join("rustlib"), + "src", + ); + shallow_symlink_dir_entries( + &sysroot.join("lib").join("rustlib").join("src"), + &fakeroot.join("lib").join("rustlib").join("src"), + ); + fakeroot +} + +/// Check that a locale can be loaded from the sysroot given a language identifier by making a local +/// copy of the sysroot and adding the custom locale to it. +fn locale_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + + // When download-rustc is enabled, real sysroot will have a share directory. Delete the link + // to it. + let _ = std::fs::remove_file(fakeroot.join("share")); + + let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN"); + rfs::create_dir_all(&fake_locale_path); + rfs::symlink_file( + cwd().join("working.ftl"), + fake_locale_path.join("basic-translation.ftl"), + ); + + rustc() + .env("RUSTC_ICE", "0") + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("this is a test message"); + }); +} + +/// Check that the compiler errors out when the sysroot requested cannot be found. This test might +/// start failing if there actually exists a Klingon translation of rustc's error messages. +fn missing_sysroot() { + run_in_tmpdir(|| { + rustc() + .input("test.rs") + .arg("-Ztranslate-lang=tlh") + .run_fail() + .assert_stderr_contains("missing locale directory"); + }); +} + +/// Check that the compiler errors out when the directory for the locale in the sysroot is actually +/// a file. +fn file_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + rfs::create_dir_all(fakeroot.join("share").join("locale")); + rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir"); + + rustc() + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("is not a directory"); + }); +}