1
Fork 0

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:
bors 2021-03-10 08:40:51 +00:00
commit dff1edf919
88 changed files with 936 additions and 920 deletions

View file

@ -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"),
},

View file

@ -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)

View file

@ -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.

View file

@ -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();

View file

@ -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);
})
}

View file

@ -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.
///