Skip to content

Commit 57135c4

Browse files
committed
compiletest: add needs-crate-type directive
The `//@ needs-crate-type: $crate_types...` directive takes a comma-separated list of crate types that the target platform must support in order for the test to be run.
1 parent 6813f95 commit 57135c4

File tree

5 files changed

+117
-2
lines changed

5 files changed

+117
-2
lines changed

src/tools/compiletest/src/common.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ pub struct Config {
395395

396396
pub target_cfgs: OnceLock<TargetCfgs>,
397397
pub builtin_cfg_names: OnceLock<HashSet<String>>,
398+
pub supported_crate_types: OnceLock<HashSet<String>>,
398399

399400
pub nocapture: bool,
400401

@@ -472,6 +473,11 @@ impl Config {
472473
self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
473474
}
474475

476+
/// Get the list of crate types that the target platform supports.
477+
pub fn supported_crate_types(&self) -> &HashSet<String> {
478+
self.supported_crate_types.get_or_init(|| supported_crate_types(self))
479+
}
480+
475481
pub fn has_threads(&self) -> bool {
476482
// Wasm targets don't have threads unless `-threads` is in the target
477483
// name, such as `wasm32-wasip1-threads`.
@@ -745,6 +751,31 @@ fn builtin_cfg_names(config: &Config) -> HashSet<String> {
745751
.collect()
746752
}
747753

754+
pub const KNOWN_CRATE_TYPES: &[&str] =
755+
&["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"];
756+
757+
fn supported_crate_types(config: &Config) -> HashSet<String> {
758+
let crate_types: HashSet<_> = rustc_output(
759+
config,
760+
&["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"],
761+
Default::default(),
762+
)
763+
.lines()
764+
.map(|l| l.to_string())
765+
.collect();
766+
767+
for crate_type in crate_types.iter() {
768+
assert!(
769+
KNOWN_CRATE_TYPES.contains(&crate_type.as_str()),
770+
"unexpected crate type `{}`: known crate types are {:?}",
771+
crate_type,
772+
KNOWN_CRATE_TYPES
773+
);
774+
}
775+
776+
crate_types
777+
}
778+
748779
fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
749780
let mut command = Command::new(&config.rustc_path);
750781
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));

src/tools/compiletest/src/directive-list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
133133
"min-llvm-version",
134134
"min-system-llvm-version",
135135
"needs-asm-support",
136+
"needs-crate-type",
136137
"needs-deterministic-layouts",
137138
"needs-dlltool",
138139
"needs-dynamic-linking",

src/tools/compiletest/src/header/needs.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use crate::common::{Config, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
1+
use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
22
use crate::header::{IgnoreDecision, llvm_has_libzstd};
33

44
pub(super) fn handle_needs(
55
cache: &CachedNeedsConditions,
66
config: &Config,
77
ln: &str,
88
) -> IgnoreDecision {
9-
// Note thet we intentionally still put the needs- prefix here to make the file show up when
9+
// Note that we intentionally still put the needs- prefix here to make the file show up when
1010
// grepping for a directive name, even though we could technically strip that.
1111
let needs = &[
1212
Need {
@@ -224,6 +224,50 @@ pub(super) fn handle_needs(
224224
}
225225
}
226226

227+
// FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above.
228+
if name == "needs-crate-type" {
229+
let Some(rest) = rest else {
230+
return IgnoreDecision::Error {
231+
message:
232+
"expected `needs-crate-type` to have a comma-separated list of crate types"
233+
.to_string(),
234+
};
235+
};
236+
237+
// Expect directive value to be a list of comma-separated crate-types.
238+
let specified_crate_types = rest
239+
.split(',')
240+
.map(|crate_type| crate_type.trim())
241+
.map(ToString::to_string)
242+
.collect::<Vec<String>>();
243+
244+
for crate_type in &specified_crate_types {
245+
if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) {
246+
return IgnoreDecision::Error {
247+
message: format!(
248+
"unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \
249+
a known crate type, known values are `{:?}`",
250+
KNOWN_CRATE_TYPES
251+
),
252+
};
253+
}
254+
}
255+
256+
let satisfies_all_crate_types = specified_crate_types
257+
.iter()
258+
.all(|specified| config.supported_crate_types().contains(specified));
259+
if satisfies_all_crate_types {
260+
return IgnoreDecision::Continue;
261+
} else {
262+
return IgnoreDecision::Ignore {
263+
reason: format!(
264+
"skipping test as target does not support all of the crate types `{:?}`",
265+
specified_crate_types
266+
),
267+
};
268+
}
269+
}
270+
227271
if !name.starts_with("needs-") {
228272
return IgnoreDecision::Continue;
229273
}

src/tools/compiletest/src/header/tests.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,3 +902,41 @@ fn test_rustc_abi() {
902902
assert!(!check_ignore(&config, "//@ ignore-rustc_abi-x86-sse2"));
903903
assert!(check_ignore(&config, "//@ only-rustc_abi-x86-sse2"));
904904
}
905+
906+
#[test]
907+
fn test_supported_crate_types() {
908+
// Basic assumptions check on under-test compiler's `--print=supported-crate-types` output based
909+
// on knowledge about the cherry-picked `x86_64-unknown-linux-gnu` and `wasm32-unknown-unknown`
910+
// targets. Also smoke tests the `needs-crate-type` directive itself.
911+
912+
use std::collections::HashSet;
913+
914+
let config = cfg().target("x86_64-unknown-linux-gnu").build();
915+
assert_eq!(
916+
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
917+
HashSet::from(["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]),
918+
);
919+
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
920+
assert!(!check_ignore(&config, "//@ needs-crate-type: dylib"));
921+
assert!(!check_ignore(
922+
&config,
923+
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
924+
));
925+
926+
let config = cfg().target("wasm32-unknown-unknown").build();
927+
assert_eq!(
928+
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
929+
HashSet::from(["bin", "cdylib", "lib", "rlib", "staticlib"]),
930+
);
931+
932+
// rlib is supported
933+
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
934+
// dylib is not
935+
assert!(check_ignore(&config, "//@ needs-crate-type: dylib"));
936+
// If multiple crate types are specified, then all specified crate types need to be supported.
937+
assert!(check_ignore(&config, "//@ needs-crate-type: cdylib, dylib"));
938+
assert!(check_ignore(
939+
&config,
940+
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
941+
));
942+
}

src/tools/compiletest/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
431431

432432
target_cfgs: OnceLock::new(),
433433
builtin_cfg_names: OnceLock::new(),
434+
supported_crate_types: OnceLock::new(),
434435

435436
nocapture: matches.opt_present("no-capture"),
436437

0 commit comments

Comments
 (0)