Rollup merge of #151294 - jieyouxu:infer-needs-target-std, r=Zalathar
compiletest: add implied `needs-target-std` for `codegen` mode tests unless annotated with `#![no_std]`/`#![no_core]` A `codegen` mode test (such as `codegen-llvm` test suite) will now by default have an implied `//@ needs-target-std` directive, *unless* the test explicitly has an `#![no_std]`/`#![no_core]` attribute which disables this behavior. - When a test has both `#![no_std]`/`#![no_core]` and `//@ needs-target-std`, the explicit `//@ needs-target-std` directive will cause the test to be ignored for targets that do not support std still. This is to make it easier to test out-of-tree targets / custom targets (and targets not tested in r-l/r CI) without requiring target maintainers to do a bunch of manual `//@ needs-target-std` busywork. Context: [#t-compiler/help > `compiletest` cannot find `core` library for target != host](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/.60compiletest.60.20cannot.20find.20.60core.60.20library.20for.20target.20!.3D.20host/with/568652419) ## Implementation remarks This is an alternative version of https://github.com/rust-lang/rust/pull/150672, with some differences: - *This* PR applies this implied-`needs-target-std` behavior to all `codegen` test mode tests. - *This* PR does the synthetic directive injection in the same place as implied-`codegen-run` directives. Both are of course hacks, but at least they're together next to each other.
This commit is contained in:
commit
504c7fe65d
5 changed files with 137 additions and 5 deletions
|
|
@ -311,14 +311,20 @@ For example, `./x test tests/debuginfo -- --debugger gdb` will only test GDB com
|
|||
|
||||
### Codegen tests
|
||||
|
||||
The tests in [`tests/codegen-llvm`] test LLVM code generation. They compile the test
|
||||
with the `--emit=llvm-ir` flag to emit LLVM IR. They then run the LLVM
|
||||
The tests in [`tests/codegen-llvm`] test LLVM code generation. They compile the
|
||||
test with the `--emit=llvm-ir` flag to emit LLVM IR. They then run the LLVM
|
||||
[FileCheck] tool. The test is annotated with various `// CHECK` comments to
|
||||
check the generated code. See the [FileCheck] documentation for a tutorial and
|
||||
more information.
|
||||
|
||||
See also the [assembly tests](#assembly-tests) for a similar set of tests.
|
||||
|
||||
By default, codegen tests will have `//@ needs-target-std` *implied* (that the
|
||||
target needs to support std), *unless* the `#![no_std]`/`#![no_core]` attribute
|
||||
was specified in the test source. You can override this behavior and explicitly
|
||||
write `//@ needs-target-std` to only run the test when target supports std, even
|
||||
if the test is `#![no_std]`/`#![no_core]`.
|
||||
|
||||
If you need to work with `#![no_std]` cross-compiling tests, consult the
|
||||
[`minicore` test auxiliary](./minicore.md) chapter.
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ The following directives will check rustc build settings and target settings:
|
|||
on `wasm32-unknown-unknown` target because the target does not support the
|
||||
`proc-macro` crate type.
|
||||
- `needs-target-std` — ignores if target platform does not have std support.
|
||||
- See also [`#![no_std]`/`#![no_core]` and implied `needs-target-std` for
|
||||
codegen tests](./compiletest.md#codegen-tests).
|
||||
- `ignore-backends` — ignores the listed backends, separated by whitespace characters.
|
||||
Please note
|
||||
that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ pub(crate) struct TestProps {
|
|||
pub add_minicore: bool,
|
||||
/// Add these flags to the build of `minicore`.
|
||||
pub minicore_compile_flags: Vec<String>,
|
||||
/// Whether line annotatins are required for the given error kind.
|
||||
/// Whether line annotations are required for the given error kind.
|
||||
pub dont_require_annotations: HashSet<ErrorKind>,
|
||||
/// Whether pretty printers should be disabled in gdb.
|
||||
pub disable_gdb_pretty_printers: bool,
|
||||
|
|
@ -600,6 +600,19 @@ fn iter_directives(
|
|||
}
|
||||
}
|
||||
|
||||
// Note: affects all codegen test suites under test mode `codegen`, e.g. `codegen-llvm`.
|
||||
//
|
||||
// Codegen tests automatically receive implied `//@ needs-target-std`, unless
|
||||
// `#![no_std]`/`#![no_core]` attribute was explicitly seen. The rationale is basically to avoid
|
||||
// having to manually maintain a bunch of `//@ needs-target-std` directives esp. for targets
|
||||
// tested/built out-of-tree.
|
||||
if mode == TestMode::Codegen && !file_directives.has_explicit_no_std_core_attribute {
|
||||
let implied_needs_target_std_line =
|
||||
line_directive(testfile, LineNumber::ZERO, "//@ needs-target-std")
|
||||
.expect("valid `needs-target-std` directive line");
|
||||
it(&implied_needs_target_std_line);
|
||||
}
|
||||
|
||||
for directive_line in &file_directives.lines {
|
||||
it(directive_line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,20 +6,37 @@ use crate::directives::line::{DirectiveLine, line_directive};
|
|||
pub(crate) struct FileDirectives<'a> {
|
||||
pub(crate) path: &'a Utf8Path,
|
||||
pub(crate) lines: Vec<DirectiveLine<'a>>,
|
||||
|
||||
/// Whether the test source file contains an explicit `#![no_std]`/`#![no_core]` attribute.
|
||||
pub(crate) has_explicit_no_std_core_attribute: bool,
|
||||
}
|
||||
|
||||
impl<'a> FileDirectives<'a> {
|
||||
pub(crate) fn from_file_contents(path: &'a Utf8Path, file_contents: &'a str) -> Self {
|
||||
let mut lines = vec![];
|
||||
let mut has_explicit_no_std_core_attribute = false;
|
||||
|
||||
for (line_number, ln) in LineNumber::enumerate().zip(file_contents.lines()) {
|
||||
let ln = ln.trim();
|
||||
|
||||
// Perform a naive check for lines starting with `#![no_std]`/`#![no_core]`, which
|
||||
// suppresses the implied `//@ needs-target-std` in codegen tests. This ignores
|
||||
// occurrences in ordinary comments.
|
||||
//
|
||||
// This check is imperfect in some edge cases, but we can generally trust our own test
|
||||
// suite to not hit those edge cases (e.g. `#![no_std]`/`#![no_core]` in multi-line
|
||||
// comments or string literals). Tests can write `//@ needs-target-std` manually if
|
||||
// needed.
|
||||
if ln.starts_with("#![no_std]") || ln.starts_with("#![no_core]") {
|
||||
has_explicit_no_std_core_attribute = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(directive_line) = line_directive(path, line_number, ln) {
|
||||
lines.push(directive_line);
|
||||
}
|
||||
}
|
||||
|
||||
Self { path, lines }
|
||||
Self { path, lines, has_explicit_no_std_core_attribute }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ fn test_parse_normalize_rule() {
|
|||
#[derive(Default)]
|
||||
struct ConfigBuilder {
|
||||
mode: Option<String>,
|
||||
suite: Option<String>,
|
||||
channel: Option<String>,
|
||||
edition: Option<Edition>,
|
||||
host: Option<String>,
|
||||
|
|
@ -126,6 +127,11 @@ impl ConfigBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
fn suite(&mut self, s: &str) -> &mut Self {
|
||||
self.suite = Some(s.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
fn channel(&mut self, s: &str) -> &mut Self {
|
||||
self.channel = Some(s.to_owned());
|
||||
self
|
||||
|
|
@ -196,7 +202,8 @@ impl ConfigBuilder {
|
|||
"compiletest",
|
||||
"--mode",
|
||||
self.mode.as_deref().unwrap_or("ui"),
|
||||
"--suite=ui",
|
||||
"--suite",
|
||||
self.suite.as_deref().unwrap_or("ui"),
|
||||
"--compile-lib-path=",
|
||||
"--run-lib-path=",
|
||||
"--python=",
|
||||
|
|
@ -1019,6 +1026,93 @@ fn test_needs_target_std() {
|
|||
assert!(!check_ignore(&config, "//@ needs-target-std"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn implied_needs_target_std() {
|
||||
let config = cfg().mode("codegen").suite("codegen-llvm").target("x86_64-unknown-none").build();
|
||||
// Implied `needs-target-std` due to no `#![no_std]`/`#![no_core]`.
|
||||
assert!(check_ignore(&config, ""));
|
||||
assert!(check_ignore(&config, "//@ needs-target-std"));
|
||||
assert!(!check_ignore(&config, "#![no_std]"));
|
||||
assert!(!check_ignore(&config, "#![no_core]"));
|
||||
// Make sure that `//@ needs-target-std` takes precedence.
|
||||
assert!(check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_std]
|
||||
"#
|
||||
));
|
||||
assert!(check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_core]
|
||||
"#
|
||||
));
|
||||
|
||||
let config =
|
||||
cfg().mode("codegen").suite("codegen-llvm").target("x86_64-unknown-linux-gnu").build();
|
||||
assert!(!check_ignore(&config, ""));
|
||||
assert!(!check_ignore(&config, "//@ needs-target-std"));
|
||||
assert!(!check_ignore(&config, "#![no_std]"));
|
||||
assert!(!check_ignore(&config, "#![no_core]"));
|
||||
assert!(!check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_std]
|
||||
"#
|
||||
));
|
||||
assert!(!check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_core]
|
||||
"#
|
||||
));
|
||||
|
||||
let config = cfg().mode("ui").suite("ui").target("x86_64-unknown-none").build();
|
||||
// The implied `//@ needs-target-std` is only applicable for mode=codegen tests.
|
||||
assert!(!check_ignore(&config, ""));
|
||||
assert!(check_ignore(&config, "//@ needs-target-std"));
|
||||
assert!(!check_ignore(&config, "#![no_std]"));
|
||||
assert!(!check_ignore(&config, "#![no_core]"));
|
||||
assert!(check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_std]
|
||||
"#
|
||||
));
|
||||
assert!(check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_core]
|
||||
"#
|
||||
));
|
||||
|
||||
let config = cfg().mode("ui").suite("ui").target("x86_64-unknown-linux-gnu").build();
|
||||
assert!(!check_ignore(&config, ""));
|
||||
assert!(!check_ignore(&config, "//@ needs-target-std"));
|
||||
assert!(!check_ignore(&config, "#![no_std]"));
|
||||
assert!(!check_ignore(&config, "#![no_core]"));
|
||||
assert!(!check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_std]
|
||||
"#
|
||||
));
|
||||
assert!(!check_ignore(
|
||||
&config,
|
||||
r#"
|
||||
//@ needs-target-std
|
||||
#![no_core]
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
fn parse_edition_range(line: &str) -> Option<EditionRange> {
|
||||
let config = cfg().build();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue