Skip to content

Commit

Permalink
Auto merge of rust-lang#130693 - jieyouxu:minicore, r=<try>
Browse files Browse the repository at this point in the history
[PROTOTYPE] Add minicore test auxiliary and support `//@ use-minicore` directive in ui/assembly/codegen tests

**TODO: work in progress prototype implementation, opened early for MCP to reference**

Context: [Real cross-compiling tests instead of `#![no_core]` silliness rust-lang#130375](rust-lang#130375)

This PR introduces a prototype implementation of `minicore` auxiliary test helper. `minicore` contains stub definitions of std/core prelude items intended for consumption by tests that want the typical prelude items like `Copy` or `Result` in cross-compilation scenarios, but don't want nor need full `-Z build-std` (e.g. `tests/ui/abi/compatibility.rs`).

The `minicore` auxiliary is a single source file `tests/auxiliary/minicore.rs`. The path to this auxiliary is made avaiable from bootstrap to compiletest via the `--minicore-path` compiletest flag. The `minicore` auxiliary is then built, on demand via `//@ use-minicore` compiletest directives, for each test revision for the given target (this distinction is important for when host != target in cross-compilation scenario).

### Implementation steps

- [ ] 1. File an MCP to describe `tests/auxiliary/minicore.rs`, `--minicore-path` compiletest flag, `//@ use-minicore` compiletest directive and the behavior.
- [ ] 2. And some self-tests to sanity check the behavior.
- [ ] 3. Update rustc-dev-guide to describe the new `use-minicore` directive and provide an example, noting that `use-minicore` both requires `no_std` + `no_core` and implies `-C panic=abort` for the test file.

r? `@ghost` (not yet ready for full review, still needs some self-tests and some try-jobs)

(TODO: cc interested people once this passes initial try jobs in cross-compilation scenarios)
cc `@/workingjubilee` `@/RalfJung` `@/nikic` `@/chrisnc` (if this makes sense to you in terms of functionality and UX)

try-job: aarch64-apple
try-job: armhf-gnu
try-job: x86_64-msvc
try-job: test-various
try-job: dist-various-1
  • Loading branch information
bors committed Sep 22, 2024
2 parents 1f9a018 + 9d6f01a commit 01b2fff
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 162 deletions.
3 changes: 3 additions & 0 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1731,6 +1731,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
cmd.arg("--rustc-path").arg(builder.rustc(compiler));

// Minicore auxiliary lib for tests that need std/core stubs in cross-compilation scenarios.
cmd.arg("--minicore-path").arg("tests/auxiliary/minicore.rs");

let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");

if mode == "run-make" {
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/command-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,5 +240,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"unset-rustc-env",
// Used by the tidy check `unknown_revision`.
"unused-revision-names",
"use-minicore",
// tidy-alphabetical-end
];
5 changes: 5 additions & 0 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@ pub struct Config {
/// True if the profiler runtime is enabled for this target.
/// Used by the "needs-profiler-support" header in test files.
pub profiler_support: bool,

/// Path to minicore aux library, used for tests that need std and core stubs in
/// cross-compilation scenarios that do not otherwise need to `-Zbuild-std`. Used in e.g. ABI
/// tests.
pub minicore_path: PathBuf,
}

impl Config {
Expand Down
18 changes: 18 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ pub struct TestProps {
pub filecheck_flags: Vec<String>,
/// Don't automatically insert any `--check-cfg` args
pub no_auto_check_cfg: bool,
/// Build and use minicore as std/core stub for tests in cross-compilation scenarios that don't
/// otherwise need `-Z build-std`.
pub use_minicore: bool,
}

mod directives {
Expand Down Expand Up @@ -263,6 +266,7 @@ mod directives {
pub const LLVM_COV_FLAGS: &'static str = "llvm-cov-flags";
pub const FILECHECK_FLAGS: &'static str = "filecheck-flags";
pub const NO_AUTO_CHECK_CFG: &'static str = "no-auto-check-cfg";
pub const USE_MINICORE: &'static str = "use-minicore";
// This isn't a real directive, just one that is probably mistyped often
pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
}
Expand Down Expand Up @@ -322,6 +326,7 @@ impl TestProps {
llvm_cov_flags: vec![],
filecheck_flags: vec![],
no_auto_check_cfg: false,
use_minicore: false,
}
}

Expand Down Expand Up @@ -597,6 +602,8 @@ impl TestProps {
}

config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);

self.update_use_minicore(ln, config);
},
);

Expand Down Expand Up @@ -710,6 +717,17 @@ impl TestProps {
pub fn local_pass_mode(&self) -> Option<PassMode> {
self.pass_mode
}

pub fn update_use_minicore(&mut self, ln: &str, config: &Config) {
let use_minicore = config.parse_name_directive(ln, directives::USE_MINICORE);
if use_minicore {
if !matches!(config.mode, Mode::Ui | Mode::Codegen | Mode::Assembly) {
panic!("`use-minicore` is only supported for ui, codegen and assembly test modes");
}

self.use_minicore = use_minicore;
}
}
}

/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present.
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ impl ConfigBuilder {
"--git-repository=",
"--nightly-branch=",
"--git-merge-commit-email=",
"--minicore-path=",
];
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();

Expand Down
6 changes: 5 additions & 1 deletion src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
"git-merge-commit-email",
"email address used for finding merge commits",
"EMAIL",
);
)
.reqopt("", "minicore-path", "path to minicore aux library", "PATH");

let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
Expand Down Expand Up @@ -357,6 +358,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),

profiler_support: matches.opt_present("profiler-support"),

minicore_path: opt_path(matches, "minicore-path"),
}
}

Expand Down Expand Up @@ -394,6 +397,7 @@ pub fn log_config(config: &Config) {
logv(c, format!("host-linker: {:?}", config.host_linker));
logv(c, format!("verbose: {}", config.verbose));
logv(c, format!("format: {:?}", config.format));
logv(c, format!("minicore_path: {:?}", config.minicore_path.display()));
logv(c, "\n".to_string());
}

Expand Down
84 changes: 45 additions & 39 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ impl<'test> TestCx<'test> {
_ => AllowUnused::No,
};

let rustc = self.make_compile_args(
let mut rustc = self.make_compile_args(
&self.testpaths.file,
output_file,
emit,
Expand All @@ -836,6 +836,12 @@ impl<'test> TestCx<'test> {
passes,
);

if self.props.use_minicore {
let minicore_path = self.build_minicore();
rustc.arg("--extern");
rustc.arg(&format!("minicore={}", minicore_path.to_str().unwrap()));
}

self.compose_and_run_compiler(rustc, None, self.testpaths)
}

Expand Down Expand Up @@ -1108,8 +1114,8 @@ impl<'test> TestCx<'test> {
}
}

/// `root_testpaths` refers to the path of the original test.
/// the auxiliary and the test with an aux-build have the same `root_testpaths`.
/// `root_testpaths` refers to the path of the original test. the auxiliary and the test with an
/// aux-build have the same `root_testpaths`.
fn compose_and_run_compiler(
&self,
mut rustc: Command,
Expand All @@ -1129,6 +1135,37 @@ impl<'test> TestCx<'test> {
)
}

/// Builds `minicore`. Returns the path to the minicore rlib within the base test output
/// directory.
fn build_minicore(&self) -> PathBuf {
let output_file_path = self.output_base_dir().join("libminicore.rlib");
let mut rustc = self.make_compile_args(
&self.config.minicore_path,
TargetLocation::ThisFile(output_file_path.clone()),
Emit::None,
AllowUnused::Yes,
LinkToAux::No,
vec![],
);

rustc.args(&["--crate-type", "rlib"]);
rustc.arg("-Cpanic=abort");

let res =
self.compose_and_run(rustc, self.config.compile_lib_path.to_str().unwrap(), None, None);
if !res.status.success() {
self.fatal_proc_rec(
&format!(
"auxiliary build of {:?} failed to compile: ",
self.config.minicore_path.display()
),
&res,
);
}

output_file_path
}

/// Builds an aux dependency.
fn build_auxiliary(
&self,
Expand Down Expand Up @@ -1420,6 +1457,11 @@ impl<'test> TestCx<'test> {
rustc.arg(dir_opt);
};

// `use-minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics.
if self.props.use_minicore {
rustc.arg("-Cpanic=abort");
}

match self.config.mode {
Incremental => {
// If we are extracting and matching errors in the new
Expand Down Expand Up @@ -1846,42 +1888,6 @@ impl<'test> TestCx<'test> {
(proc_res, output_path)
}

fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) {
let output_file = self.get_output_file("s");
let input_file = &self.testpaths.file;

let mut emit = Emit::None;
match self.props.assembly_output.as_ref().map(AsRef::as_ref) {
Some("emit-asm") => {
emit = Emit::Asm;
}

Some("bpf-linker") => {
emit = Emit::LinkArgsAsm;
}

Some("ptx-linker") => {
// No extra flags needed.
}

Some(header) => self.fatal(&format!("unknown 'assembly-output' header: {header}")),
None => self.fatal("missing 'assembly-output' header"),
}

let rustc = self.make_compile_args(
input_file,
output_file,
emit,
AllowUnused::No,
LinkToAux::Yes,
Vec::new(),
);

let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
let output_path = self.get_filecheck_file("s");
(proc_res, output_path)
}

fn verify_with_filecheck(&self, output: &Path) -> ProcRes {
let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file);
Expand Down
40 changes: 39 additions & 1 deletion src/tools/compiletest/src/runtest/assembly.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use super::TestCx;
use std::path::PathBuf;

use super::{AllowUnused, Emit, LinkToAux, ProcRes, TestCx};

impl TestCx<'_> {
pub(super) fn run_assembly_test(&self) {
Expand All @@ -16,4 +18,40 @@ impl TestCx<'_> {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}

fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) {
let output_file = self.get_output_file("s");
let input_file = &self.testpaths.file;

let mut emit = Emit::None;
match self.props.assembly_output.as_ref().map(AsRef::as_ref) {
Some("emit-asm") => {
emit = Emit::Asm;
}

Some("bpf-linker") => {
emit = Emit::LinkArgsAsm;
}

Some("ptx-linker") => {
// No extra flags needed.
}

Some(header) => self.fatal(&format!("unknown 'assembly-output' header: {header}")),
None => self.fatal("missing 'assembly-output' header"),
}

let rustc = self.make_compile_args(
input_file,
output_file,
emit,
AllowUnused::No,
LinkToAux::Yes,
Vec::new(),
);

let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
let output_path = self.get_filecheck_file("s");
(proc_res, output_path)
}
}
Loading

0 comments on commit 01b2fff

Please sign in to comment.