diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c382242d8d0..db2b03d9aed 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -344,15 +344,23 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { }) { if enabled { + // Also add all transitively implied features. features.extend(sess.target.implied_target_features(std::iter::once(feature))); } else { + // Remove transitively reverse-implied features. + // We don't care about the order in `features` since the only thing we use it for is the // `features.contains` below. #[allow(rustc::potential_query_instability)] features.retain(|f| { - // Keep a feature if it does not imply `feature`. Or, equivalently, - // remove the reverse-dependencies of `feature`. - !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) + if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) { + // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to + // remove `f`. (This is the standard logical contraposition principle.) + false + } else { + // We can keep `f`. + true + } }); } } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c4f9c742650..e8a6de98b7e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -92,6 +92,11 @@ pub fn is_supported(self) -> bool { // // Stabilizing a target feature requires t-lang approval. +// If feature A "implies" feature B, then: +// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B +// - when B gets disabled (via `-Ctarget-feature`), we also disable A +// +// Both of these are also applied transitively. type ImpliedFeatures = &'static [&'static str]; const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[