Skip to content

Implement stability_implications without a visitor. #144873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ impl DefKind {
matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait)
}

#[inline]
pub fn is_adt(self) -> bool {
matches!(self, DefKind::Struct | DefKind::Union | DefKind::Enum)
}

#[inline]
pub fn is_fn_like(self) -> bool {
matches!(
Expand All @@ -313,6 +318,43 @@ impl DefKind {
)
}

/// Whether the corresponding item has generic parameters, ie. the `generics_of` query works.
pub fn has_generics(self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe there can be a better name, like can contain generics or something? + a doc comment, e.g. at least mentioning generics_of

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modeled the name after pre-existing has_codegen_attrs. Added a doc-comment.

match self {
DefKind::AnonConst
| DefKind::AssocConst
| DefKind::AssocFn
| DefKind::AssocTy
| DefKind::Closure
| DefKind::Const
| DefKind::Ctor(..)
| DefKind::Enum
| DefKind::Field
| DefKind::Fn
| DefKind::ForeignTy
| DefKind::Impl { .. }
| DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Static { .. }
| DefKind::Struct
| DefKind::SyntheticCoroutineBody
| DefKind::Trait
| DefKind::TraitAlias
| DefKind::TyAlias
| DefKind::Union
| DefKind::Variant => true,
DefKind::ConstParam
| DefKind::ExternCrate
| DefKind::ForeignMod
| DefKind::GlobalAsm
| DefKind::LifetimeParam
| DefKind::Macro(_)
| DefKind::Mod
| DefKind::TyParam
| DefKind::Use => false,
}
}

/// Whether `query get_codegen_attrs` should be used with this definition.
pub fn has_codegen_attrs(self) -> bool {
match self {
Expand Down
111 changes: 31 additions & 80 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,93 +267,51 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstSt
None
}

/// A private tree-walker for producing an `Index`.
struct Annotator<'tcx> {
tcx: TyCtxt<'tcx>,
implications: UnordMap<Symbol, Symbol>,
}

impl<'tcx> Annotator<'tcx> {
/// Determine the stability for a node based on its attributes and inherited stability. The
/// stability is recorded in the index and used as the parent. If the node is a function,
/// `fn_sig` is its signature.
#[instrument(level = "trace", skip(self))]
fn annotate(&mut self, def_id: LocalDefId) {
if !self.tcx.features().staged_api() {
return;
}
fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap<Symbol, Symbol> {
let mut implications = UnordMap::default();

if let Some(stability) = self.tcx.lookup_stability(def_id)
let mut register_implication = |def_id| {
if let Some(stability) = tcx.lookup_stability(def_id)
&& let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
{
self.implications.insert(implied_by, stability.feature);
implications.insert(implied_by, stability.feature);
}

if let Some(stability) = self.tcx.lookup_const_stability(def_id)
if let Some(stability) = tcx.lookup_const_stability(def_id)
&& let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
{
self.implications.insert(implied_by, stability.feature);
implications.insert(implied_by, stability.feature);
}
}
}

impl<'tcx> Visitor<'tcx> for Annotator<'tcx> {
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
type NestedFilter = nested_filter::All;

fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
self.tcx
}
};

fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
match i.kind {
hir::ItemKind::Struct(_, _, ref sd) => {
if let Some(ctor_def_id) = sd.ctor_def_id() {
self.annotate(ctor_def_id);
if tcx.features().staged_api() {
register_implication(CRATE_DEF_ID);
for def_id in tcx.hir_crate_items(()).definitions() {
register_implication(def_id);
let def_kind = tcx.def_kind(def_id);
if def_kind.is_adt() {
let adt = tcx.adt_def(def_id);
for variant in adt.variants() {
if variant.def_id != def_id.to_def_id() {
register_implication(variant.def_id.expect_local());
}
for field in &variant.fields {
register_implication(field.did.expect_local());
}
if let Some(ctor_def_id) = variant.ctor_def_id() {
register_implication(ctor_def_id.expect_local())
}
}
}
if def_kind.has_generics() {
for param in tcx.generics_of(def_id).own_params.iter() {
register_implication(param.def_id.expect_local())
}
}
_ => {}
}

self.annotate(i.owner_id.def_id);
intravisit::walk_item(self, i)
}

fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
self.annotate(ti.owner_id.def_id);
intravisit::walk_trait_item(self, ti);
}

fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
self.annotate(ii.owner_id.def_id);
intravisit::walk_impl_item(self, ii);
}

fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
self.annotate(var.def_id);
if let Some(ctor_def_id) = var.data.ctor_def_id() {
self.annotate(ctor_def_id);
}

intravisit::walk_variant(self, var)
}

fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
self.annotate(s.def_id);
intravisit::walk_field_def(self, s);
}

fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
self.annotate(i.owner_id.def_id);
intravisit::walk_foreign_item(self, i);
}

fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
self.annotate(p.def_id);
intravisit::walk_generic_param(self, p);
}
implications
}

struct MissingStabilityAnnotations<'tcx> {
Expand Down Expand Up @@ -565,13 +523,6 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
}
}

fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap<Symbol, Symbol> {
let mut annotator = Annotator { tcx, implications: Default::default() };
annotator.annotate(CRATE_DEF_ID);
tcx.hir_walk_toplevel_module(&mut annotator);
annotator.implications
}

/// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors.
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
Expand Down
Loading