diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-11-12 18:11:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-12 18:11:04 +0100 |
| commit | 4a699fc475128899f0957ca116021083af89b9d8 (patch) | |
| tree | 79447cfd6f181f3506cbab3d91e97aea7df9ef4b /compiler | |
| parent | 134459ea3dfe92b423f7d9c61f6e80c2cf8df09e (diff) | |
| parent | 378049633dfad641f5c9ed0cea085a9c9d0ae56e (diff) | |
| download | rust-4a699fc475128899f0957ca116021083af89b9d8.tar.gz rust-4a699fc475128899f0957ca116021083af89b9d8.zip | |
Rollup merge of #132541 - RalfJung:const-stable-extern-crate, r=compiler-errors
Proper support for cross-crate recursive const stability checks ~~Stacked on top of https://github.com/rust-lang/rust/pull/132492; only the last three commits are new.~~ In a crate without `staged_api` but with `-Zforce-unstable-if-unmarked`, we now subject all functions marked with `#[rustc_const_stable_indirect]` to recursive const stability checks. We require an opt-in so that by default, a crate can be built with `-Zforce-unstable-if-unmarked` and use nightly features as usual. This property is recorded in the crate metadata so when a `staged_api` crate calls such a function, it sees the `#[rustc_const_stable_indirect]` and allows it to be exposed on stable. This, finally, will let us expose `const fn` from hashbrown on stable. The second commit makes const stability more like regular stability: via `check_missing_const_stability`, we ensure that all publicly reachable functions have a const stability attribute -- both in `staged_api` crates and `-Zforce-unstable-if-unmarked` crates. To achieve this, we move around the stability computation so that const stability is computed after regular stability is done. This lets us access the final result of the regular stability computation, which we use so that `const fn` can inherit the regular stability (but only if that is "unstable"). Fortunately, this lets us get rid of an `Option` in `ConstStability`. This is the last PR that I have planned in this series. r? `@compiler-errors`
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_attr/src/builtin.rs | 68 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/check_consts/check.rs | 45 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/check_consts/mod.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/base.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/stability.rs | 199 |
5 files changed, 179 insertions, 157 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2753ac529d1..94f9727eb7f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; +use rustc_span::Span; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, Span}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -92,9 +92,7 @@ impl Stability { #[derive(HashStable_Generic)] pub struct ConstStability { pub level: StabilityLevel, - /// This can be `None` for functions that do not have an explicit const feature. - /// We still track them for recursive const stability checks. - pub feature: Option<Symbol>, + pub feature: Symbol, /// This is true iff the `const_stable_indirect` attribute is present. pub const_stable_indirect: bool, /// whether the function has a `#[rustc_promotable]` attribute @@ -272,22 +270,19 @@ pub fn find_stability( /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` /// attributes in `attrs`. Returns `None` if no stability attributes are found. -/// -/// `is_const_fn` indicates whether this is a function marked as `const`. pub fn find_const_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, - is_const_fn: bool, ) -> Option<(ConstStability, Span)> { let mut const_stab: Option<(ConstStability, Span)> = None; let mut promotable = false; - let mut const_stable_indirect = None; + let mut const_stable_indirect = false; for attr in attrs { match attr.name_or_empty() { sym::rustc_promotable => promotable = true, - sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span), + sym::rustc_const_stable_indirect => const_stable_indirect = true, sym::rustc_const_unstable => { if const_stab.is_some() { sess.dcx() @@ -299,7 +294,7 @@ pub fn find_const_stability( const_stab = Some(( ConstStability { level, - feature: Some(feature), + feature, const_stable_indirect: false, promotable: false, }, @@ -317,7 +312,7 @@ pub fn find_const_stability( const_stab = Some(( ConstStability { level, - feature: Some(feature), + feature, const_stable_indirect: false, promotable: false, }, @@ -340,7 +335,7 @@ pub fn find_const_stability( } } } - if const_stable_indirect.is_some() { + if const_stable_indirect { match &mut const_stab { Some((stab, _)) => { if stab.is_const_unstable() { @@ -351,36 +346,37 @@ pub fn find_const_stability( }) } } - _ => {} + _ => { + // This function has no const stability attribute, but has `const_stable_indirect`. + // We ignore that; unmarked functions are subject to recursive const stability + // checks by default so we do carry out the user's intent. + } } } - // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const - // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const - // stability checks for them. We need to do this because the default for whether an unmarked - // function enforces recursive stability differs between staged-api crates and force-unmarked - // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect` - // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to - // assume the function does not have recursive stability. All functions that *do* have recursive - // stability must explicitly record this, and so that's what we do for all `const fn` in a - // staged_api crate. - if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() { - let c = ConstStability { - feature: None, - const_stable_indirect: const_stable_indirect.is_some(), - promotable: false, - level: StabilityLevel::Unstable { - reason: UnstableReason::Default, - issue: None, - is_soft: false, - implied_by: None, - }, - }; - const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP))); - } const_stab } +/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate +/// without the `staged_api` feature. +pub fn unmarked_crate_const_stab( + _sess: &Session, + attrs: &[Attribute], + regular_stab: Stability, +) -> ConstStability { + assert!(regular_stab.level.is_unstable()); + // The only attribute that matters here is `rustc_const_stable_indirect`. + // We enforce recursive const stability rules for those functions. + let const_stable_indirect = + attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect); + ConstStability { + feature: regular_stab.feature, + const_stable_indirect, + promotable: false, + level: regular_stab.level, + } +} + /// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. /// Returns `None` if no stability attributes are found. pub fn find_body_stability( diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8cd0ecb3e4e..c3efca28c68 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use std::borrow::Cow; use std::mem; +use std::num::NonZero; use std::ops::Deref; use rustc_attr::{ConstStability, StabilityLevel}; @@ -709,6 +710,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsics are language primitives, not regular calls, so treat them separately. if let Some(intrinsic) = tcx.intrinsic(callee) { + if !tcx.is_const_fn(callee) { + // Non-const intrinsic. + self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. + return; + } // We use `intrinsic.const_stable` to determine if this can be safely exposed to // stable code, rather than `const_stable_indirect`. This is to make // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. @@ -716,17 +724,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // fallback body is safe to expose on stable. let is_const_stable = intrinsic.const_stable || (!intrinsic.must_be_overridden - && tcx.is_const_fn(callee) && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { - // Non-const intrinsic. - self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); - } - Some(ConstStability { feature: None, .. }) => { - // Intrinsic does not need a separate feature gate (we rely on the - // regular stability checker). However, we have to worry about recursive - // const stability. + // This doesn't need a separate const-stability check -- const-stability equals + // regular stability, and regular stability is checked separately. + // However, we *do* have to worry about *recursive* const stability. if !is_const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, @@ -735,8 +738,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } Some(ConstStability { - feature: Some(feature), level: StabilityLevel::Unstable { .. }, + feature, .. }) => { self.check_op(ops::IntrinsicUnstable { @@ -773,7 +776,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { // All good. } - None | Some(ConstStability { feature: None, .. }) => { + None => { // This doesn't need a separate const-stability check -- const-stability equals // regular stability, and regular stability is checked separately. // However, we *do* have to worry about *recursive* const stability. @@ -787,8 +790,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } Some(ConstStability { - feature: Some(feature), - level: StabilityLevel::Unstable { implied_by: implied_feature, .. }, + level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, + feature, .. }) => { // An unstable const fn with a feature gate. @@ -810,7 +813,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // to allow this. let feature_enabled = callee.is_local() || tcx.features().enabled(feature) - || implied_feature.is_some_and(|f| tcx.features().enabled(f)); + || implied_feature.is_some_and(|f| tcx.features().enabled(f)) + || { + // When we're compiling the compiler itself we may pull in + // crates from crates.io, but those crates may depend on other + // crates also pulled in from crates.io. We want to ideally be + // able to compile everything without requiring upstream + // modifications, so in the case that this looks like a + // `rustc_private` crate (e.g., a compiler crate) and we also have + // the `-Z force-unstable-if-unmarked` flag present (we're + // compiling a compiler crate), then let this missing feature + // annotation slide. + // This matches what we do in `eval_stability_allow_unstable` for + // regular stability. + feature == sym::rustc_private + && issue == NonZero::new(27812) + && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked + }; // We do *not* honor this if we are in the "danger zone": we have to enforce // recursive const-stability and the callee is not safe-to-expose. In that // case we need `check_op` to do the check. diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index dcdaafaecc2..ebdd55a4f70 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -53,10 +53,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { } pub fn enforce_recursive_const_stability(&self) -> bool { - // We can skip this if `staged_api` is not enabled, since in such crates - // `lookup_const_stability` will always be `None`. + // We can skip this if neither `staged_api` nor `-Zforce-unstable-if-unmarked` are enabled, + // since in such crates `lookup_const_stability` will always be `None`. self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api() + && (self.tcx.features().staged_api() + || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked) && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id()) } @@ -109,14 +110,15 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b match tcx.lookup_const_stability(def_id) { None => { - // Only marked functions can be trusted. Note that this may be a function in a - // non-staged-API crate where no recursive checks were done! - false + // In a `staged_api` crate, we do enforce recursive const stability for all unmarked + // functions, so we can trust local functions. But in another crate we don't know which + // rules were applied, so we can't trust that. + def_id.is_local() && tcx.features().staged_api() } Some(stab) => { - // We consider things safe-to-expose if they are stable, if they don't have any explicit - // const stability attribute, or if they are marked as `const_stable_indirect`. - stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect + // We consider things safe-to-expose if they are stable or if they are marked as + // `const_stable_indirect`. + stab.is_const_stable() || stab.const_stable_indirect } } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7e4bc508e5c..bed500c3032 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -866,9 +866,7 @@ impl SyntaxExtension { }) .unwrap_or_else(|| (None, helper_attrs)); let stability = attr::find_stability(sess, attrs, span); - // We set `is_const_fn` false to avoid getting any implicit const stability. - let const_stability = - attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false); + let const_stability = attr::find_const_stability(sess, attrs, span); let body_stability = attr::find_body_stability(sess, attrs); if let Some((_, sp)) = const_stability { sess.dcx().emit_err(errors::MacroConstStability { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index cd47c8ece60..4a793f1875e 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,7 +16,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -149,6 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(stab) = self.parent_stab { if inherit_deprecation.yes() && stab.is_unstable() { self.index.stab_map.insert(def_id, stab); + if fn_sig.is_some_and(|s| s.header.is_const()) { + let const_stab = + attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab); + self.index.const_stab_map.insert(def_id, const_stab); + } } } @@ -161,68 +166,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } + // # Regular and body stability + let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); - let const_stab = attr::find_const_stability( - self.tcx.sess, - attrs, - item_sp, - fn_sig.is_some_and(|s| s.header.is_const()), - ); let body_stab = attr::find_body_stability(self.tcx.sess, attrs); - // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const or the parent impl block is const. - if let Some(fn_sig) = fn_sig - && !fn_sig.header.is_const() - && const_stab.is_some() - { - self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); - } - - // If this is marked const *stable*, it must also be regular-stable. - if let Some((const_stab, const_span)) = const_stab - && let Some(fn_sig) = fn_sig - && const_stab.is_const_stable() - && !stab.is_some_and(|(s, _)| s.is_stable()) - { - self.tcx - .dcx() - .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(( - ConstStability { level: Unstable { .. }, feature: Some(feature), .. }, - const_span, - )) = const_stab - { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - } - - let const_stab = const_stab.map(|(const_stab, _span)| { - self.index.const_stab_map.insert(def_id, const_stab); - const_stab - }); - - // `impl const Trait for Type` items forward their const stability to their - // immediate children. - // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? - // Currently, once that is set, we do not inherit anything from the parent any more. - if const_stab.is_none() { - debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); - if let Some(parent) = self.parent_const_stab { - if parent.is_const_unstable() { - self.index.const_stab_map.insert(def_id, parent); - } - } - } - if let Some((depr, span)) = &depr && depr.is_since_rustc_version() && stab.is_none() @@ -289,15 +237,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - if let Some(ConstStability { - level: Unstable { implied_by: Some(implied_by), .. }, - feature, - .. - }) = const_stab - { - self.index.implications.insert(implied_by, feature.unwrap()); - } - self.index.stab_map.insert(def_id, stab); stab }); @@ -311,6 +250,91 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + let final_stab = self.index.stab_map.get(&def_id); + + // # Const stability + + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp); + + // If the current node is a function with const stability attributes (directly given or + // implied), check if the function/method is const. + if let Some(fn_sig) = fn_sig + && !fn_sig.header.is_const() + && const_stab.is_some() + { + self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); + } + + // If this is marked const *stable*, it must also be regular-stable. + if let Some((const_stab, const_span)) = const_stab + && let Some(fn_sig) = fn_sig + && const_stab.is_const_stable() + && !stab.is_some_and(|s| s.is_stable()) + { + self.tcx + .dcx() + .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Some((ConstStability { level: Unstable { .. }, feature, .. }, const_span)) = + const_stab + { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span, + item_sp, + }); + } + } + + // After checking the immediate attributes, get rid of the span and compute implied + // const stability: inherit feature gate from regular stability. + let mut const_stab = const_stab.map(|(stab, _span)| stab); + + // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. + if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && + // We only ever inherit unstable features. + let Some(inherit_regular_stab) = + final_stab.filter(|s| s.is_unstable()) + { + const_stab = Some(ConstStability { + // We subject these implicitly-const functions to recursive const stability. + const_stable_indirect: true, + promotable: false, + level: inherit_regular_stab.level, + feature: inherit_regular_stab.feature, + }); + } + + // Now that everything is computed, insert it into the table. + const_stab.inspect(|const_stab| { + self.index.const_stab_map.insert(def_id, *const_stab); + }); + + if let Some(ConstStability { + level: Unstable { implied_by: Some(implied_by), .. }, + feature, + .. + }) = const_stab + { + self.index.implications.insert(implied_by, feature); + } + + // `impl const Trait for Type` items forward their const stability to their + // immediate children. + // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. + if const_stab.is_none() { + debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); + if let Some(parent) = self.parent_const_stab { + if parent.is_const_unstable() { + self.index.const_stab_map.insert(def_id, parent); + } + } + } + self.recurse_with_stability_attrs( depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, @@ -565,13 +589,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } - fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) { - // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support - // that on the const side. - if !self.tcx.features().staged_api() { - return; - } - + fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { // if the const impl is derived using the `derive_const` attribute, // then it would be "stable" at least for the impl. // We gate usages of it using `feature(const_trait_impl)` anyways @@ -582,12 +600,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { let is_const = self.tcx.is_const_fn(def_id.to_def_id()) || self.tcx.is_const_trait_impl(def_id.to_def_id()); - let is_stable = - self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable()); - let missing_const_stability_attribute = - self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none()); - if is_const && is_stable && missing_const_stability_attribute { + // Reachable const fn must have a stability attribute. + if is_const + && self.effective_visibilities.is_reachable(def_id) + && self.tcx.lookup_const_stability(def_id).is_none() + { let descr = self.tcx.def_descr(def_id.to_def_id()); self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr }); } @@ -615,7 +633,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } @@ -629,7 +647,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); - self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -760,23 +778,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl(hir::Impl { - constness, - of_trait: Some(ref t), - self_ty, - items, - .. - }) => { + hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir().attrs(item.hir_id()); let stab = attr::find_stability(self.tcx.sess, attrs, item.span); - let const_stab = attr::find_const_stability( - self.tcx.sess, - attrs, - item.span, - matches!(constness, Constness::Const), - ); + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because |
