From b9d5330b20128f7b69fd42c93365a0a570dc0564 Mon Sep 17 00:00:00 2001 From: fo4025 Date: Sun, 19 Jul 2026 09:48:12 +0800 Subject: [PATCH] Add -Zllvm-target-feature to pass features directly to LLVM Implement MCP 994 (tracking issue 157753): a new unstable flag `-Zllvm-target-feature` that forwards comma-separated `+feat`/`-feat` strings verbatim to the LLVM backend, bypassing Rust's known-feature table. The flag is registered as a target modifier, so mixing different values across crates is an error unless overridden with `-Cunsafe-allow-abi-mismatch=llvm-target-feature`. Non-LLVM backends ignore it, like `-Cllvm-args`. As part of the deprecation path, the warning for unknown features passed via `-Ctarget-feature` now notes that this will become a hard error in a future release and points to `-Zllvm-target-feature` instead. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 7 ++++ compiler/rustc_codegen_ssa/src/diagnostics.rs | 5 +++ .../rustc_codegen_ssa/src/target_features.rs | 2 + compiler/rustc_session/src/options.rs | 3 ++ .../src/compiler-flags/llvm-target-feature.md | 40 +++++++++++++++++++ tests/codegen-llvm/llvm-target-feature.rs | 19 +++++++++ .../similar-feature-suggestion.stderr | 2 + .../auxiliary/wrong_llvm_target_feature.rs | 7 ++++ ....allow_llvm_target_feature_mismatch.stderr | 1 + ..._llvm_target_feature.allow_no_value.stderr | 2 + ...llvm_target_feature.error_generated.stderr | 14 +++++++ .../incompatible_llvm_target_feature.rs | 19 +++++++++ 12 files changed, 121 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/llvm-target-feature.md create mode 100644 tests/codegen-llvm/llvm-target-feature.rs create mode 100644 tests/ui/target_modifiers/auxiliary/wrong_llvm_target_feature.rs create mode 100644 tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_llvm_target_feature_mismatch.stderr create mode 100644 tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_no_value.stderr create mode 100644 tests/ui/target_modifiers/incompatible_llvm_target_feature.error_generated.stderr create mode 100644 tests/ui/target_modifiers/incompatible_llvm_target_feature.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 73b7f699b606d..db20e96ef3b3a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -639,6 +639,13 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { features.push("+reserve-x18".into()); } } + + // -Zllvm-target-feature + for feature in sess.opts.unstable_opts.llvm_target_feature.split(',') { + if !feature.is_empty() { + features.push(feature.into()); + } + } } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, diff --git a/compiler/rustc_codegen_ssa/src/diagnostics.rs b/compiler/rustc_codegen_ssa/src/diagnostics.rs index 1fe52c34e89f4..abe67ac992c7f 100644 --- a/compiler/rustc_codegen_ssa/src/diagnostics.rs +++ b/compiler/rustc_codegen_ssa/src/diagnostics.rs @@ -1224,6 +1224,11 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub feature: &'a str, #[subdiagnostic] pub rust_feature: PossibleFeature<'a>, + #[note( + "passing unknown features via `-Ctarget-feature` is deprecated and will become a hard error in a future release" + )] + #[note("use `-Zllvm-target-feature` to pass features directly to the LLVM backend")] + pub future_compat_note: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 8f459e5a218d2..ce111990654f7 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -313,11 +313,13 @@ pub fn cfg_target_feature<'a, const N: usize>( diagnostics::UnknownCTargetFeature { feature: base_feature, rust_feature: diagnostics::PossibleFeature::Some { rust_feature }, + future_compat_note: true, } } else { diagnostics::UnknownCTargetFeature { feature: base_feature, rust_feature: diagnostics::PossibleFeature::None, + future_compat_note: true, } }; sess.dcx().emit_warn(unknown_feature); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6f3a505c2c26f..70c5e0620f36c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2550,6 +2550,9 @@ options! { "a list of module flags to pass to LLVM (space separated)"), llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], "a list LLVM plugins to enable (space separated)"), + llvm_target_feature: String = (String::new(), parse_string, [TRACKED] { TARGET_MODIFIER: LlvmTargetFeature }, + "a comma-separated list of features to pass directly to the LLVM backend (+feat/-feat); \ + ignored by non-LLVM backends (unstable)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], "generate JSON tracing data file from LLVM data (default: no)"), llvm_writable: bool = (false, parse_bool, [TRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/llvm-target-feature.md b/src/doc/unstable-book/src/compiler-flags/llvm-target-feature.md new file mode 100644 index 0000000000000..d9f7e8f1b0123 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/llvm-target-feature.md @@ -0,0 +1,40 @@ +# `llvm-target-feature` + +The tracking issue for this feature is: [#157753](https://github.com/rust-lang/rust/issues/157753). + +------------------------ + +The `-Zllvm-target-feature` flag passes target feature strings directly to the LLVM +backend, bypassing Rust's known-feature validation. It accepts a comma-separated list of +features in the form `+feat` or `-feat`, for example: + +```sh +rustc -Zllvm-target-feature=+prefer-256-bit main.rs +``` + +Each feature string is forwarded verbatim to LLVM. This allows using LLVM target features +that are not (or not yet) part of Rust's target feature system, for example to match the +ABI of foreign libraries built with features Rust does not recognize. + +Because such features can change the ABI, this flag is registered as a *target modifier*: +linking together crates compiled with different values of this flag is an error by +default. If you are sure the mismatch is sound, it can be overridden with +`-Cunsafe-allow-abi-mismatch=llvm-target-feature`. + +## Scope and interactions + +This flag: + +- does **not** affect `cfg(target_feature)`: conditional compilation will not observe + features passed this way; +- does **not** affect runtime feature detection macros such as `is_x86_feature_detected!`; +- is ignored by non-LLVM codegen backends (like `-Cllvm-args`); +- performs no validation: invalid or unsupported feature names are reported (or silently + ignored) by LLVM itself during codegen. + +## Relationship to `-Ctarget-feature` + +`-Ctarget-feature` is the supported way to toggle target features that Rust recognizes. +Passing feature names unknown to Rust through `-Ctarget-feature` is deprecated and will +eventually become a hard error; use `-Zllvm-target-feature` for LLVM-only features +instead. diff --git a/tests/codegen-llvm/llvm-target-feature.rs b/tests/codegen-llvm/llvm-target-feature.rs new file mode 100644 index 0000000000000..9b0429d87fd5c --- /dev/null +++ b/tests/codegen-llvm/llvm-target-feature.rs @@ -0,0 +1,19 @@ +// Test that `-Zllvm-target-feature` forwards raw feature strings directly to the +// LLVM backend, bypassing Rust's known-feature table. This test uses +// `prefer-256-bit`, an LLVM-only x86 feature that is not listed in rustc's +// `target_features.rs`. + +//@ add-minicore +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zllvm-target-feature=+prefer-256-bit +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] +extern crate minicore; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // CHECK: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+prefer-256-bit{{.*}} } +} diff --git a/tests/ui/target-feature/similar-feature-suggestion.stderr b/tests/ui/target-feature/similar-feature-suggestion.stderr index f39dfd401e07c..80515f2f226b9 100644 --- a/tests/ui/target-feature/similar-feature-suggestion.stderr +++ b/tests/ui/target-feature/similar-feature-suggestion.stderr @@ -2,6 +2,8 @@ warning: unknown and unstable feature specified for `-Ctarget-feature`: `rdrnd` | = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future = help: you might have meant: `rdrand` + = note: passing unknown features via `-Ctarget-feature` is deprecated and will become a hard error in a future release + = note: use `-Zllvm-target-feature` to pass features directly to the LLVM backend warning: 1 warning emitted diff --git a/tests/ui/target_modifiers/auxiliary/wrong_llvm_target_feature.rs b/tests/ui/target_modifiers/auxiliary/wrong_llvm_target_feature.rs new file mode 100644 index 0000000000000..89f755b1eaf7d --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/wrong_llvm_target_feature.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zllvm-target-feature=+fake-feature +//@ needs-llvm-components: x86 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_llvm_target_feature_mismatch.stderr b/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_llvm_target_feature_mismatch.stderr new file mode 100644 index 0000000000000..60d96ab513f12 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_llvm_target_feature_mismatch.stderr @@ -0,0 +1 @@ +'+another-feature' is not a recognized feature for this target (ignoring feature) diff --git a/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_no_value.stderr b/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_no_value.stderr new file mode 100644 index 0000000000000..9f68e6ca919d8 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_llvm_target_feature.allow_no_value.stderr @@ -0,0 +1,2 @@ +error: codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings (`-C unsafe-allow-abi-mismatch=`) + diff --git a/tests/ui/target_modifiers/incompatible_llvm_target_feature.error_generated.stderr b/tests/ui/target_modifiers/incompatible_llvm_target_feature.error_generated.stderr new file mode 100644 index 0000000000000..0958ec9c98412 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_llvm_target_feature.error_generated.stderr @@ -0,0 +1,14 @@ +'+another-feature' is not a recognized feature for this target (ignoring feature) +error: mixing `-Zllvm-target-feature` will cause an ABI mismatch in crate `incompatible_llvm_target_feature` + --> $DIR/incompatible_llvm_target_feature.rs:12:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zllvm-target-feature` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zllvm-target-feature=+another-feature` in this crate is incompatible with `-Zllvm-target-feature=+fake-feature` in dependency `wrong_llvm_target_feature` + = help: set `-Zllvm-target-feature=+fake-feature` in this crate or `-Zllvm-target-feature=+another-feature` in `wrong_llvm_target_feature` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=llvm-target-feature` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/incompatible_llvm_target_feature.rs b/tests/ui/target_modifiers/incompatible_llvm_target_feature.rs new file mode 100644 index 0000000000000..c9717bf1e7755 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_llvm_target_feature.rs @@ -0,0 +1,19 @@ +//@ aux-build:wrong_llvm_target_feature.rs +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zllvm-target-feature=+another-feature +//@ needs-llvm-components: x86 + +//@ revisions:allow_llvm_target_feature_mismatch allow_no_value error_generated +//@[allow_llvm_target_feature_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=llvm-target-feature +//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch +// [error_generated] no extra compile-flags +//@[allow_llvm_target_feature_mismatch] check-pass +//@ ignore-backends: gcc + +#![feature(no_core)] +//[error_generated]~^ ERROR mixing `-Zllvm-target-feature` will cause an ABI mismatch in crate `incompatible_llvm_target_feature` +#![crate_type = "rlib"] +#![no_core] + +extern crate wrong_llvm_target_feature; + +//[allow_no_value]~? ERROR codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings