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
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine, out: &mut Str
.target
.rust_target_features()
.iter()
.filter_map(|(feature, gate, _implied)| {
.filter_map(|(feature, gate, _implied, _)| {
if !gate.in_cfg() {
// Only list (experimentally) supported features.
return None;
Expand Down
16 changes: 8 additions & 8 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ fn parse_rust_feature_flag<'a>(

let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| {
let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default();
for (f, _, is) in sess.target.rust_target_features() {
for (f, _, is, _) in sess.target.rust_target_features() {
for i in is.iter() {
set.entry(i).or_default().insert(f);
}
Expand Down Expand Up @@ -222,8 +222,8 @@ pub fn cfg_target_feature(
.target
.rust_target_features()
.iter()
.filter(|(feature, _, _)| target_base_has_feature(feature))
.flat_map(|(base_feature, _, _)| {
.filter(|(feature, _, _, _)| target_base_has_feature(feature))
.flat_map(|(base_feature, _, _, _)| {
// Expand the direct base feature into all transitively-implied features. Note that we
// cannot simply use the `implied` field of the tuple since that only contains
// directly-implied features.
Expand Down Expand Up @@ -260,7 +260,7 @@ pub fn cfg_target_feature(
sess.target
.rust_target_features()
.iter()
.filter_map(|(feature, gate, _)| {
.filter_map(|(feature, gate, _, _)| {
// The `allow_unstable` set is used by rustc internally to determine which target
// features are truly available, so we want to return even perma-unstable
// "forbidden" features.
Expand Down Expand Up @@ -330,13 +330,13 @@ pub fn flag_to_backend_features<'a, const N: usize>(
);
// Check feature validity.
if diagnostics {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature);
let feature_state = known_features.iter().find(|&&(v, _, _, _)| v == base_feature);
match feature_state {
None => {
// This is definitely not a valid Rust feature name. Maybe it is a backend
// feature name? If so, give a better error message.
let rust_feature =
known_features.iter().find_map(|&(rust_feature, _, _)| {
known_features.iter().find_map(|&(rust_feature, _, _, _)| {
let backend_features = to_backend_features(rust_feature);
if backend_features.contains(&base_feature)
&& !backend_features.contains(&rust_feature)
Expand All @@ -359,7 +359,7 @@ pub fn flag_to_backend_features<'a, const N: usize>(
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
Some((_, stability, _, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(errors::ForbiddenCTargetFeature {
feature: base_feature,
Expand Down Expand Up @@ -463,7 +463,7 @@ pub(crate) fn provide(providers: &mut Providers) {
.target
.rust_target_features()
.iter()
.map(|(a, b, _)| (a.to_string(), *b))
.map(|(a, b, _, _)| (a.to_string(), *b))
.collect()
}
},
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl CStore {
match (&left_name_val, &right_name_val) {
(Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
cmp::Ordering::Equal => {
if !l.1.consistent(&tcx.sess.opts, Some(&r.1)) {
if !l.1.consistent(&tcx.sess, Some(&r.1)) {
report_diff(
&l.0.prefix,
&l.0.name,
Expand All @@ -424,26 +424,26 @@ impl CStore {
right_name_val = None;
}
cmp::Ordering::Greater => {
if !r.1.consistent(&tcx.sess.opts, None) {
if !r.1.consistent(&tcx.sess, None) {
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
}
right_name_val = None;
}
cmp::Ordering::Less => {
if !l.1.consistent(&tcx.sess.opts, None) {
if !l.1.consistent(&tcx.sess, None) {
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
}
left_name_val = None;
}
},
(Some(l), None) => {
if !l.1.consistent(&tcx.sess.opts, None) {
if !l.1.consistent(&tcx.sess, None) {
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
}
left_name_val = None;
}
(None, Some(r)) => {
if !r.1.consistent(&tcx.sess.opts, None) {
if !r.1.consistent(&tcx.sess, None) {
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
}
right_name_val = None;
Expand Down
61 changes: 56 additions & 5 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use rustc_target::spec::{
use crate::config::*;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use crate::{EarlyDiagCtxt, lint};
use crate::{EarlyDiagCtxt, Session, lint};

macro_rules! insert {
($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
Expand Down Expand Up @@ -85,6 +85,53 @@ pub struct TargetModifier {

mod target_modifier_consistency_check {
use super::*;
pub(super) fn target_feature(
sess: &Session,
l: &TargetModifier,
r: Option<&TargetModifier>,
) -> bool {
fn parse<'a>(session: &'a Session, val: &'a TargetModifier) -> Vec<&'a str> {
let mut target_features = Vec::new();

for feature in session
.target_features
.iter()
.map(|symbol| symbol.as_str())
.chain(val.value_name.split(','))
{
if let Some(feature) = feature.strip_prefix('+') {
if session
.target
.rust_target_features()
.iter()
.any(|(name, _, _, target_modifier)| feature == *name && *target_modifier)
{
target_features.push(feature);
}
} else if let Some(feature) = feature.strip_prefix('-') {
if session
.target
.rust_target_features()
.iter()
.any(|(name, _, _, target_modifier)| feature == *name && *target_modifier)
{
for (index, target_feature) in target_features.iter().enumerate() {
if *target_feature == feature {
target_features.remove(index);
break;
}
}
}
}
}
Comment on lines +96 to +126
Copy link
Member

Choose a reason for hiding this comment

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

I suspect this parsing already exists elsewhere in the codebase -- would it be possible to deduplicate the parsing routine?

Copy link
Member

@bjorn3 bjorn3 Nov 3, 2025

Choose a reason for hiding this comment

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

-Ctarget-features is parsed by parse_rust_feature_flag in cg_ssa. sess.target.features is split on , by cg_llvm and then parsed by LLVM given that it is a set of backend features rather than rust features:

// Features implied by an implicit or explicit `--target`.
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));


target_features
}

let l = parse(sess, l);

if let Some(r) = r { l == parse(sess, r) } else { l.is_empty() }
}
pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool {
let mut lparsed: SanitizerSet = Default::default();
let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) };
Expand Down Expand Up @@ -133,21 +180,25 @@ impl TargetModifier {
}
// Custom consistency check for target modifiers (or default `l.tech_value == r.tech_value`)
// When other is None, consistency with default value is checked
pub fn consistent(&self, opts: &Options, other: Option<&TargetModifier>) -> bool {
pub fn consistent(&self, sess: &Session, other: Option<&TargetModifier>) -> bool {
assert!(other.is_none() || self.opt == other.unwrap().opt);
match self.opt {
OptionsTargetModifiers::CodegenOptions(
CodegenOptionsTargetModifiers::target_feature,
) => {
return target_modifier_consistency_check::target_feature(sess, self, other);
}
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
UnstableOptionsTargetModifiers::sanitizer => {
return target_modifier_consistency_check::sanitizer(self, other);
}
UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => {
return target_modifier_consistency_check::sanitizer_cfi_normalize_integers(
opts, self, other,
&sess.opts, self, other,
);
}
_ => {}
},
_ => {}
};
match other {
Some(other) => self.extend().tech_value == other.extend().tech_value,
Expand Down Expand Up @@ -2172,7 +2223,7 @@ options! {
"which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"),
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select target processor (`rustc --print target-cpus` for details)"),
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
target_feature: String = (String::new(), parse_target_feature, [TRACKED TARGET_MODIFIER],
"target specific attributes. (`rustc --print target-features` for details). \
This feature is unsafe."),
unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
Expand Down
Loading
Loading