From 84ac80f1921afc243d71fd0caaa4f2838c294102 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 29 Jul 2024 08:13:50 +1000 Subject: Reformat `use` declarations. The previous commit updated `rustfmt.toml` appropriately. This commit is the outcome of running `x fmt --all` with the new formatting options. --- compiler/rustc_codegen_llvm/src/context.rs | 37 ++++++++++++++---------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src/context.rs') diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 49677dcf12f..ea930421b58 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,19 +1,13 @@ -use crate::attributes; -use crate::back::write::to_llvm_code_model; -use crate::callee::get_fn; -use crate::coverageinfo; -use crate::debuginfo; -use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm; -use crate::llvm_util; -use crate::type_::Type; -use crate::value::Value; +use std::borrow::Borrow; +use std::cell::{Cell, RefCell}; +use std::ffi::CStr; +use std::str; +use libc::c_uint; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::base_n::ToBaseN; -use rustc_data_structures::base_n::ALPHANUMERIC_ONLY; +use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; @@ -24,20 +18,23 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; -use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; +use rustc_session::config::{ + BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet, +}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx}; +use rustc_target::abi::call::FnAbi; +use rustc_target::abi::{HasDataLayout, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; -use libc::c_uint; -use std::borrow::Borrow; -use std::cell::{Cell, RefCell}; -use std::ffi::CStr; -use std::str; +use crate::back::write::to_llvm_code_model; +use crate::callee::get_fn; +use crate::debuginfo::metadata::apply_vcall_visibility_metadata; +use crate::type_::Type; +use crate::value::Value; +use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM /// `llvm::Context` so that several compilation units may be optimized in parallel. -- cgit 1.4.1-3-g733a5 From e6d570241fd2e12fa143938e2b17ba6ec31001da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 12 Jul 2024 03:54:54 -0400 Subject: Specify the integer type of the `powi` LLVM intrinsic Since LLVM (4c7f820b2b20, "Update @llvm.powi to handle different int sizes for the exponent"), the size of the integer can be specified for the `powi` intrinsic. Make use of this so it is more obvious that integer size is consistent across all float types. This feature is available since LLVM 13 (October 2021). Based on bootstrap we currently support >= 17.0, so there should be no support problems. --- compiler/rustc_codegen_llvm/src/context.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src/context.rs') diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ea930421b58..14540d41e7c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> ptr); - ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16); - ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); - ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); - ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128); + ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16); + ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32); + ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64); + ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128); ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 040de1c7dd7..57d5f6fdf50 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -35,10 +35,10 @@ fn get_simple_intrinsic<'ll>( sym::sqrtf64 => "llvm.sqrt.f64", sym::sqrtf128 => "llvm.sqrt.f128", - sym::powif16 => "llvm.powi.f16", - sym::powif32 => "llvm.powi.f32", - sym::powif64 => "llvm.powi.f64", - sym::powif128 => "llvm.powi.f128", + sym::powif16 => "llvm.powi.f16.i32", + sym::powif32 => "llvm.powi.f32.i32", + sym::powif64 => "llvm.powi.f64.i32", + sym::powif128 => "llvm.powi.f128.i32", sym::sinf16 => "llvm.sin.f16", sym::sinf32 => "llvm.sin.f32", -- cgit 1.4.1-3-g733a5 From 484aca885765739d5fa1f3d77e082552d8c4bc58 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 3 Aug 2024 04:45:48 -0400 Subject: Don't use LLVM's target features --- compiler/rustc_codegen_llvm/src/back/write.rs | 8 ++- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 63 ++++++++++++++++++----- compiler/rustc_codegen_ssa/src/target_features.rs | 23 +-------- compiler/rustc_target/src/target_features.rs | 25 +++++++++ 6 files changed, 84 insertions(+), 39 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src/context.rs') diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 5a7909d1511..890fcf508a8 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -95,11 +95,15 @@ pub fn write_output_file<'ll>( } } -pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine { +pub fn create_informational_target_machine( + sess: &Session, + extra_features: bool, +) -> OwnedTargetMachine { let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None }; // Can't use query system here quite yet because this function is invoked before the query // system/tcx is set up. - let features = llvm_util::global_llvm_features(sess, false); + let features = + if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() }; target_machine_factory(sess, config::OptLevel::No, &features)(config) .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise()) } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ea930421b58..1dc3fbfc7b3 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { - let tm = crate::back::write::create_informational_target_machine(tcx.sess); + let tm = crate::back::write::create_informational_target_machine(tcx.sess, true); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 41e9cfd1066..333f1fdf6e0 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -434,7 +434,7 @@ impl ModuleLlvm { ModuleLlvm { llmod_raw, llcx, - tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, true)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c70f6dd8180..e85974b7cc1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -308,7 +308,53 @@ pub fn check_tied_features( /// Used to generate cfg variables and apply features /// Must express features in the way Rust understands them pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { - let target_machine = create_informational_target_machine(sess); + let rust_features = sess + .target + .supported_target_features() + .iter() + .map(|(feature, _, _)| { + (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature)) + }) + .collect::>(); + + let mut features = FxHashSet::default(); + + // Add base features for the target + let target_machine = create_informational_target_machine(sess, false); + features.extend( + sess.target + .supported_target_features() + .iter() + .filter(|(feature, _, _)| { + // skip checking special features, as LLVM may not understands them + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } + // check that all features in a given smallvec are enabled + for llvm_feature in to_llvm_features(sess, feature) { + let cstr = SmallCStr::new(llvm_feature); + if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } { + return false; + } + } + true + }) + .map(|(feature, _, _)| Symbol::intern(feature)), + ); + + // Add enabled features + for llvm_feature in global_llvm_features(sess, false) { + let (add, llvm_feature) = llvm_feature.split_at(1); + let feature = + rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature)); + if add == "+" { + features.extend(sess.target.implied_target_features(std::iter::once(feature))); + } else if add == "-" { + features.remove(&feature); + } + } + + // Filter enabled features based on feature gates sess.target .supported_target_features() .iter() @@ -320,18 +366,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { } }) .filter(|feature| { - // skip checking special features, as LLVM may not understands them - if RUSTC_SPECIAL_FEATURES.contains(feature) { - return true; - } - // check that all features in a given smallvec are enabled - for llvm_feature in to_llvm_features(sess, feature) { - let cstr = SmallCStr::new(llvm_feature); - if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } { - return false; - } - } - true + RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature)) }) .map(|feature| Symbol::intern(feature)) .collect() @@ -440,7 +475,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { require_inited(); - let tm = create_informational_target_machine(sess); + let tm = create_informational_target_machine(sess, true); match req.kind { PrintKind::TargetCPUs => { // SAFETY generate a C compatible string from a byte slice to pass diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 536f39375bb..c84b844cd04 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,6 +1,6 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -165,26 +165,7 @@ pub(crate) fn provide(providers: &mut Providers) { } }, implied_target_features: |tcx, feature| { - let implied_features = tcx - .sess - .target - .supported_target_features() - .iter() - .map(|(f, _, i)| (Symbol::intern(f), i)) - .collect::>(); - - // implied target features have their own implied target features, so we traverse the - // map until there are no more features to add - let mut features = UnordSet::new(); - let mut new_features = vec![feature]; - while let Some(new_feature) = new_features.pop() { - if features.insert(new_feature) { - if let Some(implied_features) = implied_features.get(&new_feature) { - new_features.extend(implied_features.iter().copied().map(Symbol::intern)) - } - } - } - features + tcx.sess.target.implied_target_features(std::iter::once(feature)).into() }, asm_target_features, ..*providers diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f408db1dcba..0e9979e1bb7 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_span::symbol::{sym, Symbol}; /// Features that control behaviour of rustc, rather than the codegen. @@ -469,4 +470,28 @@ impl super::spec::Target { _ => &[], } } + + pub fn implied_target_features( + &self, + base_features: impl Iterator, + ) -> FxHashSet { + let implied_features = self + .supported_target_features() + .iter() + .map(|(f, _, i)| (Symbol::intern(f), i)) + .collect::>(); + + // implied target features have their own implied target features, so we traverse the + // map until there are no more features to add + let mut features = FxHashSet::default(); + let mut new_features = base_features.collect::>(); + while let Some(new_feature) = new_features.pop() { + if features.insert(new_feature) { + if let Some(implied_features) = implied_features.get(&new_feature) { + new_features.extend(implied_features.iter().copied().map(Symbol::intern)) + } + } + } + features + } } -- cgit 1.4.1-3-g733a5 From a25da077cf7606f42ffad17ee1562f932aa19b12 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 3 Aug 2024 23:51:37 -0400 Subject: Don't use LLVM to compute -Ctarget-feature --- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 211 +++++++++++++------------- compiler/rustc_target/src/target_features.rs | 8 +- tests/codegen/target-feature-overrides.rs | 2 +- 6 files changed, 120 insertions(+), 112 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src/context.rs') diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 890fcf508a8..a1f2433ab6f 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -97,13 +97,12 @@ pub fn write_output_file<'ll>( pub fn create_informational_target_machine( sess: &Session, - extra_features: bool, + only_base_features: bool, ) -> OwnedTargetMachine { let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None }; // Can't use query system here quite yet because this function is invoked before the query // system/tcx is set up. - let features = - if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() }; + let features = llvm_util::global_llvm_features(sess, false, only_base_features); target_machine_factory(sess, config::OptLevel::No, &features)(config) .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise()) } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1dc3fbfc7b3..173b8a479ef 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { - let tm = crate::back::write::create_informational_target_machine(tcx.sess, true); + let tm = crate::back::write::create_informational_target_machine(tcx.sess, false); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 333f1fdf6e0..518a86e0cb0 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend { fn provide(&self, providers: &mut Providers) { providers.global_backend_features = - |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) + |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false) } fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { @@ -434,7 +434,7 @@ impl ModuleLlvm { ModuleLlvm { llmod_raw, llcx, - tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, true)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e85974b7cc1..3190853a84c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -308,19 +308,10 @@ pub fn check_tied_features( /// Used to generate cfg variables and apply features /// Must express features in the way Rust understands them pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { - let rust_features = sess - .target - .supported_target_features() - .iter() - .map(|(feature, _, _)| { - (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature)) - }) - .collect::>(); - let mut features = FxHashSet::default(); // Add base features for the target - let target_machine = create_informational_target_machine(sess, false); + let target_machine = create_informational_target_machine(sess, true); features.extend( sess.target .supported_target_features() @@ -343,13 +334,16 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { ); // Add enabled features - for llvm_feature in global_llvm_features(sess, false) { - let (add, llvm_feature) = llvm_feature.split_at(1); - let feature = - rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature)); - if add == "+" { + for (enabled, feature) in + sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() { + Some('+') => Some((true, Symbol::intern(&s[1..]))), + Some('-') => Some((false, Symbol::intern(&s[1..]))), + _ => None, + }) + { + if enabled { features.extend(sess.target.implied_target_features(std::iter::once(feature))); - } else if add == "-" { + } else { features.remove(&feature); } } @@ -475,7 +469,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { require_inited(); - let tm = create_informational_target_machine(sess, true); + let tm = create_informational_target_machine(sess, false); match req.kind { PrintKind::TargetCPUs => { // SAFETY generate a C compatible string from a byte slice to pass @@ -523,7 +517,11 @@ pub fn target_cpu(sess: &Session) -> &str { /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). -pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec { +pub(crate) fn global_llvm_features( + sess: &Session, + diagnostics: bool, + only_base_features: bool, +) -> Vec { // Features that come earlier are overridden by conflicting features later in the string. // Typically we'll want more explicit settings to override the implicit ones, so: // @@ -583,96 +581,109 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec return None, - Some(c @ ('+' | '-')) => c, - Some(_) => { - if diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); + if !only_base_features { + let supported_features = sess.target.supported_target_features(); + let (llvm_major, _, _) = get_version(); + let mut featsmap = FxHashMap::default(); + let feats = sess + .opts + .cg + .target_feature + .split(',') + .filter_map(|s| { + let enable_disable = match s.chars().next() { + None => return None, + Some(c @ ('+' | '-')) => c, + Some(_) => { + if diagnostics { + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); + } + return None; } - return None; - } - }; + }; - let feature = backend_feature_name(sess, s)?; - // Warn against use of LLVM specific feature names and unstable features on the CLI. - if diagnostics { - let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature); - if feature_state.is_none() { - let rust_feature = - supported_features.iter().find_map(|&(rust_feature, _, _)| { - let llvm_features = to_llvm_features(sess, rust_feature); - if llvm_features.contains(feature) - && !llvm_features.contains(rust_feature) - { - Some(rust_feature) - } else { - None + let feature = backend_feature_name(sess, s)?; + // Warn against use of LLVM specific feature names and unstable features on the CLI. + if diagnostics { + let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature); + if feature_state.is_none() { + let rust_feature = + supported_features.iter().find_map(|&(rust_feature, _, _)| { + let llvm_features = to_llvm_features(sess, rust_feature); + if llvm_features.contains(feature) + && !llvm_features.contains(rust_feature) + { + Some(rust_feature) + } else { + None + } + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + UnknownCTargetFeature { + feature, + rust_feature: PossibleFeature::Some { rust_feature }, } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } else if feature_state - .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable()) - { - // An unstable feature. Warn about using it. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + } else { + UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } + }; + sess.dcx().emit_warn(unknown_feature); + } else if feature_state + .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable()) + { + // An unstable feature. Warn about using it. + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + } } - } - if diagnostics { - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable_disable == '+'); - } + if diagnostics { + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable_disable == '+'); + } - // rustc-specific features do not get passed down to LLVM… - if RUSTC_SPECIFIC_FEATURES.contains(&feature) { - return None; - } + // rustc-specific features do not get passed down to LLVM… + if RUSTC_SPECIFIC_FEATURES.contains(&feature) { + return None; + } - // if the target-feature is "backchain" and LLVM version is greater than 18 - // then we also need to add "+backchain" to the target-features attribute. - // otherwise, we will only add the naked `backchain` attribute to the attribute-group. - if feature == "backchain" && llvm_major < 18 { - return None; - } - // ... otherwise though we run through `to_llvm_features` when - // passing requests down to LLVM. This means that all in-language - // features also work on the command line instead of having two - // different names when the LLVM name and the Rust name differ. - let llvm_feature = to_llvm_features(sess, feature); - - Some( - std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)) - .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| { - match (enable_disable, feat) { + // if the target-feature is "backchain" and LLVM version is greater than 18 + // then we also need to add "+backchain" to the target-features attribute. + // otherwise, we will only add the naked `backchain` attribute to the attribute-group. + if feature == "backchain" && llvm_major < 18 { + return None; + } + // ... otherwise though we run through `to_llvm_features` when + // passing requests down to LLVM. This means that all in-language + // features also work on the command line instead of having two + // different names when the LLVM name and the Rust name differ. + let llvm_feature = to_llvm_features(sess, feature); + + Some( + std::iter::once(format!( + "{}{}", + enable_disable, llvm_feature.llvm_feature_name + )) + .chain(llvm_feature.dependency.into_iter().filter_map( + move |feat| match (enable_disable, feat) { ('-' | '+', TargetFeatureFoldStrength::Both(f)) | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => { Some(format!("{enable_disable}{f}")) } _ => None, - } - })), - ) - }) - .flatten(); - features.extend(feats); + }, + )), + ) + }) + .flatten(); + features.extend(feats); + + if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { + sess.dcx().emit_err(TargetFeatureDisableOrEnable { + features: f, + span: None, + missing_features: None, + }); + } + } // -Zfixed-x18 if sess.opts.unstable_opts.fixed_x18 { @@ -683,14 +694,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec