Skip to content
Draft
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: 7 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,13 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
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`,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_ssa/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2550,6 +2550,9 @@ options! {
"a list of module flags to pass to LLVM (space separated)"),
llvm_plugins: Vec<String> = (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],
Expand Down
40 changes: 40 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/llvm-target-feature.md
Original file line number Diff line number Diff line change
@@ -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

@workingjubilee workingjubilee Jul 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example should exemplify the multi-feature case (either in the same invocation or in another).

```

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

@workingjubilee workingjubilee Jul 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be less ambiguous: some things LLVM calls "target features" should never be part of ours, because they e.g. are incoherent with target_feature(enable), which allows adding them on a per-function basis, and only make sense as whole-program modifiers.

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.
19 changes: 19 additions & 0 deletions tests/codegen-llvm/llvm-target-feature.rs
Original file line number Diff line number Diff line change
@@ -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{{.*}} }
}
2 changes: 2 additions & 0 deletions tests/ui/target-feature/similar-feature-suggestion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Original file line number Diff line number Diff line change
@@ -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]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'+another-feature' is not a recognized feature for this target (ignoring feature)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings (`-C unsafe-allow-abi-mismatch=<value>`)

Original file line number Diff line number Diff line change
@@ -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

19 changes: 19 additions & 0 deletions tests/ui/target_modifiers/incompatible_llvm_target_feature.rs
Original file line number Diff line number Diff line change
@@ -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
Loading