diff options
Diffstat (limited to 'compiler/rustc_passes/src/stability.rs')
| -rw-r--r-- | compiler/rustc_passes/src/stability.rs | 194 |
1 files changed, 98 insertions, 96 deletions
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 264dd364b5b..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; @@ -166,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() @@ -294,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 }); @@ -316,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, @@ -570,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 @@ -587,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 }); } @@ -620,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) } @@ -634,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); } @@ -765,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 |
