diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index f2773dcdc60..94fcfabc32c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -600,59 +600,61 @@ macro_rules! gate_all_legacy_dont_use { } fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) { - // checks if `#![feature]` has been used to enable any lang feature - // does not check the same for lib features unless there's at least one - // declared lang feature - if !sess.opts.unstable_features.is_nightly_build() { - if features.declared_features.is_empty() { - return; - } - for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { - let mut err = errors::FeatureOnNonNightly { - span: attr.span, - channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), - stable_features: vec![], - sugg: None, - }; - - let mut all_stable = true; - for ident in - attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) - { - let name = ident.name; - let stable_since = features - .declared_lang_features - .iter() - .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) - .next(); - if let Some(since) = stable_since { - err.stable_features.push(errors::StableFeature { name, since }); - } else { - all_stable = false; - } - } - if all_stable { - err.sugg = Some(attr.span); - } - sess.dcx().emit_err(err); - } + // checks if `#![feature]` has been used to enable any feature. + if sess.opts.unstable_features.is_nightly_build() { + return; } + if features.enabled_features().is_empty() { + return; + } + let mut errored = false; + for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { + // `feature(...)` used on non-nightly. This is definitely an error. + let mut err = errors::FeatureOnNonNightly { + span: attr.span, + channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), + stable_features: vec![], + sugg: None, + }; + + let mut all_stable = true; + for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { + let name = ident.name; + let stable_since = features + .enabled_lang_features() + .iter() + .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) + .next(); + if let Some(since) = stable_since { + err.stable_features.push(errors::StableFeature { name, since }); + } else { + all_stable = false; + } + } + if all_stable { + err.sugg = Some(attr.span); + } + sess.dcx().emit_err(err); + errored = true; + } + // Just make sure we actually error if anything is listed in `enabled_features`. + assert!(errored); } fn check_incompatible_features(sess: &Session, features: &Features) { - let declared_features = features - .declared_lang_features + let enabled_features = features + .enabled_lang_features() .iter() .copied() .map(|(name, span, _)| (name, span)) - .chain(features.declared_lib_features.iter().copied()); + .chain(features.enabled_lib_features().iter().copied()); for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() - .filter(|&&(f1, f2)| features.active(f1) && features.active(f2)) + .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) { - if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { - if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) + if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) { + if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2) { let spans = vec![f1_span, f2_span]; sess.dcx().emit_err(errors::IncompatibleFeatures { @@ -672,7 +674,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { // Ban GCE with the new solver, because it does not implement GCE correctly. if let Some(&(_, gce_span, _)) = features - .declared_lang_features + .enabled_lang_features() .iter() .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 463a66d4e2e..73344508a9d 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -276,7 +276,7 @@ pub fn check_op_spanned>(&mut self, op: O, span: Span) { let gate = match op.status_in_item(self.ccx) { Status::Allowed => return, - Status::Unstable(gate) if self.tcx.features().active(gate) => { + Status::Unstable(gate) if self.tcx.features().enabled(gate) => { let unstable_in_stable = self.ccx.is_const_stable_const_fn() && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); if unstable_in_stable { @@ -700,10 +700,10 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location // Calling an unstable function *always* requires that the corresponding gate // (or implied gate) be enabled, even if the function has // `#[rustc_allow_const_fn_unstable(the_gate)]`. - let gate_declared = |gate| tcx.features().declared(gate); - let feature_gate_declared = gate_declared(gate); - let implied_gate_declared = implied_by.is_some_and(gate_declared); - if !feature_gate_declared && !implied_gate_declared { + let gate_enabled = |gate| tcx.features().enabled(gate); + let feature_gate_enabled = gate_enabled(gate); + let implied_gate_enabled = implied_by.is_some_and(gate_enabled); + if !feature_gate_enabled && !implied_gate_enabled { self.check_op(ops::FnCallUnstable(callee, Some(gate))); return; } @@ -717,7 +717,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location // Otherwise, we are something const-stable calling a const-unstable fn. if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { - trace!("rustc_allow_const_fn_unstable gate active"); + trace!("rustc_allow_const_fn_unstable gate enabled"); return; } diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md index 57cf72db556..41fd701a8ed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0636.md +++ b/compiler/rustc_error_codes/src/error_codes/E0636.md @@ -1,9 +1,9 @@ -A `#![feature]` attribute was declared multiple times. +The same feature is enabled multiple times with `#![feature]` attributes Erroneous code example: ```compile_fail,E0636 #![allow(stable_features)] #![feature(rust1)] -#![feature(rust1)] // error: the feature `rust1` has already been declared +#![feature(rust1)] // error: the feature `rust1` has already been enabled ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0705.md b/compiler/rustc_error_codes/src/error_codes/E0705.md index 317f3a47eff..e7d7d74cc4c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0705.md +++ b/compiler/rustc_error_codes/src/error_codes/E0705.md @@ -1,6 +1,6 @@ #### Note: this error code is no longer emitted by the compiler. -A `#![feature]` attribute was declared for a feature that is stable in the +A `#![feature]` attribute was used for a feature that is stable in the current edition, but not in all editions. Erroneous code example: diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ea06415801f..a6b7291ee8f 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -52,7 +52,7 @@ fn feature_list(attr: &Attribute) -> ThinVec { let mut features = Features::default(); - // Process all features declared in the code. + // Process all features enabled in the code. for attr in krate_attrs { for mi in feature_list(attr) { let name = match mi.ident() { @@ -76,7 +76,7 @@ fn feature_list(attr: &Attribute) -> ThinVec { } }; - // If the declared feature has been removed, issue an error. + // If the enabled feature has been removed, issue an error. if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) { sess.dcx().emit_err(FeatureRemoved { span: mi.span(), @@ -85,14 +85,14 @@ fn feature_list(attr: &Attribute) -> ThinVec { continue; } - // If the declared feature is stable, record it. + // If the enabled feature is stable, record it. if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { let since = Some(Symbol::intern(f.since)); - features.set_declared_lang_feature(name, mi.span(), since); + features.set_enabled_lang_feature(name, mi.span(), since, None); continue; } - // If `-Z allow-features` is used and the declared feature is + // If `-Z allow-features` is used and the enabled feature is // unstable and not also listed as one of the allowed features, // issue an error. if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { @@ -102,9 +102,8 @@ fn feature_list(attr: &Attribute) -> ThinVec { } } - // If the declared feature is unstable, record it. + // If the enabled feature is unstable, record it. if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { - (f.set_enabled)(&mut features); // When the ICE comes from core, alloc or std (approximation of the standard // library), there's a chance that the person hitting the ICE may be using // -Zbuild-std or similar with an untested target. The bug is probably in the @@ -115,13 +114,13 @@ fn feature_list(attr: &Attribute) -> ThinVec { { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } - features.set_declared_lang_feature(name, mi.span(), None); + features.set_enabled_lang_feature(name, mi.span(), None, Some(f)); continue; } - // Otherwise, the feature is unknown. Record it as a lib feature. - // It will be checked later. - features.set_declared_lib_feature(name, mi.span()); + // Otherwise, the feature is unknown. Enable it as a lib feature. + // It will be checked later whether the feature really exists. + features.set_enabled_lib_feature(name, mi.span()); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 2edd289625e..e518b27e419 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -119,7 +119,7 @@ pub(super) fn parse( result } -/// Asks for the `macro_metavar_expr` feature if it is not already declared +/// Asks for the `macro_metavar_expr` feature if it is not enabled fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) { if !features.macro_metavar_expr { let msg = "meta-variable expressions are unstable"; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f4795c75e48..0606f2914c3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -8,7 +8,7 @@ pub struct UnstableFeature { pub feature: Feature, - pub set_enabled: fn(&mut Features), + set_enabled: fn(&mut Features), } #[derive(PartialEq)] @@ -54,14 +54,13 @@ macro_rules! declare_features { #[derive(Clone, Default, Debug)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. - /// "declared" here means that the feature is actually enabled in the current crate. - pub declared_lang_features: Vec<(Symbol, Span, Option)>, + enabled_lang_features: Vec<(Symbol, Span, Option)>, /// `#![feature]` attrs for non-language (library) features. - /// "declared" here means that the feature is actually enabled in the current crate. - pub declared_lib_features: Vec<(Symbol, Span)>, - /// `declared_lang_features` + `declared_lib_features`. - pub declared_features: FxHashSet, - /// Active state of individual features (unstable only). + enabled_lib_features: Vec<(Symbol, Span)>, + /// `enabled_lang_features` + `enabled_lib_features`. + enabled_features: FxHashSet, + /// State of individual features (unstable lang features only). + /// This is `true` if and only if the corresponding feature is listed in `enabled_lang_features`. $( $(#[doc = $doc])* pub $feature: bool @@ -69,46 +68,71 @@ pub struct Features { } impl Features { - pub fn set_declared_lang_feature( + pub fn set_enabled_lang_feature( &mut self, - symbol: Symbol, + name: Symbol, span: Span, - since: Option + since: Option, + feature: Option<&UnstableFeature>, ) { - self.declared_lang_features.push((symbol, span, since)); - self.declared_features.insert(symbol); + self.enabled_lang_features.push((name, span, since)); + self.enabled_features.insert(name); + if let Some(feature) = feature { + assert_eq!(feature.feature.name, name); + (feature.set_enabled)(self); + } else { + // Ensure we don't skip a `set_enabled` call. + debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none()); + } } - pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) { - self.declared_lib_features.push((symbol, span)); - self.declared_features.insert(symbol); + pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { + self.enabled_lib_features.push((name, span)); + self.enabled_features.insert(name); + // Ensure we don't skip a `set_enabled` call. + debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none()); } - /// This is intended for hashing the set of active features. + /// This is intended for hashing the set of enabled language features. /// /// The expectation is that this produces much smaller code than other alternatives. /// /// Note that the total feature count is pretty small, so this is not a huge array. #[inline] - pub fn all_features(&self) -> [u8; NUM_FEATURES] { + pub fn all_lang_features(&self) -> [u8; NUM_FEATURES] { [$(self.$feature as u8),+] } - /// Is the given feature explicitly declared, i.e. named in a - /// `#![feature(...)]` within the code? - pub fn declared(&self, feature: Symbol) -> bool { - self.declared_features.contains(&feature) + pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option)> { + &self.enabled_lang_features } - /// Is the given feature active (enabled by the user)? - /// - /// Panics if the symbol doesn't correspond to a declared feature. - pub fn active(&self, feature: Symbol) -> bool { - match feature { - $( sym::$feature => self.$feature, )* + pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { + &self.enabled_lib_features + } - _ => panic!("`{}` was not listed in `declare_features`", feature), + pub fn enabled_features(&self) -> &FxHashSet { + &self.enabled_features + } + + /// Is the given feature enabled (via `#[feature(...)]`)? + pub fn enabled(&self, feature: Symbol) -> bool { + let e = self.enabled_features.contains(&feature); + if cfg!(debug_assertions) { + // Ensure this matches `self.$feature`, if that exists. + let e2 = match feature { + $( sym::$feature => Some(self.$feature), )* + _ => None, + }; + if let Some(e2) = e2 { + assert_eq!( + e, e2, + "mismatch in feature state for `{feature}`: \ + `enabled_features` says {e} but `self.{feature}` says {e2}" + ); + } } + e } /// Some features are known to be incomplete and using them is likely to have @@ -119,8 +143,11 @@ pub fn incomplete(&self, feature: Symbol) -> bool { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete, )* - // Accepted/removed features aren't in this file but are never incomplete. - _ if self.declared_features.contains(&feature) => false, + _ if self.enabled_features.contains(&feature) => { + // Accepted/removed features and library features aren't in this file but + // are never incomplete. + false + } _ => panic!("`{}` was not listed in `declare_features`", feature), } } @@ -132,7 +159,7 @@ pub fn internal(&self, feature: Symbol) -> bool { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, )* - _ if self.declared_features.contains(&feature) => { + _ if self.enabled_features.contains(&feature) => { // This could be accepted/removed, or a libs feature. // Accepted/removed features aren't in this file but are never internal // (a removed feature might have been internal, but that's now irrelevant). diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ef8100da9e2..125fe9b3f16 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2288,10 +2288,10 @@ impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.builder.features(); features - .declared_lang_features + .enabled_lang_features() .iter() .map(|(name, span, _)| (name, span)) - .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) + .chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span))) .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) .for_each(|(&name, &span)| { if features.incomplete(name) { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 95a8e7625ff..ff2ae69e1db 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -858,7 +858,7 @@ fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: #[track_caller] fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool { let feature = if let Some(feature) = lint_id.lint.feature_gate - && !self.features.active(feature) + && !self.features.enabled(feature) { // Lint is behind a feature that is not enabled; eventually return false. feature diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index ee34ccd889f..c0688aff183 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -422,15 +422,15 @@ pub fn eval_stability_allow_unstable( debug!("stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; } - if self.features().declared(feature) { + if self.features().enabled(feature) { return EvalResult::Allow; } // If this item was previously part of a now-stabilized feature which is still - // active (i.e. the user hasn't removed the attribute for the stabilized feature + // enabled (i.e. the user hasn't removed the attribute for the stabilized feature // yet) then allow use of this item. if let Some(implied_by) = implied_by - && self.features().declared(implied_by) + && self.features().enabled(implied_by) { return EvalResult::Allow; } @@ -509,7 +509,7 @@ pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResul debug!("body stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; } - if self.features().declared(feature) { + if self.features().enabled(feature) { return EvalResult::Allow; } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c2a55060490..210b115ae37 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3093,7 +3093,7 @@ pub fn is_const_fn(self, def_id: DefId) -> bool { Some(stability) if stability.is_const_unstable() => { // has a `rustc_const_unstable` attribute, check whether the user enabled the // corresponding feature gate. - self.features().declared(stability.feature) + self.features().enabled(stability.feature) } // functions without const stability are either stable user written // const fn or the user is using feature gates and we thus don't diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3613b7b862d..899a7b84100 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -256,7 +256,7 @@ passes_duplicate_diagnostic_item_in_crate = .note = the diagnostic item is first defined in crate `{$orig_crate_name}` passes_duplicate_feature_err = - the feature `{$feature}` has already been declared + the feature `{$feature}` has already been enabled passes_duplicate_lang_item = found duplicate lang item `{$lang_item_name}` diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 0dad94a9939..ca13ca11673 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -87,7 +87,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) { let is_feature_allowed = |feature_gate| { // All features require that the corresponding gate be enabled, // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. - if !tcx.features().active(feature_gate) { + if !tcx.features().enabled(feature_gate) { return false; } @@ -135,7 +135,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) { let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = - required_gates.iter().copied().filter(|&g| !features.active(g)).collect(); + required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { [] => { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 751c87a9fe5..80ac2741c38 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -935,9 +935,9 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx.hir().visit_all_item_likes_in_crate(&mut missing); } - let declared_lang_features = &tcx.features().declared_lang_features; + let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); - for &(feature, span, since) in declared_lang_features { + for &(feature, span, since) in enabled_lang_features { if let Some(since) = since { // Warn if the user has enabled an already-stable lang feature. unnecessary_stable_feature_lint(tcx, span, feature, since); @@ -948,9 +948,9 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } } - let declared_lib_features = &tcx.features().declared_lib_features; + let enabled_lib_features = tcx.features().enabled_lib_features(); let mut remaining_lib_features = FxIndexMap::default(); - for (feature, span) in declared_lib_features { + for (feature, span) in enabled_lib_features { if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); @@ -961,7 +961,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // recognise the feature when building std. // Likewise, libtest is handled specially, so `test` isn't // available as we'd like it to be. - // FIXME: only remove `libc` when `stdbuild` is active. + // FIXME: only remove `libc` when `stdbuild` is enabled. // FIXME: remove special casing for `test`. // FIXME(#120456) - is `swap_remove` correct? remaining_lib_features.swap_remove(&sym::libc); @@ -1021,7 +1021,7 @@ fn check_features<'tcx>( // All local crate implications need to have the feature that implies it confirmed to exist. let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone(); - // We always collect the lib features declared in the current crate, even if there are + // We always collect the lib features enabled in the current crate, even if there are // no unknown features, because the collection also does feature attribute validation. let local_defined_features = tcx.lib_features(LOCAL_CRATE); if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() { diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 5e450979273..78c37688d34 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -112,10 +112,10 @@ impl<'tcx> HashStable> for rustc_feature::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the // struct is macro generated. - self.declared_lang_features.hash_stable(hcx, hasher); - self.declared_lib_features.hash_stable(hcx, hasher); + self.enabled_lang_features().hash_stable(hcx, hasher); + self.enabled_lib_features().hash_stable(hcx, hasher); - self.all_features()[..].hash_stable(hcx, hasher); + self.all_lang_features()[..].hash_stable(hcx, hasher); for feature in rustc_feature::UNSTABLE_FEATURES.iter() { feature.feature.name.hash_stable(hcx, hasher); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index e43c8718665..5e38fb5b6c5 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1007,10 +1007,8 @@ fn check_stability_and_deprecation( { let feature = stability.feature; - let is_allowed = |feature| { - self.tcx.features().declared_features.contains(&feature) - || span.allows_unstable(feature) - }; + let is_allowed = + |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature); let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature)); if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index cac0cf9959d..c2095155afa 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -184,7 +184,7 @@ pub fn is_enabled( ) -> Result<(), AbiDisabled> { let s = is_stable(name); if let Err(AbiDisabled::Unstable { feature, .. }) = s { - if features.active(feature) || span.allows_unstable(feature) { + if features.enabled(feature) || span.allows_unstable(feature) { return Ok(()); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 00e02e2a336..4c171e6d890 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -111,11 +111,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.peel_refs().kind() { ty::Uint(_) => true, - ty::Int(_) => cx - .tcx - .features() - .declared_features - .contains(&Symbol::intern("int_roundings")), + ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")), _ => false, } diff --git a/tests/rustdoc-ui/rustc-check-passes.stderr b/tests/rustdoc-ui/rustc-check-passes.stderr index 58d61c0213e..5b20d1128c5 100644 --- a/tests/rustdoc-ui/rustc-check-passes.stderr +++ b/tests/rustdoc-ui/rustc-check-passes.stderr @@ -1,4 +1,4 @@ -error[E0636]: the feature `rustdoc_internals` has already been declared +error[E0636]: the feature `rustdoc_internals` has already been enabled --> $DIR/rustc-check-passes.rs:2:12 | LL | #![feature(rustdoc_internals)] diff --git a/tests/ui/feature-gates/duplicate-features.rs b/tests/ui/feature-gates/duplicate-features.rs index d8f7818054a..1fae71c3eb2 100644 --- a/tests/ui/feature-gates/duplicate-features.rs +++ b/tests/ui/feature-gates/duplicate-features.rs @@ -1,9 +1,9 @@ #![allow(stable_features)] #![feature(rust1)] -#![feature(rust1)] //~ ERROR the feature `rust1` has already been declared +#![feature(rust1)] //~ ERROR the feature `rust1` has already been enabled #![feature(if_let)] -#![feature(if_let)] //~ ERROR the feature `if_let` has already been declared +#![feature(if_let)] //~ ERROR the feature `if_let` has already been enabled fn main() {} diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr index dbde806f6cc..f667a5b9623 100644 --- a/tests/ui/feature-gates/duplicate-features.stderr +++ b/tests/ui/feature-gates/duplicate-features.stderr @@ -1,10 +1,10 @@ -error[E0636]: the feature `if_let` has already been declared +error[E0636]: the feature `if_let` has already been enabled --> $DIR/duplicate-features.rs:7:12 | LL | #![feature(if_let)] | ^^^^^^ -error[E0636]: the feature `rust1` has already been declared +error[E0636]: the feature `rust1` has already been enabled --> $DIR/duplicate-features.rs:4:12 | LL | #![feature(rust1)]