Skip to content

Introduce a //@ needs-crate-type compiletest directive #139469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/doc/rustc-dev-guide/src/tests/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,13 @@ settings:
specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8,
16, ptr` will only run if it supports the comma-separated list of atomic
widths.
- `needs-dynamic-linking` - ignores if target does not support dynamic linking
- `needs-dynamic-linking` ignores if target does not support dynamic linking
(which is orthogonal to it being unable to create `dylib` and `cdylib` crate types)
- `needs-crate-type` — ignores if target platform does not support one or more
of the comma-delimited list of specified crate types. For example,
`//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored
on `wasm32-unknown-unknown` target because the target does not support the
`proc-macro` crate type.

The following directives will check LLVM support:

Expand Down
31 changes: 31 additions & 0 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ pub struct Config {

pub target_cfgs: OnceLock<TargetCfgs>,
pub builtin_cfg_names: OnceLock<HashSet<String>>,
pub supported_crate_types: OnceLock<HashSet<String>>,

pub nocapture: bool,

Expand Down Expand Up @@ -472,6 +473,11 @@ impl Config {
self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
}

/// Get the list of crate types that the target platform supports.
pub fn supported_crate_types(&self) -> &HashSet<String> {
self.supported_crate_types.get_or_init(|| supported_crate_types(self))
}

pub fn has_threads(&self) -> bool {
// Wasm targets don't have threads unless `-threads` is in the target
// name, such as `wasm32-wasip1-threads`.
Expand Down Expand Up @@ -745,6 +751,31 @@ fn builtin_cfg_names(config: &Config) -> HashSet<String> {
.collect()
}

pub const KNOWN_CRATE_TYPES: &[&str] =
&["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"];

fn supported_crate_types(config: &Config) -> HashSet<String> {
let crate_types: HashSet<_> = rustc_output(
config,
&["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"],
Default::default(),
)
.lines()
.map(|l| l.to_string())
.collect();

for crate_type in crate_types.iter() {
assert!(
KNOWN_CRATE_TYPES.contains(&crate_type.as_str()),
"unexpected crate type `{}`: known crate types are {:?}",
crate_type,
KNOWN_CRATE_TYPES
);
}

crate_types
}

fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
let mut command = Command::new(&config.rustc_path);
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/directive-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"min-llvm-version",
"min-system-llvm-version",
"needs-asm-support",
"needs-crate-type",
"needs-deterministic-layouts",
"needs-dlltool",
"needs-dynamic-linking",
Expand Down
48 changes: 46 additions & 2 deletions src/tools/compiletest/src/header/needs.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::common::{Config, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
use crate::header::{IgnoreDecision, llvm_has_libzstd};

pub(super) fn handle_needs(
cache: &CachedNeedsConditions,
config: &Config,
ln: &str,
) -> IgnoreDecision {
// Note thet we intentionally still put the needs- prefix here to make the file show up when
// Note that we intentionally still put the needs- prefix here to make the file show up when
// grepping for a directive name, even though we could technically strip that.
let needs = &[
Need {
Expand Down Expand Up @@ -224,6 +224,50 @@ pub(super) fn handle_needs(
}
}

// FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above.
if name == "needs-crate-type" {
let Some(rest) = rest else {
return IgnoreDecision::Error {
message:
"expected `needs-crate-type` to have a comma-separated list of crate types"
.to_string(),
};
};

// Expect directive value to be a list of comma-separated crate-types.
let specified_crate_types = rest
.split(',')
.map(|crate_type| crate_type.trim())
.map(ToString::to_string)
.collect::<Vec<String>>();

for crate_type in &specified_crate_types {
if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) {
return IgnoreDecision::Error {
message: format!(
"unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \
a known crate type, known values are `{:?}`",
KNOWN_CRATE_TYPES
),
};
}
}

let satisfies_all_crate_types = specified_crate_types
.iter()
.all(|specified| config.supported_crate_types().contains(specified));
if satisfies_all_crate_types {
return IgnoreDecision::Continue;
} else {
return IgnoreDecision::Ignore {
reason: format!(
"skipping test as target does not support all of the crate types `{:?}`",
specified_crate_types
),
};
}
}

if !name.starts_with("needs-") {
return IgnoreDecision::Continue;
}
Expand Down
38 changes: 38 additions & 0 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,3 +902,41 @@ fn test_rustc_abi() {
assert!(!check_ignore(&config, "//@ ignore-rustc_abi-x86-sse2"));
assert!(check_ignore(&config, "//@ only-rustc_abi-x86-sse2"));
}

#[test]
fn test_supported_crate_types() {
// Basic assumptions check on under-test compiler's `--print=supported-crate-types` output based
// on knowledge about the cherry-picked `x86_64-unknown-linux-gnu` and `wasm32-unknown-unknown`
// targets. Also smoke tests the `needs-crate-type` directive itself.

use std::collections::HashSet;

let config = cfg().target("x86_64-unknown-linux-gnu").build();
assert_eq!(
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
HashSet::from(["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]),
);
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
assert!(!check_ignore(&config, "//@ needs-crate-type: dylib"));
assert!(!check_ignore(
&config,
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
));

let config = cfg().target("wasm32-unknown-unknown").build();
assert_eq!(
config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
HashSet::from(["bin", "cdylib", "lib", "rlib", "staticlib"]),
);

// rlib is supported
assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
// dylib is not
assert!(check_ignore(&config, "//@ needs-crate-type: dylib"));
// If multiple crate types are specified, then all specified crate types need to be supported.
assert!(check_ignore(&config, "//@ needs-crate-type: cdylib, dylib"));
assert!(check_ignore(
&config,
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
));
}
1 change: 1 addition & 0 deletions src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ pub fn parse_config(args: Vec<String>) -> Config {

target_cfgs: OnceLock::new(),
builtin_cfg_names: OnceLock::new(),
supported_crate_types: OnceLock::new(),

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

Expand Down
9 changes: 3 additions & 6 deletions tests/ui/invalid-compile-flags/crate-type-flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
//!
//! This test does not try to check if the output artifacts are valid.

// FIXME(#132309): add a proper `supports-crate-type` directive.

// Single valid crate types should pass
//@ revisions: lib rlib staticlib dylib cdylib bin proc_dash_macro

Expand All @@ -17,19 +15,18 @@
//@[staticlib] compile-flags: --crate-type=staticlib
//@[staticlib] check-pass

//@[dylib] ignore-musl (dylib is supported, but musl libc is statically linked by default)
//@[dylib] ignore-wasm (dylib is not supported)
//@[dylib] needs-crate-type: dylib
//@[dylib] compile-flags: --crate-type=dylib
//@[dylib] check-pass

//@[cdylib] ignore-musl (cdylib is supported, but musl libc is statically linked by default)
//@[cdylib] needs-crate-type: cdylib
//@[cdylib] compile-flags: --crate-type=cdylib
//@[cdylib] check-pass

//@[bin] compile-flags: --crate-type=bin
//@[bin] check-pass

//@[proc_dash_macro] ignore-wasm (proc-macro is not supported)
//@[proc_dash_macro] needs-crate-type: proc-macro
//@[proc_dash_macro] needs-unwind (panic=abort causes warning to be emitted)
//@[proc_dash_macro] compile-flags: --crate-type=proc-macro
//@[proc_dash_macro] check-pass
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/linkage-attr/issue-12133-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
//@ aux-build:issue-12133-rlib.rs
//@ aux-build:issue-12133-dylib.rs
//@ aux-build:issue-12133-dylib2.rs
//@ ignore-wasm32 no dylib support
//@ ignore-musl
//@ needs-crate-type: dylib
//@ needs-dynamic-linking


Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
29 changes: 14 additions & 15 deletions tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,27 @@

// But should fire on non-binary crates.

// FIXME(#132309): dylib crate type is not supported on wasm; we need a proper
// supports-crate-type directive. Also, needs-dynamic-linking should rule out
// musl since it supports neither dylibs nor cdylibs.
//@[dylib_] ignore-wasm
//@[dylib_] ignore-musl
//@[cdylib_] ignore-musl

//@[dylib_] needs-dynamic-linking
//@[cdylib_] compile-flags: --crate-type=cdylib
//@[cdylib_] needs-dynamic-linking
//@[proc_macro_] force-host
//@[proc_macro_] no-prefer-dynamic
//@[cdylib_] needs-crate-type: cdylib

//@[cdylib_] compile-flags: --crate-type=cdylib
//@[dylib_] compile-flags: --crate-type=dylib
//@[dylib_] needs-dynamic-linking
//@[dylib_] needs-crate-type: dylib

//@[lib_] compile-flags: --crate-type=lib

//@[proc_macro_] force-host
//@[proc_macro_] no-prefer-dynamic
//@[proc_macro_] compile-flags: --crate-type=proc-macro
// The compiler may emit a warning that causes stderr output that contains a warning this test does
// not wish to check.
//@[proc_macro_] needs-unwind
//@[proc_macro_] needs-crate-type: proc-macro

//@[rlib_] compile-flags: --crate-type=rlib
//@[staticlib_] compile-flags: --crate-type=staticlib

// The compiler may emit a warning that causes stderr output
// that contains a warning this test does not wish to check.
//@[proc_macro_] needs-unwind
//@[staticlib_] compile-flags: --crate-type=staticlib

#![crate_name = "NonSnakeCase"]
//[cdylib_,dylib_,lib_,proc_macro_,rlib_,staticlib_]~^ ERROR crate `NonSnakeCase` should have a snake case name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: crate `NonSnakeCase` should have a snake case name
--> $DIR/lint-non-snake-case-crate.rs:36:18
--> $DIR/lint-non-snake-case-crate.rs:35:18
|
LL | #![crate_name = "NonSnakeCase"]
| ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
|
note: the lint level is defined here
--> $DIR/lint-non-snake-case-crate.rs:38:9
--> $DIR/lint-non-snake-case-crate.rs:37:9
|
LL | #![deny(non_snake_case)]
| ^^^^^^^^^^^^^^
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/panic-runtime/abort-link-to-unwind-dylib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//@ build-fail
//@ compile-flags:-C panic=abort -C prefer-dynamic
//@ needs-unwind
//@ ignore-musl - no dylibs here
//@ ignore-emscripten
//@ ignore-sgx no dynamic lib support
//@ needs-crate-type: dylib

// This is a test where the local crate, compiled with `panic=abort`, links to
// the standard library **dynamically** which is already linked against
Expand Down
Loading