diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c9a5541585f..f0a139eccfe 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -260,6 +260,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { // Merge attributes into the inner expression. let mut attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect(); attrs.extend::>(ex.attrs.into()); + self.attrs[ex.hir_id] = &*self.arena.alloc_from_iter(attrs.iter().cloned()); ex.attrs = attrs.into(); return ex; } @@ -272,12 +273,10 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { - hir_id: self.lower_node_id(e.id), - kind, - span: e.span, - attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::>().into(), - } + let hir_id = self.lower_node_id(e.id); + let attrs = e.attrs.iter().map(|a| self.lower_attr(a)).collect::>(); + self.attrs.push_sparse(hir_id, &*self.arena.alloc_from_iter(attrs.iter().cloned())); + hir::Expr { hir_id, kind, span: e.span, attrs: attrs.into() } }) } @@ -618,9 +617,10 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { hir::Guard::If(self.lower_expr(cond)) } }); + let hir_id = self.next_id(); hir::Arm { - hir_id: self.next_id(), - attrs: self.lower_attrs(&arm.attrs), + hir_id, + attrs: self.lower_attrs(hir_id, &arm.attrs), pat, guard, body: self.lower_expr(&arm.body), @@ -2159,7 +2159,9 @@ pub(super) fn expr( kind: hir::ExprKind<'hir>, attrs: AttrVec, ) -> hir::Expr<'hir> { - hir::Expr { hir_id: self.next_id(), kind, span, attrs } + let hir_id = self.next_id(); + self.attrs.push_sparse(hir_id, &*self.arena.alloc_from_iter(attrs.iter().cloned())); + hir::Expr { hir_id, kind, span, attrs } } fn field(&mut self, ident: Ident, expr: &'hir hir::Expr<'hir>, span: Span) -> hir::Field<'hir> { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8b740b77740..5d733eda349 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -217,42 +217,40 @@ fn lower_item_id_use_tree( pub fn lower_item(&mut self, i: &Item) -> Option> { let mut ident = i.ident; let mut vis = self.lower_visibility(&i.vis, None); - let attrs = self.lower_attrs(&i.attrs); if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind { if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) { - let def_id = self.lower_node_id(i.id).expect_owner(); + let hir_id = self.lower_node_id(i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs); let body = P(self.lower_mac_args(body)); self.exported_macros.push(hir::MacroDef { ident, vis, attrs, - def_id, + def_id: hir_id.expect_owner(), span: i.span, ast: MacroDef { body, macro_rules }, }); } else { - self.non_exported_macro_attrs.extend(attrs.iter().cloned()); + for a in i.attrs.iter() { + let a = self.lower_attr(a); + self.non_exported_macro_attrs.push(a); + } } return None; } - let kind = self.lower_item_kind(i.span, i.id, &mut ident, attrs, &mut vis, &i.kind); - - Some(hir::Item { - def_id: self.lower_node_id(i.id).expect_owner(), - ident, - attrs, - kind, - vis, - span: i.span, - }) + let hir_id = self.lower_node_id(i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs); + let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind); + Some(hir::Item { def_id: hir_id.expect_owner(), ident, attrs, kind, vis, span: i.span }) } fn lower_item_kind( &mut self, span: Span, id: NodeId, + hir_id: hir::HirId, ident: &mut Ident, attrs: &'hir [Attribute], vis: &mut hir::Visibility<'hir>, @@ -365,14 +363,14 @@ fn lower_item_kind( self.lower_generics(generics, ImplTraitContext::disallowed()), ), ItemKind::Struct(ref struct_def, ref generics) => { - let struct_def = self.lower_variant_data(struct_def); + let struct_def = self.lower_variant_data(hir_id, struct_def); hir::ItemKind::Struct( struct_def, self.lower_generics(generics, ImplTraitContext::disallowed()), ) } ItemKind::Union(ref vdata, ref generics) => { - let vdata = self.lower_variant_data(vdata); + let vdata = self.lower_variant_data(hir_id, vdata); hir::ItemKind::Union( vdata, self.lower_generics(generics, ImplTraitContext::disallowed()), @@ -554,6 +552,7 @@ fn lower_use_tree( let path = this.lower_path_extra(res, &path, ParamMode::Explicit, None); let kind = hir::ItemKind::Use(path, hir::UseKind::Single); let vis = this.rebuild_vis(&vis); + this.attrs.push_sparse(new_id, attrs); this.insert_item(hir::Item { def_id: new_id.expect_owner(), @@ -626,6 +625,7 @@ fn lower_use_tree( let kind = this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs); + this.attrs.push_sparse(new_hir_id, attrs); this.insert_item(hir::Item { def_id: new_hir_id.expect_owner(), @@ -699,11 +699,12 @@ fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir> } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> { - let def_id = self.resolver.local_def_id(i.id); + let hir_id = self.lower_node_id(i.id); + let def_id = hir_id.expect_owner(); hir::ForeignItem { def_id, ident: i.ident, - attrs: self.lower_attrs(&i.attrs), + attrs: self.lower_attrs(hir_id, &i.attrs), kind: match i.kind { ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => { let fdec = &sig.decl; @@ -748,29 +749,43 @@ fn lower_global_asm(&mut self, ga: &GlobalAsm) -> &'hir hir::GlobalAsm { } fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { + let id = self.lower_node_id(v.id); hir::Variant { - attrs: self.lower_attrs(&v.attrs), - data: self.lower_variant_data(&v.data), + id, + attrs: self.lower_attrs(id, &v.attrs), + data: self.lower_variant_data(id, &v.data), disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)), - id: self.lower_node_id(v.id), ident: v.ident, span: v.span, } } - fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData<'hir> { + fn lower_variant_data( + &mut self, + parent_id: hir::HirId, + vdata: &VariantData, + ) -> hir::VariantData<'hir> { match *vdata { VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct( self.arena .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_struct_field(f))), recovered, ), - VariantData::Tuple(ref fields, id) => hir::VariantData::Tuple( - self.arena - .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_struct_field(f))), - self.lower_node_id(id), - ), - VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id)), + VariantData::Tuple(ref fields, id) => { + let ctor_id = self.lower_node_id(id); + self.attrs.push_sparse(ctor_id, self.attrs[parent_id]); + hir::VariantData::Tuple( + self.arena.alloc_from_iter( + fields.iter().enumerate().map(|f| self.lower_struct_field(f)), + ), + ctor_id, + ) + } + VariantData::Unit(id) => { + let ctor_id = self.lower_node_id(id); + self.attrs.push_sparse(ctor_id, self.attrs[parent_id]); + hir::VariantData::Unit(ctor_id) + } } } @@ -787,9 +802,10 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru } else { self.lower_ty(&f.ty, ImplTraitContext::disallowed()) }; + let hir_id = self.lower_node_id(f.id); hir::StructField { span: f.span, - hir_id: self.lower_node_id(f.id), + hir_id, ident: match f.ident { Some(ident) => ident, // FIXME(jseyfried): positional field hygiene. @@ -797,12 +813,13 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru }, vis: self.lower_visibility(&f.vis, None), ty, - attrs: self.lower_attrs(&f.attrs), + attrs: self.lower_attrs(hir_id, &f.attrs), } } fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> { - let trait_item_def_id = self.resolver.local_def_id(i.id); + let hir_id = self.lower_node_id(i.id); + let trait_item_def_id = hir_id.expect_owner(); let (generics, kind) = match i.kind { AssocItemKind::Const(_, ref ty, ref default) => { @@ -838,7 +855,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> { hir::TraitItem { def_id: trait_item_def_id, ident: i.ident, - attrs: self.lower_attrs(&i.attrs), + attrs: self.lower_attrs(hir_id, &i.attrs), generics, kind, span: i.span, @@ -920,10 +937,11 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); + let hir_id = self.lower_node_id(i.id); hir::ImplItem { - def_id: self.lower_node_id(i.id).expect_owner(), + def_id: hir_id.expect_owner(), ident: i.ident, - attrs: self.lower_attrs(&i.attrs), + attrs: self.lower_attrs(hir_id, &i.attrs), generics, vis: self.lower_visibility(&i.vis, None), defaultness, @@ -1024,9 +1042,10 @@ pub(super) fn lower_body( } fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { + let hir_id = self.lower_node_id(param.id); hir::Param { - attrs: self.lower_attrs(¶m.attrs), - hir_id: self.lower_node_id(param.id), + hir_id, + attrs: self.lower_attrs(hir_id, ¶m.attrs), pat: self.lower_pat(¶m.pat), ty_span: param.ty.span, span: param.span, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 756caf18ec5..c7a2b33a1d8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -114,6 +114,8 @@ struct LoweringContext<'a, 'hir: 'a> { generator_kind: Option, + attrs: hir::HirIdVec<&'hir [Attribute]>, + /// When inside an `async` context, this is the `HirId` of the /// `task_context` local bound to the resume argument of the generator. task_context: Option, @@ -309,6 +311,7 @@ pub fn lower_crate<'a, 'hir>( bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), modules: BTreeMap::new(), + attrs: hir::HirIdVec::default(), exported_macros: Vec::new(), non_exported_macro_attrs: Vec::new(), catch_scopes: Vec::new(), @@ -565,7 +568,7 @@ fn visit_ty(&mut self, t: &'tcx Ty) { visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); let module = self.lower_mod(&c.items, c.span); - let attrs = self.lower_attrs(&c.attrs); + let attrs = self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); let body_ids = body_ids(&self.bodies); let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect(); @@ -592,6 +595,9 @@ fn visit_ty(&mut self, t: &'tcx Ty) { self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id); + // Not all HIR owners have declared attrs. Complete with empty IndexVecs. + self.attrs.push_owner(Idx::new(self.resolver.definitions().def_index_count() - 1)); + hir::Crate { item: hir::CrateItem { module, attrs, span: c.span }, exported_macros: self.arena.alloc_from_iter(self.exported_macros), @@ -606,6 +612,7 @@ fn visit_ty(&mut self, t: &'tcx Ty) { modules: self.modules, proc_macros, trait_map, + attrs: self.attrs, } } @@ -967,8 +974,10 @@ fn with_new_scopes(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { ret } - fn lower_attrs(&mut self, attrs: &[Attribute]) -> &'hir [Attribute] { - self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))) + fn lower_attrs(&mut self, id: hir::HirId, attrs: &[Attribute]) -> &'hir [Attribute] { + let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); + self.attrs.push_sparse(id, ret); + ret } fn lower_attr(&mut self, attr: &Attribute) -> Attribute { @@ -1790,14 +1799,17 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { ) }); let init = l.init.as_ref().map(|e| self.lower_expr(e)); + let hir_id = self.lower_node_id(l.id); + let attrs = l.attrs.iter().map(|a| self.lower_attr(a)).collect::>(); + self.attrs.push_sparse(hir_id, &*self.arena.alloc_from_iter(attrs.iter().cloned())); ( hir::Local { - hir_id: self.lower_node_id(l.id), + hir_id, ty, pat: self.lower_pat(&l.pat), init, span: l.span, - attrs: l.attrs.iter().map(|a| self.lower_attr(a)).collect::>().into(), + attrs: attrs.into(), source: hir::LocalSource::Normal, }, ids, @@ -2300,12 +2312,13 @@ fn lower_generic_param( } }; + let hir_id = self.lower_node_id(param.id); hir::GenericParam { - hir_id: self.lower_node_id(param.id), + hir_id, name, span: param.ident.span, pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle), - attrs: self.lower_attrs(¶m.attrs), + attrs: self.lower_attrs(hir_id, ¶m.attrs), bounds: self.arena.alloc_from_iter(bounds), kind, } @@ -2519,7 +2532,9 @@ fn stmt_let_pat( pat: &'hir hir::Pat<'hir>, source: hir::LocalSource, ) -> hir::Stmt<'hir> { - let local = hir::Local { attrs, hir_id: self.next_id(), init, pat, source, span, ty: None }; + let hir_id = self.next_id(); + self.attrs.push_sparse(hir_id, &*self.arena.alloc_from_iter(attrs.iter().cloned())); + let local = hir::Local { attrs, hir_id, init, pat, source, span, ty: None }; self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1938cdd1e46..d4dfab2168c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2,7 +2,7 @@ use crate::def::{CtorKind, DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; -use crate::{itemlikevisit, LangItem}; +use crate::{itemlikevisit, HirIdVec, LangItem}; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect}; @@ -675,6 +675,9 @@ pub struct Crate<'hir> { pub proc_macros: Vec, pub trait_map: BTreeMap>, + + /// Collected attributes from HIR nodes. + pub attrs: HirIdVec<&'hir [Attribute]>, } impl Crate<'hir> { diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index dc7cf40bd90..e0b3d9026a0 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -82,6 +82,20 @@ pub fn push(&mut self, id: HirId, value: T) { debug_assert_eq!(_ret_id, id.local_id); } + pub fn push_sparse(&mut self, id: HirId, value: T) + where + T: Default, + { + self.map.ensure_contains_elem(id.owner, IndexVec::new); + let submap = &mut self.map[id.owner]; + let i = id.local_id.index(); + let len = submap.len(); + if i >= len { + submap.extend(std::iter::repeat_with(T::default).take(i - len + 1)); + } + submap[id.local_id] = value; + } + pub fn get(&self, id: HirId) -> Option<&T> { self.map.get(id.owner)?.get(id.local_id) } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index a5ffa9c7a54..0d2db4af7a8 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -116,6 +116,7 @@ pub(super) fn root( modules: _, proc_macros: _, trait_map: _, + attrs: _, } = *krate; hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes) @@ -131,7 +132,11 @@ pub(super) fn root( hcx, hir_body_nodes, map: (0..definitions.def_index_count()) - .map(|_| HirOwnerData { signature: None, with_bodies: None }) + .map(|id| HirOwnerData { + attrs: krate.attrs.get_owner(Idx::new(id)), + signature: None, + with_bodies: None, + }) .collect(), }; collector.insert_entry( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5c2bd575e7d..f0deb8bb668 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -88,6 +88,7 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool { #[derive(Debug)] pub(super) struct HirOwnerData<'hir> { + pub(super) attrs: &'hir IndexVec, pub(super) signature: Option<&'hir Owner<'hir>>, pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>, } @@ -457,10 +458,7 @@ pub fn trait_impls(&self, trait_did: DefId) -> &'hir [LocalDefId] { /// 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 +851,7 @@ pub fn name(&self, id: HirId) -> Symbol { /// 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).copied().unwrap_or(&[]) } /// Gets the span of the definition of the specified HIR node. diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 5f9cf8771ea..491934b845e 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -76,6 +76,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| &tcx.index_hir(LOCAL_CRATE).map[id].attrs; 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(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a8600af1de2..8edcefe72da 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -61,6 +61,15 @@ 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) -> &'tcx IndexVec { + 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. ///