Auto merge of #79519 - cjgillot:noattr, r=wesleywiser
Store HIR attributes in a side table Same idea as #72015 but for attributes. The objective is to reduce incr-comp invalidations due to modified attributes. Notably, those due to modified doc comments. Implementation: - collect attributes during AST->HIR lowering, in `LocalDefId -> ItemLocalId -> &[Attributes]` nested tables; - access the attributes through a `hir_owner_attrs` query; - local refactorings to use this access; - remove `attrs` from HIR data structures one-by-one. Change in behaviour: - the HIR visitor traverses all attributes at once instead of parent-by-parent; - attribute arrays are sometimes duplicated: for statements and variant constructors; - as a consequence, attributes are marked as used after unused-attribute lint emission to avoid duplicate lints. ~~Current bug: the lint level is not correctly applied in `std::backtrace_rs`, triggering an unused attribute warning on `#![no_std]`. I welcome suggestions.~~
This commit is contained in:
commit
dff1edf919
88 changed files with 936 additions and 920 deletions
|
@ -12,7 +12,6 @@
|
|||
//! for the `Code` associated with a particular NodeId.
|
||||
|
||||
use crate::hir::map::Map;
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Expr, FnDecl, Node};
|
||||
|
@ -105,7 +104,6 @@ struct ItemFnParts<'a> {
|
|||
body: hir::BodyId,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
attrs: &'a [Attribute],
|
||||
}
|
||||
|
||||
/// These are all the components one can extract from a closure expr
|
||||
|
@ -115,18 +113,11 @@ struct ClosureParts<'a> {
|
|||
body: hir::BodyId,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
attrs: &'a [Attribute],
|
||||
}
|
||||
|
||||
impl<'a> ClosureParts<'a> {
|
||||
fn new(
|
||||
d: &'a FnDecl<'a>,
|
||||
b: hir::BodyId,
|
||||
id: hir::HirId,
|
||||
s: Span,
|
||||
attrs: &'a [Attribute],
|
||||
) -> Self {
|
||||
ClosureParts { decl: d, body: b, id, span: s, attrs }
|
||||
fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self {
|
||||
ClosureParts { decl: d, body: b, id, span: s }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +137,7 @@ impl<'a> FnLikeNode<'a> {
|
|||
pub fn body(self) -> hir::BodyId {
|
||||
self.handle(
|
||||
|i: ItemFnParts<'a>| i.body,
|
||||
|_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _, _| body,
|
||||
|_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body,
|
||||
|c: ClosureParts<'a>| c.body,
|
||||
)
|
||||
}
|
||||
|
@ -154,7 +145,7 @@ impl<'a> FnLikeNode<'a> {
|
|||
pub fn decl(self) -> &'a FnDecl<'a> {
|
||||
self.handle(
|
||||
|i: ItemFnParts<'a>| &*i.decl,
|
||||
|_, _, sig: &'a hir::FnSig<'a>, _, _, _, _| &sig.decl,
|
||||
|_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl,
|
||||
|c: ClosureParts<'a>| c.decl,
|
||||
)
|
||||
}
|
||||
|
@ -162,7 +153,7 @@ impl<'a> FnLikeNode<'a> {
|
|||
pub fn span(self) -> Span {
|
||||
self.handle(
|
||||
|i: ItemFnParts<'_>| i.span,
|
||||
|_, _, _: &'a hir::FnSig<'a>, _, _, span, _| span,
|
||||
|_, _, _: &'a hir::FnSig<'a>, _, _, span| span,
|
||||
|c: ClosureParts<'_>| c.span,
|
||||
)
|
||||
}
|
||||
|
@ -170,7 +161,7 @@ impl<'a> FnLikeNode<'a> {
|
|||
pub fn id(self) -> hir::HirId {
|
||||
self.handle(
|
||||
|i: ItemFnParts<'_>| i.id,
|
||||
|id, _, _: &'a hir::FnSig<'a>, _, _, _, _| id,
|
||||
|id, _, _: &'a hir::FnSig<'a>, _, _, _| id,
|
||||
|c: ClosureParts<'_>| c.id,
|
||||
)
|
||||
}
|
||||
|
@ -189,12 +180,11 @@ impl<'a> FnLikeNode<'a> {
|
|||
|
||||
pub fn kind(self) -> FnKind<'a> {
|
||||
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
|
||||
FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
|
||||
};
|
||||
let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs);
|
||||
let method = |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _, attrs| {
|
||||
FnKind::Method(ident, sig, vis, attrs)
|
||||
FnKind::ItemFn(p.ident, p.generics, p.header, p.vis)
|
||||
};
|
||||
let closure = |_: ClosureParts<'a>| FnKind::Closure;
|
||||
let method =
|
||||
|_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis);
|
||||
self.handle(item, method, closure)
|
||||
}
|
||||
|
||||
|
@ -208,7 +198,6 @@ impl<'a> FnLikeNode<'a> {
|
|||
Option<&'a hir::Visibility<'a>>,
|
||||
hir::BodyId,
|
||||
Span,
|
||||
&'a [Attribute],
|
||||
) -> A,
|
||||
C: FnOnce(ClosureParts<'a>) -> A,
|
||||
{
|
||||
|
@ -221,7 +210,6 @@ impl<'a> FnLikeNode<'a> {
|
|||
body: block,
|
||||
vis: &i.vis,
|
||||
span: i.span,
|
||||
attrs: &i.attrs,
|
||||
header: sig.header,
|
||||
generics,
|
||||
}),
|
||||
|
@ -229,19 +217,19 @@ impl<'a> FnLikeNode<'a> {
|
|||
},
|
||||
Node::TraitItem(ti) => match ti.kind {
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
method(ti.hir_id(), ti.ident, sig, None, body, ti.span, &ti.attrs)
|
||||
method(ti.hir_id(), ti.ident, sig, None, body, ti.span)
|
||||
}
|
||||
_ => bug!("trait method FnLikeNode that is not fn-like"),
|
||||
},
|
||||
Node::ImplItem(ii) => match ii.kind {
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
|
||||
method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span)
|
||||
}
|
||||
_ => bug!("impl method FnLikeNode that is not fn-like"),
|
||||
},
|
||||
Node::Expr(e) => match e.kind {
|
||||
hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
|
||||
closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs))
|
||||
closure(ClosureParts::new(&decl, block, e.hir_id, e.span))
|
||||
}
|
||||
_ => bug!("expr FnLikeNode that is not fn-like"),
|
||||
},
|
||||
|
|
|
@ -116,6 +116,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
modules: _,
|
||||
proc_macros: _,
|
||||
trait_map: _,
|
||||
attrs: _,
|
||||
} = *krate;
|
||||
|
||||
hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
|
||||
|
|
|
@ -457,10 +457,7 @@ impl<'hir> Map<'hir> {
|
|||
/// invoking `krate.attrs` because it registers a tighter
|
||||
/// dep-graph access.
|
||||
pub fn krate_attrs(&self) -> &'hir [ast::Attribute] {
|
||||
match self.get_entry(CRATE_HIR_ID).node {
|
||||
Node::Crate(item) => item.attrs,
|
||||
_ => bug!(),
|
||||
}
|
||||
self.attrs(CRATE_HIR_ID)
|
||||
}
|
||||
|
||||
pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
|
||||
|
@ -853,34 +850,7 @@ impl<'hir> Map<'hir> {
|
|||
/// Given a node ID, gets a list of attributes associated with the AST
|
||||
/// corresponding to the node-ID.
|
||||
pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
|
||||
self.find_entry(id).map_or(&[], |entry| match entry.node {
|
||||
Node::Param(a) => a.attrs,
|
||||
Node::Local(l) => &l.attrs[..],
|
||||
Node::Item(i) => i.attrs,
|
||||
Node::ForeignItem(fi) => fi.attrs,
|
||||
Node::TraitItem(ref ti) => ti.attrs,
|
||||
Node::ImplItem(ref ii) => ii.attrs,
|
||||
Node::Variant(ref v) => v.attrs,
|
||||
Node::Field(ref f) => f.attrs,
|
||||
Node::Expr(ref e) => &*e.attrs,
|
||||
Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id)),
|
||||
Node::Arm(ref a) => &*a.attrs,
|
||||
Node::GenericParam(param) => param.attrs,
|
||||
// Unit/tuple structs/variants take the attributes straight from
|
||||
// the struct/variant definition.
|
||||
Node::Ctor(..) => self.attrs(self.get_parent_item(id)),
|
||||
Node::Crate(item) => item.attrs,
|
||||
Node::MacroDef(def) => def.attrs,
|
||||
Node::AnonConst(..)
|
||||
| Node::PathSegment(..)
|
||||
| Node::Ty(..)
|
||||
| Node::Pat(..)
|
||||
| Node::Binding(..)
|
||||
| Node::TraitRef(..)
|
||||
| Node::Block(..)
|
||||
| Node::Lifetime(..)
|
||||
| Node::Visibility(..) => &[],
|
||||
})
|
||||
self.tcx.hir_attrs(id.owner).get(id.local_id)
|
||||
}
|
||||
|
||||
/// Gets the span of the definition of the specified HIR node.
|
||||
|
|
|
@ -9,6 +9,7 @@ pub mod place;
|
|||
use crate::ich::StableHashingContext;
|
||||
use crate::ty::query::Providers;
|
||||
use crate::ty::TyCtxt;
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
@ -16,6 +17,7 @@ use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
|
|||
use rustc_hir::*;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Owner<'tcx> {
|
||||
|
@ -55,6 +57,48 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AttributeMap<'tcx> {
|
||||
map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
|
||||
prefix: LocalDefId,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> {
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||
let range = self.range();
|
||||
|
||||
range.clone().count().hash_stable(hcx, hasher);
|
||||
for (key, value) in range {
|
||||
key.hash_stable(hcx, hasher);
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AttributeMap")
|
||||
.field("prefix", &self.prefix)
|
||||
.field("range", &&self.range().collect::<Vec<_>>()[..])
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AttributeMap<'tcx> {
|
||||
fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
|
||||
self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[])
|
||||
}
|
||||
|
||||
fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> {
|
||||
let local_zero = ItemLocalId::from_u32(0);
|
||||
let range = HirId { owner: self.prefix, local_id: local_zero }..HirId {
|
||||
owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 },
|
||||
local_id: local_zero,
|
||||
};
|
||||
self.map.range(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
#[inline(always)]
|
||||
pub fn hir(self) -> map::Map<'tcx> {
|
||||
|
@ -76,6 +120,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
|
||||
providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
|
||||
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
|
||||
providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
|
||||
providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
|
||||
providers.fn_arg_names = |tcx, id| {
|
||||
let hir = tcx.hir();
|
||||
|
|
|
@ -66,11 +66,10 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
|
|||
|
||||
fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
|
||||
self.while_hashing_hir_bodies(true, |hcx| {
|
||||
let hir::Expr { hir_id: _, ref span, ref kind, ref attrs } = *expr;
|
||||
let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
|
||||
|
||||
span.hash_stable(hcx, hasher);
|
||||
kind.hash_stable(hcx, hasher);
|
||||
attrs.hash_stable(hcx, hasher);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,15 @@ rustc_queries! {
|
|||
desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
}
|
||||
|
||||
/// Gives access to the HIR attributes inside the HIR owner `key`.
|
||||
///
|
||||
/// This can be conveniently accessed by methods on `tcx.hir()`.
|
||||
/// Avoid calling this query directly.
|
||||
query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> {
|
||||
eval_always
|
||||
desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
}
|
||||
|
||||
/// Computes the `DefId` of the corresponding const parameter in case the `key` is a
|
||||
/// const argument and returns `None` otherwise.
|
||||
///
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue