From eb3c9327b1f56fbd391673698f60a4ba8425dae0 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Mon, 29 Jul 2024 13:06:06 -0400 Subject: [PATCH] rewrite cross-lang-lto-clang to rmake --- .../run-make-support/src/assertion_helpers.rs | 32 +++++++++- src/tools/run-make-support/src/command.rs | 33 +++++++++- src/tools/run-make-support/src/lib.rs | 3 +- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/cross-lang-lto-clang/Makefile | 25 -------- tests/run-make/cross-lang-lto-clang/rmake.rs | 61 +++++++++++++++++++ 6 files changed, 126 insertions(+), 29 deletions(-) delete mode 100644 tests/run-make/cross-lang-lto-clang/Makefile create mode 100644 tests/run-make/cross-lang-lto-clang/rmake.rs diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 4b5b349431db9..6d256fc594d8e 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -3,7 +3,7 @@ use std::panic; use std::path::Path; -use crate::fs; +use crate::{fs, regex}; /// Assert that `actual` is equal to `expected`. #[track_caller] @@ -47,6 +47,36 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) } } +/// Assert that `haystack` contains the regex pattern `needle`. +#[track_caller] +pub fn assert_contains_regex, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + let re = regex::Regex::new(needle).unwrap(); + if !re.is_match(haystack) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + +/// Assert that `haystack` does not contain the regex pattern `needle`. +#[track_caller] +pub fn assert_not_contains_regex, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + let re = regex::Regex::new(needle).unwrap(); + if re.is_match(haystack) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} + /// Assert that all files in `dir1` exist and have the same content in `dir2` pub fn assert_dirs_are_equal(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index fb94ff996f0d6..dd7c0e32cf129 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -7,7 +7,10 @@ use std::{ffi, panic}; use build_helper::drop_bomb::DropBomb; use crate::util::handle_failed_output; -use crate::{assert_contains, assert_equals, assert_not_contains}; +use crate::{ + assert_contains, assert_contains_regex, assert_equals, assert_not_contains, + assert_not_contains_regex, +}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -191,6 +194,13 @@ impl CompletedProcess { self } + /// Checks that `stdout` does not contain the regex pattern `unexpected`. + #[track_caller] + pub fn assert_stdout_not_contains_regex>(&self, unexpected: S) -> &Self { + assert_not_contains_regex(&self.stdout_utf8(), unexpected); + self + } + /// Checks that `stdout` contains `expected`. #[track_caller] pub fn assert_stdout_contains>(&self, expected: S) -> &Self { @@ -198,6 +208,13 @@ impl CompletedProcess { self } + /// Checks that `stdout` contains the regex pattern `expected`. + #[track_caller] + pub fn assert_stdout_contains_regex>(&self, expected: S) -> &Self { + assert_contains_regex(&self.stdout_utf8(), expected); + self + } + /// Checks that trimmed `stderr` matches trimmed `expected`. #[track_caller] pub fn assert_stderr_equals>(&self, expected: S) -> &Self { @@ -212,6 +229,13 @@ impl CompletedProcess { self } + /// Checks that `stderr` contains the regex pattern `expected`. + #[track_caller] + pub fn assert_stderr_contains_regex>(&self, expected: S) -> &Self { + assert_contains_regex(&self.stderr_utf8(), expected); + self + } + /// Checks that `stderr` does not contain `unexpected`. #[track_caller] pub fn assert_stderr_not_contains>(&self, unexpected: S) -> &Self { @@ -219,6 +243,13 @@ impl CompletedProcess { self } + /// Checks that `stderr` does not contain the regex pattern `unexpected`. + #[track_caller] + pub fn assert_stderr_not_contains_regex>(&self, unexpected: S) -> &Self { + assert_not_contains_regex(&self.stdout_utf8(), unexpected); + self + } + #[track_caller] pub fn assert_exit_code(&self, code: i32) -> &Self { assert!(self.output.status.code() == Some(code)); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 085120764b463..6dfe7a8bcf7ad 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -84,7 +84,8 @@ pub use path_helpers::{ pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ - assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains, + assert_contains, assert_contains_regex, assert_dirs_are_equal, assert_equals, + assert_not_contains, assert_not_contains_regex, }; pub use string::{ diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 7284feadf9cdd..817259ee92166 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,7 +1,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile diff --git a/tests/run-make/cross-lang-lto-clang/Makefile b/tests/run-make/cross-lang-lto-clang/Makefile deleted file mode 100644 index acf49c8f5c85d..0000000000000 --- a/tests/run-make/cross-lang-lto-clang/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# needs-force-clang-based-tests - -# This test makes sure that cross-language inlining actually works by checking -# the generated machine code. - -include ../tools.mk - -all: cpp-executable rust-executable - -cpp-executable: - $(RUSTC) -Clinker-plugin-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs - $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 - # Make sure we don't find a call instruction to the function we expect to - # always be inlined. - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" - # As a sanity check, make sure we do find a call instruction to a - # non-inlined function - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" - -rust-executable: - $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 - (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) - $(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs new file mode 100644 index 0000000000000..114b2d355793f --- /dev/null +++ b/tests/run-make/cross-lang-lto-clang/rmake.rs @@ -0,0 +1,61 @@ +// This test checks that cross-language inlining actually works by checking +// the generated machine code. +// See https://github.com/rust-lang/rust/pull/57514 + +//@ needs-force-clang-based-tests +// FIXME(#126180): This test doesn't actually run anywhere, because the only +// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. + +use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name}; + +fn main() { + rustc() + .linker_plugin_lto("on") + .output(static_lib_name("rustlib-xlto")) + .opt_level("2") + .codegen_units(1) + .input("rustlib.rs") + .run(); + clang() + .lto("thin") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + // Make sure we don't find a call instruction to the function we expect to + // always be inlined. + llvm_objdump() + .arg("-d") + .input("cmain") + .run() + .assert_stdout_not_contains_regex("call.*rust_always_inlined"); + // As a sanity check, make sure we do find a call instruction to a + // non-inlined function + llvm_objdump() + .arg("-d") + .input("cmain") + .run() + .assert_stdout_contains_regex("call.*rust_never_inlined"); + clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("2") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); + llvm_objdump() + .arg("-d") + .input("rsmain") + .run() + .assert_stdout_not_contains_regex("call.*c_always_inlined"); + llvm_objdump() + .arg("-d") + .input("rsmain") + .run() + .assert_stdout_contains_regex("call.*c_never_inlined"); +}