use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability::{DeprecationEntry, Index};
use rustc_middle::ty::{self, query::Providers, TyCtxt};
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
}
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
- let stab_map = self.tcx.stability();
- let stab = stab_map.local_stability(def_id);
- if stab.map_or(false, |stab| stab.level.is_stable()) {
- let const_stab = stab_map.local_const_stability(def_id);
- if const_stab.is_none() {
- self.tcx.sess.span_err(
- span,
- "`#[stable]` const functions must also be either \
- `#[rustc_const_stable]` or `#[rustc_const_unstable]`",
- );
- }
+ if !self.tcx.features().staged_api {
+ return;
+ }
+
+ let is_const = self.tcx.is_const_fn(def_id.to_def_id());
+ let is_stable = self
+ .tcx
+ .lookup_stability(def_id)
+ .map_or(false, |stability| stability.level.is_stable());
+ let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
+ let is_reachable = self.access_levels.is_reachable(def_id);
+
+ if is_const && is_stable && missing_const_stability_attribute && is_reachable {
+ let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
+ self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
}
}
}
impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
self.check_missing_stability(i.def_id, i.span);
}
- // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
- // `rustc_const_stable`.
- if self.tcx.features().staged_api
- && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
- {
- self.check_missing_const_stability(i.def_id, i.span);
- }
+ // Ensure stable `const fn` have a const stability attribute.
+ self.check_missing_const_stability(i.def_id, i.span);
intravisit::walk_item(self, i)
}
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
- let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id()));
+ 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.def_id, ii.span);
+ self.check_missing_const_stability(ii.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
}
impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
}
}
- if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
- for impl_item_ref in items {
- let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
- let trait_item_def_id = self
- .tcx
- .associated_items(trait_did)
- .filter_by_name_unhygienic(impl_item.ident.name)
- .next()
- .map(|item| item.def_id);
- if let Some(def_id) = trait_item_def_id {
- // Pass `None` to skip deprecation warnings.
- self.tcx.check_stability(def_id, None, impl_item.span, None);
- }
+ for impl_item_ref in items {
+ let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+
+ if let Some(def_id) = impl_item.trait_item_def_id {
+ // Pass `None` to skip deprecation warnings.
+ self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
}
}
}
}
impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
- type Map = Map<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
if let Some(def_id) = path.res.opt_def_id() {
if let Some(stab) = self.tcx.lookup_stability(def_id) {