Skip to content

Commit 099101e

Browse files
authored
Unrolled build for #151294
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 #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.
2 parents fb292b7 + 841d781 commit 099101e

5 files changed

Lines changed: 137 additions & 5 deletions

File tree

src/doc/rustc-dev-guide/src/tests/compiletest.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,14 +311,20 @@ For example, `./x test tests/debuginfo -- --debugger gdb` will only test GDB com
311311
312312
### Codegen tests
313313

314-
The tests in [`tests/codegen-llvm`] test LLVM code generation. They compile the test
315-
with the `--emit=llvm-ir` flag to emit LLVM IR. They then run the LLVM
314+
The tests in [`tests/codegen-llvm`] test LLVM code generation. They compile the
315+
test with the `--emit=llvm-ir` flag to emit LLVM IR. They then run the LLVM
316316
[FileCheck] tool. The test is annotated with various `// CHECK` comments to
317317
check the generated code. See the [FileCheck] documentation for a tutorial and
318318
more information.
319319

320320
See also the [assembly tests](#assembly-tests) for a similar set of tests.
321321

322+
By default, codegen tests will have `//@ needs-target-std` *implied* (that the
323+
target needs to support std), *unless* the `#![no_std]`/`#![no_core]` attribute
324+
was specified in the test source. You can override this behavior and explicitly
325+
write `//@ needs-target-std` to only run the test when target supports std, even
326+
if the test is `#![no_std]`/`#![no_core]`.
327+
322328
If you need to work with `#![no_std]` cross-compiling tests, consult the
323329
[`minicore` test auxiliary](./minicore.md) chapter.
324330

src/doc/rustc-dev-guide/src/tests/directives.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ The following directives will check rustc build settings and target settings:
200200
on `wasm32-unknown-unknown` target because the target does not support the
201201
`proc-macro` crate type.
202202
- `needs-target-std` — ignores if target platform does not have std support.
203+
- See also [`#![no_std]`/`#![no_core]` and implied `needs-target-std` for
204+
codegen tests](./compiletest.md#codegen-tests).
203205
- `ignore-backends` — ignores the listed backends, separated by whitespace characters.
204206
Please note
205207
that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line

src/tools/compiletest/src/directives.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ pub(crate) struct TestProps {
206206
pub add_minicore: bool,
207207
/// Add these flags to the build of `minicore`.
208208
pub minicore_compile_flags: Vec<String>,
209-
/// Whether line annotatins are required for the given error kind.
209+
/// Whether line annotations are required for the given error kind.
210210
pub dont_require_annotations: HashSet<ErrorKind>,
211211
/// Whether pretty printers should be disabled in gdb.
212212
pub disable_gdb_pretty_printers: bool,
@@ -600,6 +600,19 @@ fn iter_directives(
600600
}
601601
}
602602

603+
// Note: affects all codegen test suites under test mode `codegen`, e.g. `codegen-llvm`.
604+
//
605+
// Codegen tests automatically receive implied `//@ needs-target-std`, unless
606+
// `#![no_std]`/`#![no_core]` attribute was explicitly seen. The rationale is basically to avoid
607+
// having to manually maintain a bunch of `//@ needs-target-std` directives esp. for targets
608+
// tested/built out-of-tree.
609+
if mode == TestMode::Codegen && !file_directives.has_explicit_no_std_core_attribute {
610+
let implied_needs_target_std_line =
611+
line_directive(testfile, LineNumber::ZERO, "//@ needs-target-std")
612+
.expect("valid `needs-target-std` directive line");
613+
it(&implied_needs_target_std_line);
614+
}
615+
603616
for directive_line in &file_directives.lines {
604617
it(directive_line);
605618
}

src/tools/compiletest/src/directives/file.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,37 @@ use crate::directives::line::{DirectiveLine, line_directive};
66
pub(crate) struct FileDirectives<'a> {
77
pub(crate) path: &'a Utf8Path,
88
pub(crate) lines: Vec<DirectiveLine<'a>>,
9+
10+
/// Whether the test source file contains an explicit `#![no_std]`/`#![no_core]` attribute.
11+
pub(crate) has_explicit_no_std_core_attribute: bool,
912
}
1013

1114
impl<'a> FileDirectives<'a> {
1215
pub(crate) fn from_file_contents(path: &'a Utf8Path, file_contents: &'a str) -> Self {
1316
let mut lines = vec![];
17+
let mut has_explicit_no_std_core_attribute = false;
1418

1519
for (line_number, ln) in LineNumber::enumerate().zip(file_contents.lines()) {
1620
let ln = ln.trim();
1721

22+
// Perform a naive check for lines starting with `#![no_std]`/`#![no_core]`, which
23+
// suppresses the implied `//@ needs-target-std` in codegen tests. This ignores
24+
// occurrences in ordinary comments.
25+
//
26+
// This check is imperfect in some edge cases, but we can generally trust our own test
27+
// suite to not hit those edge cases (e.g. `#![no_std]`/`#![no_core]` in multi-line
28+
// comments or string literals). Tests can write `//@ needs-target-std` manually if
29+
// needed.
30+
if ln.starts_with("#![no_std]") || ln.starts_with("#![no_core]") {
31+
has_explicit_no_std_core_attribute = true;
32+
continue;
33+
}
34+
1835
if let Some(directive_line) = line_directive(path, line_number, ln) {
1936
lines.push(directive_line);
2037
}
2138
}
2239

23-
Self { path, lines }
40+
Self { path, lines, has_explicit_no_std_core_attribute }
2441
}
2542
}

src/tools/compiletest/src/directives/tests.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ fn test_parse_normalize_rule() {
105105
#[derive(Default)]
106106
struct ConfigBuilder {
107107
mode: Option<String>,
108+
suite: Option<String>,
108109
channel: Option<String>,
109110
edition: Option<Edition>,
110111
host: Option<String>,
@@ -126,6 +127,11 @@ impl ConfigBuilder {
126127
self
127128
}
128129

130+
fn suite(&mut self, s: &str) -> &mut Self {
131+
self.suite = Some(s.to_owned());
132+
self
133+
}
134+
129135
fn channel(&mut self, s: &str) -> &mut Self {
130136
self.channel = Some(s.to_owned());
131137
self
@@ -196,7 +202,8 @@ impl ConfigBuilder {
196202
"compiletest",
197203
"--mode",
198204
self.mode.as_deref().unwrap_or("ui"),
199-
"--suite=ui",
205+
"--suite",
206+
self.suite.as_deref().unwrap_or("ui"),
200207
"--compile-lib-path=",
201208
"--run-lib-path=",
202209
"--python=",
@@ -1019,6 +1026,93 @@ fn test_needs_target_std() {
10191026
assert!(!check_ignore(&config, "//@ needs-target-std"));
10201027
}
10211028

1029+
#[test]
1030+
fn implied_needs_target_std() {
1031+
let config = cfg().mode("codegen").suite("codegen-llvm").target("x86_64-unknown-none").build();
1032+
// Implied `needs-target-std` due to no `#![no_std]`/`#![no_core]`.
1033+
assert!(check_ignore(&config, ""));
1034+
assert!(check_ignore(&config, "//@ needs-target-std"));
1035+
assert!(!check_ignore(&config, "#![no_std]"));
1036+
assert!(!check_ignore(&config, "#![no_core]"));
1037+
// Make sure that `//@ needs-target-std` takes precedence.
1038+
assert!(check_ignore(
1039+
&config,
1040+
r#"
1041+
//@ needs-target-std
1042+
#![no_std]
1043+
"#
1044+
));
1045+
assert!(check_ignore(
1046+
&config,
1047+
r#"
1048+
//@ needs-target-std
1049+
#![no_core]
1050+
"#
1051+
));
1052+
1053+
let config =
1054+
cfg().mode("codegen").suite("codegen-llvm").target("x86_64-unknown-linux-gnu").build();
1055+
assert!(!check_ignore(&config, ""));
1056+
assert!(!check_ignore(&config, "//@ needs-target-std"));
1057+
assert!(!check_ignore(&config, "#![no_std]"));
1058+
assert!(!check_ignore(&config, "#![no_core]"));
1059+
assert!(!check_ignore(
1060+
&config,
1061+
r#"
1062+
//@ needs-target-std
1063+
#![no_std]
1064+
"#
1065+
));
1066+
assert!(!check_ignore(
1067+
&config,
1068+
r#"
1069+
//@ needs-target-std
1070+
#![no_core]
1071+
"#
1072+
));
1073+
1074+
let config = cfg().mode("ui").suite("ui").target("x86_64-unknown-none").build();
1075+
// The implied `//@ needs-target-std` is only applicable for mode=codegen tests.
1076+
assert!(!check_ignore(&config, ""));
1077+
assert!(check_ignore(&config, "//@ needs-target-std"));
1078+
assert!(!check_ignore(&config, "#![no_std]"));
1079+
assert!(!check_ignore(&config, "#![no_core]"));
1080+
assert!(check_ignore(
1081+
&config,
1082+
r#"
1083+
//@ needs-target-std
1084+
#![no_std]
1085+
"#
1086+
));
1087+
assert!(check_ignore(
1088+
&config,
1089+
r#"
1090+
//@ needs-target-std
1091+
#![no_core]
1092+
"#
1093+
));
1094+
1095+
let config = cfg().mode("ui").suite("ui").target("x86_64-unknown-linux-gnu").build();
1096+
assert!(!check_ignore(&config, ""));
1097+
assert!(!check_ignore(&config, "//@ needs-target-std"));
1098+
assert!(!check_ignore(&config, "#![no_std]"));
1099+
assert!(!check_ignore(&config, "#![no_core]"));
1100+
assert!(!check_ignore(
1101+
&config,
1102+
r#"
1103+
//@ needs-target-std
1104+
#![no_std]
1105+
"#
1106+
));
1107+
assert!(!check_ignore(
1108+
&config,
1109+
r#"
1110+
//@ needs-target-std
1111+
#![no_core]
1112+
"#
1113+
));
1114+
}
1115+
10221116
fn parse_edition_range(line: &str) -> Option<EditionRange> {
10231117
let config = cfg().build();
10241118

0 commit comments

Comments
 (0)