diff --git a/Cargo.lock b/Cargo.lock index cef4f11da80..af23324cbef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4146,6 +4146,7 @@ dependencies = [ name = "rustc_privacy" version = "0.0.0" dependencies = [ + "rustc_ast", "rustc_attr", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3acf69ec2b7..cc87078d54b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -170,7 +170,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_item_id_use_tree(use_tree, i.id, &mut vec); vec } - ItemKind::MacroDef(..) => SmallVec::new(), ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => { smallvec![i.id] } @@ -212,28 +211,6 @@ impl<'hir> LoweringContext<'_, 'hir> { pub fn lower_item(&mut self, i: &Item) -> Option> { let mut ident = i.ident; let mut vis = self.lower_visibility(&i.vis, None); - - if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind { - if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) { - let hir_id = self.lower_node_id(i.id); - self.lower_attrs(hir_id, &i.attrs); - let body = P(self.lower_mac_args(body)); - self.insert_macro_def(hir::MacroDef { - ident, - vis, - def_id: hir_id.expect_owner(), - span: i.span, - ast: MacroDef { body, macro_rules }, - }); - } else { - for a in i.attrs.iter() { - let a = self.lower_attr(a); - self.non_exported_macro_attrs.push(a); - } - } - return None; - } - 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); @@ -465,7 +442,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics(generics, ImplTraitContext::disallowed()), self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), ), - ItemKind::MacroDef(..) | ItemKind::MacCall(..) => { + ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => { + let body = P(self.lower_mac_args(body)); + + hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }) + } + ItemKind::MacCall(..) => { panic!("`TyMac` should have been expanded by now") } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 948d74e3bf8..bd2c9f41a53 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -103,7 +103,6 @@ struct LoweringContext<'a, 'hir: 'a> { /// The items being lowered are collected here. owners: IndexVec>>, bodies: BTreeMap>, - non_exported_macro_attrs: Vec, trait_impls: BTreeMap>, @@ -330,7 +329,6 @@ pub fn lower_crate<'a, 'hir>( trait_impls: BTreeMap::new(), modules: BTreeMap::new(), attrs: BTreeMap::default(), - non_exported_macro_attrs: Vec::new(), catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, @@ -551,7 +549,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let krate = hir::Crate { - non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs), owners: self.owners, bodies: self.bodies, body_ids, @@ -600,13 +597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id } - fn insert_macro_def(&mut self, item: hir::MacroDef<'hir>) { - let def_id = item.def_id; - let item = self.arena.alloc(item); - self.owners.ensure_contains_elem(def_id, || None); - self.owners[def_id] = Some(hir::OwnerNode::MacroDef(item)); - } - fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId { // Set up the counter if needed. self.item_local_id_counters.entry(owner).or_insert(0); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b09c668273a..f729973ddc6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -578,6 +578,33 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } + fn print_mac_def( + &mut self, + macro_def: &ast::MacroDef, + ident: &Ident, + sp: &Span, + print_visibility: impl FnOnce(&mut Self), + ) { + let (kw, has_bang) = if macro_def.macro_rules { + ("macro_rules", true) + } else { + print_visibility(self); + ("macro", false) + }; + self.print_mac_common( + Some(MacHeader::Keyword(kw)), + has_bang, + Some(*ident), + macro_def.body.delim(), + ¯o_def.body.inner_tokens(), + true, + *sp, + ); + if macro_def.body.need_semicolon() { + self.word(";"); + } + } + fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) { self.maybe_print_comment(path.span.lo()); @@ -1305,24 +1332,9 @@ impl<'a> State<'a> { } } ast::ItemKind::MacroDef(ref macro_def) => { - let (kw, has_bang) = if macro_def.macro_rules { - ("macro_rules", true) - } else { - self.print_visibility(&item.vis); - ("macro", false) - }; - self.print_mac_common( - Some(MacHeader::Keyword(kw)), - has_bang, - Some(item.ident), - macro_def.body.delim(), - ¯o_def.body.inner_tokens(), - true, - item.span, - ); - if macro_def.body.need_semicolon() { - self.word(";"); - } + self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + state.print_visibility(&item.vis) + }); } } self.ann.post(self, AnnNode::Item(item)) diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index c4cff79f6c5..0801a1bde22 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -35,7 +35,6 @@ macro_rules! arena_types { [few] inline_asm: rustc_hir::InlineAsm<$tcx>, [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, [] local: rustc_hir::Local<$tcx>, - [few] macro_def: rustc_hir::MacroDef<$tcx>, [few] mod_: rustc_hir::Mod<$tcx>, [] param: rustc_hir::Param<$tcx>, [] pat: rustc_hir::Pat<$tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 551e6a57b32..a9bd83a67c9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -670,9 +670,6 @@ pub struct ModuleItems { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(Debug)] pub struct Crate<'hir> { - // Attributes from non-exported macros, kept only for collecting the library feature list. - pub non_exported_macro_attrs: &'hir [Attribute], - pub owners: IndexVec>>, pub bodies: BTreeMap>, pub trait_impls: BTreeMap>, @@ -743,7 +740,7 @@ impl Crate<'_> { OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), - OwnerNode::MacroDef(_) | OwnerNode::Crate(_) => {} + OwnerNode::Crate(_) => {} } } } @@ -758,7 +755,7 @@ impl Crate<'_> { Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), - Some(OwnerNode::MacroDef(_)) | Some(OwnerNode::Crate(_)) | None => {} + Some(OwnerNode::Crate(_)) | None => {} }) } @@ -768,32 +765,6 @@ impl Crate<'_> { _ => None, }) } - - pub fn exported_macros<'hir>(&'hir self) -> impl Iterator> + 'hir { - self.owners.iter().filter_map(|owner| match owner { - Some(OwnerNode::MacroDef(macro_def)) => Some(*macro_def), - _ => None, - }) - } -} - -/// A macro definition, in this crate or imported from another. -/// -/// Not parsed directly, but created on macro import or `macro_rules!` expansion. -#[derive(Debug)] -pub struct MacroDef<'hir> { - pub ident: Ident, - pub vis: Visibility<'hir>, - pub def_id: LocalDefId, - pub span: Span, - pub ast: ast::MacroDef, -} - -impl MacroDef<'_> { - #[inline] - pub fn hir_id(&self) -> HirId { - HirId::make_owner(self.def_id) - } } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -2602,7 +2573,7 @@ pub struct PolyTraitRef<'hir> { pub type Visibility<'hir> = Spanned>; -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum VisibilityKind<'hir> { Public, Crate(CrateSugar), @@ -2791,6 +2762,8 @@ pub enum ItemKind<'hir> { Const(&'hir Ty<'hir>, BodyId), /// A function declaration. Fn(FnSig<'hir>, Generics<'hir>, BodyId), + /// A MBE macro definition (`macro_rules!` or `macro`). + Macro(ast::MacroDef), /// A module. Mod(Mod<'hir>), /// An external module, e.g. `extern { .. }`. @@ -2856,6 +2829,7 @@ impl ItemKind<'_> { ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", ItemKind::Fn(..) => "function", + ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "module", ItemKind::ForeignMod { .. } => "extern block", ItemKind::GlobalAsm(..) => "global asm item", @@ -2996,7 +2970,6 @@ pub enum OwnerNode<'hir> { ForeignItem(&'hir ForeignItem<'hir>), TraitItem(&'hir TraitItem<'hir>), ImplItem(&'hir ImplItem<'hir>), - MacroDef(&'hir MacroDef<'hir>), Crate(&'hir Mod<'hir>), } @@ -3006,8 +2979,7 @@ impl<'hir> OwnerNode<'hir> { OwnerNode::Item(Item { ident, .. }) | OwnerNode::ForeignItem(ForeignItem { ident, .. }) | OwnerNode::ImplItem(ImplItem { ident, .. }) - | OwnerNode::TraitItem(TraitItem { ident, .. }) - | OwnerNode::MacroDef(MacroDef { ident, .. }) => Some(*ident), + | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident), OwnerNode::Crate(..) => None, } } @@ -3018,7 +2990,6 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ForeignItem(ForeignItem { span, .. }) | OwnerNode::ImplItem(ImplItem { span, .. }) | OwnerNode::TraitItem(TraitItem { span, .. }) - | OwnerNode::MacroDef(MacroDef { span, .. }) | OwnerNode::Crate(Mod { inner: span, .. }) => *span, } } @@ -3062,8 +3033,7 @@ impl<'hir> OwnerNode<'hir> { OwnerNode::Item(Item { def_id, .. }) | OwnerNode::TraitItem(TraitItem { def_id, .. }) | OwnerNode::ImplItem(ImplItem { def_id, .. }) - | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) - | OwnerNode::MacroDef(MacroDef { def_id, .. }) => *def_id, + | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id, OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner, } } @@ -3095,13 +3065,6 @@ impl<'hir> OwnerNode<'hir> { _ => panic!(), } } - - pub fn expect_macro_def(self) -> &'hir MacroDef<'hir> { - match self { - OwnerNode::MacroDef(n) => n, - _ => panic!(), - } - } } impl<'hir> Into> for &'hir Item<'hir> { @@ -3128,12 +3091,6 @@ impl<'hir> Into> for &'hir TraitItem<'hir> { } } -impl<'hir> Into> for &'hir MacroDef<'hir> { - fn into(self) -> OwnerNode<'hir> { - OwnerNode::MacroDef(self) - } -} - impl<'hir> Into> for OwnerNode<'hir> { fn into(self) -> Node<'hir> { match self { @@ -3141,7 +3098,6 @@ impl<'hir> Into> for OwnerNode<'hir> { OwnerNode::ForeignItem(n) => Node::ForeignItem(n), OwnerNode::ImplItem(n) => Node::ImplItem(n), OwnerNode::TraitItem(n) => Node::TraitItem(n), - OwnerNode::MacroDef(n) => Node::MacroDef(n), OwnerNode::Crate(n) => Node::Crate(n), } } @@ -3167,7 +3123,6 @@ pub enum Node<'hir> { Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), Local(&'hir Local<'hir>), - MacroDef(&'hir MacroDef<'hir>), /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants /// with synthesized constructors. @@ -3204,7 +3159,6 @@ impl<'hir> Node<'hir> { | Node::ForeignItem(ForeignItem { ident, .. }) | Node::Field(FieldDef { ident, .. }) | Node::Variant(Variant { ident, .. }) - | Node::MacroDef(MacroDef { ident, .. }) | Node::Item(Item { ident, .. }) | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident), Node::Lifetime(lt) => Some(lt.name.ident()), @@ -3265,8 +3219,7 @@ impl<'hir> Node<'hir> { Node::Item(Item { def_id, .. }) | Node::TraitItem(TraitItem { def_id, .. }) | Node::ImplItem(ImplItem { def_id, .. }) - | Node::ForeignItem(ForeignItem { def_id, .. }) - | Node::MacroDef(MacroDef { def_id, .. }) => Some(HirId::make_owner(*def_id)), + | Node::ForeignItem(ForeignItem { def_id, .. }) => Some(HirId::make_owner(*def_id)), Node::Field(FieldDef { hir_id, .. }) | Node::AnonConst(AnonConst { hir_id, .. }) | Node::Expr(Expr { hir_id, .. }) @@ -3326,7 +3279,6 @@ impl<'hir> Node<'hir> { Node::ForeignItem(i) => Some(OwnerNode::ForeignItem(i)), Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)), Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)), - Node::MacroDef(i) => Some(OwnerNode::MacroDef(i)), Node::Crate(i) => Some(OwnerNode::Crate(i)), _ => None, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 7f153867596..f4fbfd2692c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -466,9 +466,6 @@ pub trait Visitor<'v>: Sized { walk_assoc_type_binding(self, type_binding) } fn visit_attribute(&mut self, _id: HirId, _attr: &'v Attribute) {} - fn visit_macro_def(&mut self, macro_def: &'v MacroDef<'v>) { - walk_macro_def(self, macro_def) - } fn visit_vis(&mut self, vis: &'v Visibility<'v>) { walk_vis(self, vis) } @@ -484,7 +481,6 @@ pub trait Visitor<'v>: Sized { pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) { let top_mod = krate.module(); visitor.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); - walk_list!(visitor, visit_macro_def, krate.exported_macros()); for (&id, attrs) in krate.attrs.iter() { for a in *attrs { visitor.visit_attribute(id, a) @@ -492,11 +488,6 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) { } } -pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) { - visitor.visit_id(macro_def.hir_id()); - visitor.visit_ident(macro_def.ident); -} - pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) { visitor.visit_id(mod_hir_id); for &item_id in module.item_ids { @@ -586,6 +577,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { item.span, item.hir_id(), ), + ItemKind::Macro(_) => { + visitor.visit_id(item.hir_id()); + } ItemKind::Mod(ref module) => { // `visit_mod()` takes care of visiting the `Item`'s `HirId`. visitor.visit_mod(module, item.span, item.hir_id()) diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 56060752833..422a1064874 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, MacroDef, Mod, - TraitItem, TraitItemId, Ty, VisibilityKind, + BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, + TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -190,16 +190,3 @@ impl HashStable for Item<'_> { }); } } - -impl HashStable for MacroDef<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - let MacroDef { ident, def_id: _, ref ast, ref vis, span } = *self; - - hcx.hash_hir_item_like(|hcx| { - ident.name.hash_stable(hcx, hasher); - ast.hash_stable(hcx, hasher); - vis.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - }); - } -} diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 473477bf22d..29c948fe318 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -111,6 +111,7 @@ impl Target { ItemKind::Static(..) => Target::Static, ItemKind::Const(..) => Target::Const, ItemKind::Fn(..) => Target::Fn, + ItemKind::Macro(..) => Target::MacroDef, ItemKind::Mod(..) => Target::Mod, ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9c286ad5ccf..42e51f4bb48 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -120,7 +120,6 @@ impl<'a> State<'a> { // printing. Node::Ctor(..) => panic!("cannot print isolated Ctor"), Node::Local(a) => self.print_local_decl(&a), - Node::MacroDef(_) => panic!("cannot print MacroDef"), Node::Crate(..) => panic!("cannot print Crate"), } } @@ -642,6 +641,11 @@ impl<'a> State<'a> { self.end(); // need to close a box self.ann.nested(self, Nested::Body(body)); } + hir::ItemKind::Macro(ref macro_def) => { + self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + state.print_visibility(&item.vis) + }); + } hir::ItemKind::Mod(ref _mod) => { self.head(visibility_qualified(&item.vis, "mod")); self.print_ident(item.ident); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8f848f54aad..a5b4fa15921 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -585,24 +585,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) { self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate"); - - for macro_def in krate.exported_macros() { - // Non exported macros should be skipped, since `missing_docs` only - // applies to externally visible items. - if !cx.access_levels.is_exported(macro_def.def_id) { - continue; - } - - let attrs = cx.tcx.hir().attrs(macro_def.hir_id()); - let has_doc = attrs.iter().any(has_doc); - if !has_doc { - cx.struct_span_lint( - MISSING_DOCS, - cx.tcx.sess.source_map().guess_head_span(macro_def.span), - |lint| lint.build("missing documentation for macro").emit(), - ); - } - } } fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { @@ -636,6 +618,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { hir::ItemKind::TyAlias(..) | hir::ItemKind::Fn(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 052efa851f7..30400da86b4 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -453,10 +453,6 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) lint_callback!(cx, check_crate, krate); hir_visit::walk_crate(cx, krate); - for attr in krate.non_exported_macro_attrs { - // This HIR ID is a lie, since the macro ID isn't available. - cx.visit_attribute(hir::CRATE_HIR_ID, attr); - } lint_callback!(cx, check_crate_post, krate); }) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index e6cbfa0c9e2..90bf34ee863 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -37,9 +37,6 @@ fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); - for macro_def in krate.exported_macros() { - builder.levels.register_id(macro_def.hir_id()); - } intravisit::walk_crate(&mut builder, krate); builder.levels.pop(push); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4e591b28f60..dd44e0cb1fa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1100,7 +1100,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(child_index); let def_id = self.local_def_id(child_index); let res = Res::Def(kind, def_id); - callback(Export { res, ident, vis, span }); + + // FIXME: Macros are currently encoded twice, once as items and once as + // reexports. We ignore the items here and only use the reexports. + if !matches!(kind, DefKind::Macro(..)) { + callback(Export { res, ident, vis, span }); + } + // For non-re-export structs and variants add their constructors to children. // Re-export lists automatically contain constructors when necessary. match kind { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1c243f8bd51..2cd4fe3b706 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -448,9 +448,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } krate.visit_all_item_likes(&mut self.as_deep_visitor()); - for macro_def in krate.exported_macros() { - self.visit_macro_def(macro_def); - } } fn encode_def_path_table(&mut self) { @@ -1385,6 +1382,9 @@ impl EncodeContext<'a, 'tcx> { EntryKind::Fn(self.lazy(data)) } + hir::ItemKind::Macro(ref macro_def) => { + EntryKind::MacroDef(self.lazy(macro_def.clone())) + } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); } @@ -1539,13 +1539,6 @@ impl EncodeContext<'a, 'tcx> { } } - /// Serialize the text of exported macros - fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) { - let def_id = macro_def.def_id.to_def_id(); - record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone()))); - self.encode_ident_span(def_id, macro_def.ident); - } - fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) { record!(self.tables.kind[def_id] <- kind); if encode_type { @@ -1915,9 +1908,6 @@ impl Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_generics(self, generics); self.encode_info_for_generics(generics); } - fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) { - self.encode_info_for_macro_def(macro_def); - } } impl EncodeContext<'a, 'tcx> { @@ -1972,6 +1962,7 @@ impl EncodeContext<'a, 'tcx> { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 5c166c74004..1351b4950f1 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -394,20 +394,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } } - fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) { - // Exported macros are visited directly from the crate root, - // so they do not have `parent_node` set. - // Find the correct enclosing module from their DefKey. - let def_key = self.definitions.def_key(macro_def.def_id); - let parent = def_key.parent.map_or(hir::CRATE_HIR_ID, |local_def_index| { - self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index }) - }); - self.insert_owner(macro_def.def_id, OwnerNode::MacroDef(macro_def)); - self.with_parent(parent, |this| { - this.insert_nested(macro_def.def_id); - }); - } - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { self.insert(v.span, v.id, Node::Variant(v)); self.with_parent(v.id, |this| { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index c313146b072..62d0374fb52 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -10,7 +10,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit; -use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; use rustc_index::vec::Idx; @@ -218,6 +217,7 @@ impl<'hir> Map<'hir> { ItemKind::Static(..) => DefKind::Static, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) => DefKind::Fn, + ItemKind::Macro(..) => DefKind::Macro(MacroKind::Bang), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, ItemKind::TyAlias(..) => DefKind::TyAlias, @@ -266,7 +266,6 @@ impl<'hir> Map<'hir> { ExprKind::Closure(.., Some(_)) => DefKind::Generator, _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), }, - Node::MacroDef(_) => DefKind::Macro(MacroKind::Bang), Node::GenericParam(param) => match param.kind { GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam, GenericParamKind::Type { .. } => DefKind::TyParam, @@ -543,15 +542,6 @@ impl<'hir> Map<'hir> { } } - pub fn visit_exported_macros_in_krate(&self, visitor: &mut V) - where - V: Visitor<'hir>, - { - for macro_def in self.krate().exported_macros() { - visitor.visit_macro_def(macro_def); - } - } - /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> { @@ -645,8 +635,6 @@ impl<'hir> Map<'hir> { /// in a module, trait, or impl. pub fn get_parent_item(&self, hir_id: HirId) -> HirId { if let Some((hir_id, _node)) = self.parent_owner_iter(hir_id).next() { - // A MacroDef does not have children. - debug_assert!(!matches!(_node, OwnerNode::MacroDef(_))); hir_id } else { CRATE_HIR_ID @@ -774,13 +762,6 @@ impl<'hir> Map<'hir> { } } - pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> { - match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::MacroDef(macro_def) }) => macro_def, - _ => bug!("expected macro def, found {}", self.node_to_string(id)), - } - } - pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> { match self.find(id) { Some(Node::Expr(expr)) => expr, @@ -800,7 +781,6 @@ impl<'hir> Map<'hir> { Node::GenericParam(param) => param.name.ident().name, Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name, Node::Ctor(..) => self.name(self.get_parent_item(id)), - Node::MacroDef(md) => md.ident.name, _ => return None, }) } @@ -867,7 +847,6 @@ impl<'hir> Map<'hir> { Node::Infer(i) => i.span, Node::Visibility(v) => bug!("unexpected Visibility {:?}", v), Node::Local(local) => local.span, - Node::MacroDef(macro_def) => macro_def.span, Node::Crate(item) => item.inner, }; Some(span) @@ -1013,7 +992,6 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { source_file_names.hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); - tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher); let crate_hash: Fingerprint = stable_hasher.finish(); Svh::new(crate_hash.to_smaller_hash()) @@ -1062,6 +1040,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { ItemKind::Static(..) => "static", ItemKind::Const(..) => "const", ItemKind::Fn(..) => "fn", + ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "mod", ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", @@ -1118,7 +1097,6 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { Some(Node::Lifetime(_)) => node_str("lifetime"), Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str), Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str), - Some(Node::MacroDef(_)) => format!("macro {}{}", path_str(), id_str), Some(Node::Crate(..)) => String::from("root_crate"), None => format!("unknown node{}", id_str), } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index f03036267ac..4cb362238c1 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -1149,6 +1149,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { match item.kind { hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::TyAlias(..) | hir::ItemKind::Trait(..) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0ddad1c1a3..d3dac35d2c9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1723,6 +1723,16 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx Item<'tcx>) { + // Historically we've run more checks on non-exported than exported macros, + // so this lets us continue to run them while maintaining backwards compatibility. + // In the long run, the checks should be harmonized. + if let ItemKind::Macro(ref macro_def) = item.kind { + let def_id = item.def_id.to_def_id(); + if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { + check_non_exported_macro_for_invalid_attrs(self.tcx, item); + } + } + let target = Target::from_item(item); self.check_attributes(item.hir_id(), &item.span, target, Some(ItemLike::Item(item))); intravisit::walk_item(self, item) @@ -1795,11 +1805,6 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_variant(self, variant, generics, item_id) } - fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) { - self.check_attributes(macro_def.hir_id(), ¯o_def.span, Target::MacroDef, None); - intravisit::walk_macro_def(self, macro_def); - } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { self.check_attributes(param.hir_id, ¶m.span, Target::Param, None); @@ -1848,7 +1853,9 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { } } -fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { +fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { + let attrs = tcx.hir().attrs(item.hir_id()); + for attr in attrs { if attr.has_name(sym::inline) { struct_span_err!( @@ -1869,8 +1876,6 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { if module_def_id.is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); - tcx.hir().visit_exported_macros_in_krate(check_attr_visitor); - check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs); } } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index e43abda7133..3f12a744be0 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -107,10 +107,6 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_attribute(&mut self, _: hir::HirId, attr: &'v ast::Attribute) { self.record("Attribute", Id::Attr(attr.id), attr); } - - fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) { - self.record("MacroDef", Id::Node(macro_def.hir_id()), macro_def); - hir_visit::walk_macro_def(self, macro_def) - } } impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 605b52f1891..7d15ca1e8f7 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -127,9 +127,7 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> { fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { let mut collector = LibFeatureCollector::new(tcx); let krate = tcx.hir().krate(); - for attr in krate.non_exported_macro_attrs { - collector.visit_attribute(rustc_hir::CRATE_HIR_ID, attr); - } + intravisit::walk_crate(&mut collector, krate); collector.lib_features } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 5ca098c2287..23f43233b79 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -263,6 +263,7 @@ impl<'tcx> ReachableContext<'tcx> { | hir::ItemKind::Use(..) | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } @@ -309,8 +310,7 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Ctor(..) | Node::Field(_) | Node::Ty(_) - | Node::Crate(_) - | Node::MacroDef(_) => {} + | Node::Crate(_) => {} _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b64dcb0bbf0..a88393cea82 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -538,19 +538,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ); } - fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.annotate( - md.def_id, - md.span, - None, - AnnotationKind::Required, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::No, - |_| {}, - ); - } - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { let kind = match &p.kind { // Allow stability attributes on default generic arguments. @@ -662,11 +649,6 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { self.check_missing_stability(i.def_id, i.span); intravisit::walk_foreign_item(self, i); } - - fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.check_missing_stability(md.def_id, md.span); - } - // Note that we don't need to `check_missing_stability` for default generic parameters, // as we assume that any default generic parameters without attributes are automatically // stable (assuming they have not inherited instability from their parent). diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 85a53b1bde2..6ac2915c345 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [dependencies] rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6fe68a0c17a..079a9ed878a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -6,6 +6,7 @@ #![feature(associated_type_defaults)] #![recursion_limit = "256"] +use rustc_ast::MacroDef; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; @@ -26,7 +27,7 @@ use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst}; @@ -462,6 +463,43 @@ impl EmbargoVisitor<'tcx> { } } + // We have to make sure that the items that macros might reference + // are reachable, since they might be exported transitively. + fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &MacroDef) { + // Non-opaque macros cannot make other items more accessible than they already are. + + let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + let attrs = self.tcx.hir().attrs(hir_id); + if attr::find_transparency(&attrs, md.macro_rules).0 != Transparency::Opaque { + return; + } + + let item_def_id = local_def_id.to_def_id(); + let macro_module_def_id = + ty::DefIdTree::parent(self.tcx, item_def_id).unwrap().expect_local(); + if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { + // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). + return; + } + + if self.get(local_def_id).is_none() { + return; + } + + // Since we are starting from an externally visible module, + // all the parents in the loop below are also guaranteed to be modules. + let mut module_def_id = macro_module_def_id; + loop { + let changed_reachability = + self.update_macro_reachable(module_def_id, macro_module_def_id); + if changed_reachability || module_def_id == CRATE_DEF_ID { + break; + } + module_def_id = + ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local(); + } + } + /// Updates the item as being reachable through a macro defined in the given /// module. Returns `true` if the level has changed. fn update_macro_reachable( @@ -511,16 +549,26 @@ impl EmbargoVisitor<'tcx> { } match def_kind { // No type privacy, so can be directly marked as reachable. - DefKind::Const - | DefKind::Macro(_) - | DefKind::Static - | DefKind::TraitAlias - | DefKind::TyAlias => { + DefKind::Const | DefKind::Static | DefKind::TraitAlias | DefKind::TyAlias => { if vis.is_accessible_from(module.to_def_id(), self.tcx) { self.update(def_id, level); } } + // Hygine isn't really implemented for `macro_rules!` macros at the + // moment. Accordingly, marking them as reachable is unwise. `macro` macros + // have normal hygine, so we can treat them like other items without type + // privacy and mark them reachable. + DefKind::Macro(_) => { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let item = self.tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind { + if vis.is_accessible_from(module.to_def_id(), self.tcx) { + self.update(def_id, level); + } + } + } + // We can't use a module name as the final segment of a path, except // in use statements. Since re-export checking doesn't consider // hygiene these don't need to be marked reachable. The contents of @@ -644,6 +692,12 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { hir::ItemKind::Impl { .. } => { Option::::of_impl(item.def_id, self.tcx, &self.access_levels) } + // Only exported `macro_rules!` items are public, but they always are. + hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => { + let def_id = item.def_id.to_def_id(); + let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export); + if is_macro_export { Some(AccessLevel::Public) } else { None } + } // Foreign modules inherit level from parents. hir::ItemKind::ForeignMod { .. } => self.prev_level, // Other `pub` items inherit levels from parents. @@ -652,6 +706,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::ExternCrate(..) | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Fn(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) @@ -708,6 +763,9 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } + hir::ItemKind::Macro(ref macro_def) => { + self.update_reachability_from_macro(item.def_id, macro_def); + } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { if foreign_item.vis.node.is_pub() { @@ -715,6 +773,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } + hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Use(..) | hir::ItemKind::Static(..) @@ -730,7 +789,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { // Mark all items in interfaces of reachable items as reachable. match item.kind { // The interface is empty. - hir::ItemKind::ExternCrate(..) => {} + hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {} // All nested items are checked by `visit_item`. hir::ItemKind::Mod(..) => {} // Re-exports are handled in `visit_mod`. However, in order to avoid looping over @@ -885,45 +944,6 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { intravisit::walk_mod(self, m, id); } - - fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - // Non-opaque macros cannot make other items more accessible than they already are. - let attrs = self.tcx.hir().attrs(md.hir_id()); - if attr::find_transparency(&attrs, md.ast.macro_rules).0 != Transparency::Opaque { - // `#[macro_export]`-ed `macro_rules!` are `Public` since they - // ignore their containing path to always appear at the crate root. - if md.ast.macro_rules { - self.update(md.def_id, Some(AccessLevel::Public)); - } - return; - } - - let macro_module_def_id = - ty::DefIdTree::parent(self.tcx, md.def_id.to_def_id()).unwrap().expect_local(); - if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { - // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). - return; - } - - let level = if md.vis.node.is_pub() { self.get(macro_module_def_id) } else { None }; - let new_level = self.update(md.def_id, level); - if new_level.is_none() { - return; - } - - // Since we are starting from an externally visible module, - // all the parents in the loop below are also guaranteed to be modules. - let mut module_def_id = macro_module_def_id; - loop { - let changed_reachability = - self.update_macro_reachable(module_def_id, macro_module_def_id); - if changed_reachability || module_def_id == CRATE_DEF_ID { - break; - } - module_def_id = - ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local(); - } - } } impl ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { @@ -1981,7 +2001,7 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> { // Checked in resolve. hir::ItemKind::Use(..) => {} // No subitems. - hir::ItemKind::GlobalAsm(..) => {} + hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {} // Subitems of these items have inherited publicity. hir::ItemKind::Const(..) | hir::ItemKind::Static(..) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 882d15cf892..bc2c46ec0aa 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -740,6 +740,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) => { diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index c3bc1c191ff..7864b47ab0a 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -416,6 +416,14 @@ impl<'hir> Sig for hir::Item<'hir> { Ok(sig) } + hir::ItemKind::Macro(_) => { + let mut text = "macro".to_owned(); + let name = self.ident.to_string(); + text.push_str(&name); + text.push_str(&"! {}"); + + Ok(text_sig(text)) + } hir::ItemKind::Mod(ref _mod) => { let mut text = "mod ".to_owned(); let name = self.ident.to_string(); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b514176ad52..145a0c5413b 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -746,6 +746,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { // These don't define types. hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) + | hir::ItemKind::Macro(_) | hir::ItemKind::Mod(_) | hir::ItemKind::GlobalAsm(_) => {} hir::ItemKind::ForeignMod { items, .. } => { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 9bce5ee0da2..41277b22da0 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -427,6 +427,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } ItemKind::Trait(..) | ItemKind::TraitAlias(..) + | ItemKind::Macro(..) | ItemKind::Mod(..) | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm(..) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b6ff3890c58..640acffb114 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -91,7 +91,6 @@ impl Clean for doctree::Module<'_> { items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); - items.extend(self.macros.iter().map(|x| x.clean(cx))); // determine if we should display the inner contents or // the outer `mod` item for the source code. @@ -1861,6 +1860,10 @@ impl Clean> for (&hir::Item<'_>, Option) { ItemKind::Fn(ref sig, ref generics, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } + ItemKind::Macro(ref macro_def) => MacroItem(Macro { + source: display_macro_source(cx, name, ¯o_def, def_id, &item.vis), + imported_from: None, + }), ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids .iter() @@ -2138,24 +2141,6 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { } } -impl Clean for (&hir::MacroDef<'_>, Option) { - fn clean(&self, cx: &mut DocContext<'_>) -> Item { - let (item, renamed) = self; - let name = renamed.unwrap_or(item.ident.name); - let def_id = item.def_id.to_def_id(); - - Item::from_hir_id_and_parts( - item.hir_id(), - Some(name), - MacroItem(Macro { - source: display_macro_source(cx, name, &item.ast, def_id, &item.vis), - imported_from: None, - }), - cx, - ) - } -} - impl Clean for hir::TypeBinding<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding { TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 083d82cb414..bf14a17c076 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1171,10 +1171,21 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> } fn visit_item(&mut self, item: &'hir hir::Item<'_>) { - let name = if let hir::ItemKind::Impl(impl_) = &item.kind { - rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) - } else { - item.ident.to_string() + let name = match &item.kind { + hir::ItemKind::Macro(ref macro_def) => { + // FIXME(#88038): Non exported macros have historically not been tested, + // but we really ought to start testing them. + let def_id = item.def_id.to_def_id(); + if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { + intravisit::walk_item(self, item); + return; + } + item.ident.to_string() + } + hir::ItemKind::Impl(impl_) => { + rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) + } + _ => item.ident.to_string(), }; self.visit_testable(name, item.hir_id(), item.span, |this| { @@ -1216,15 +1227,6 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> intravisit::walk_field_def(this, f); }); } - - fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef<'_>) { - self.visit_testable( - macro_def.ident.to_string(), - macro_def.hir_id(), - macro_def.span, - |_| (), - ); - } } #[cfg(test)] diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index eadac89f79e..8f1e8f277c5 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -5,6 +5,7 @@ use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; +#[derive(Debug)] crate struct Module<'hir> { crate name: Symbol, crate where_inner: Span, @@ -13,20 +14,11 @@ crate struct Module<'hir> { // (item, renamed) crate items: Vec<(&'hir hir::Item<'hir>, Option)>, crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, - crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, } impl Module<'hir> { crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> { - Module { - name, - id, - where_inner, - mods: Vec::new(), - items: Vec::new(), - foreigns: Vec::new(), - macros: Vec::new(), - } + Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() } } crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e2891035535..897b9140fc8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -9,7 +9,7 @@ use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span; -use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; @@ -79,49 +79,23 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &krate.module(), self.cx.tcx.crate_name(LOCAL_CRATE), ); - // Attach the crate's exported macros to the top-level module. - // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as - // well (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by - // moving them back to their correct locations. - 'exported_macros: for def in krate.exported_macros() { - // The `def` of a macro in `exported_macros` should correspond to either: - // - a `#[macro_export] macro_rules!` macro, - // - a built-in `derive` (or attribute) macro such as the ones in `::core`, - // - a `pub macro`. - // Only the last two need to be fixed, thus: - if def.ast.macro_rules { - top_level_module.macros.push((def, None)); - continue 'exported_macros; - } - let tcx = self.cx.tcx; - // Note: this is not the same as `.parent_module()`. Indeed, the latter looks - // for the closest module _ancestor_, which is not necessarily a direct parent - // (since a direct parent isn't necessarily a module, c.f. #77828). - let macro_parent_def_id = { - use rustc_middle::ty::DefIdTree; - tcx.parent(def.def_id.to_def_id()).unwrap() - }; - let macro_parent_path = tcx.def_path(macro_parent_def_id); - // HACK: rustdoc has no way to lookup `doctree::Module`s by their HirId. Instead, - // lookup the module by its name, by looking at each path segment one at a time. - let mut cur_mod = &mut top_level_module; - for path_segment in macro_parent_path.data { - // Path segments may refer to a module (in which case they belong to the type - // namespace), which is _necessary_ for the macro to be accessible outside it - // (no "associated macros" as of yet). Else we bail with an outer `continue`. - let path_segment_ty_ns = match path_segment.data { - rustc_hir::definitions::DefPathData::TypeNs(symbol) => symbol, - _ => continue 'exported_macros, - }; - // Descend into the child module that matches this path segment (if any). - match cur_mod.mods.iter_mut().find(|child| child.name == path_segment_ty_ns) { - Some(child_mod) => cur_mod = &mut *child_mod, - None => continue 'exported_macros, + + // `#[macro_export] macro_rules!` items are reexported at the top level of the + // crate, regardless of where they're defined. We want to document the + // top level rexport of the macro, not its original definition, since + // the rexport defines the path that a user will actually see. Accordingly, + // we add the rexport as an item here, and then skip over the original + // definition in `visit_item()` below. + for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) { + if let Res::Def(DefKind::Macro(_), def_id) = export.res { + if let Some(local_def_id) = def_id.as_local() { + if self.cx.tcx.has_attr(def_id, sym::macro_export) { + let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + let item = self.cx.tcx.hir().expect_item(hir_id); + top_level_module.items.push((item, None)); + } } } - let cur_mod_def_id = tcx.hir().local_def_id(cur_mod.id).to_def_id(); - assert_eq!(cur_mod_def_id, macro_parent_def_id); - cur_mod.macros.push((def, None)); } self.cx.cache.exact_paths = self.exact_paths; top_level_module @@ -238,10 +212,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.inlining = prev; true } - Node::MacroDef(def) if !glob => { - om.macros.push((def, renamed)); - true - } _ => false, }; self.view_item_stack.remove(&res_hir_id); @@ -257,7 +227,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); - if item.vis.node.is_pub() { + let def_id = item.def_id.to_def_id(); + let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export); + + if is_pub { self.store_path(item.def_id.to_def_id()); } @@ -269,7 +242,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } // If we're inlining, skip private items. - _ if self.inlining && !item.vis.node.is_pub() => {} + _ if self.inlining && !is_pub => {} hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} hir::ItemKind::Use(ref path, kind) => { @@ -285,7 +258,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. - if item.vis.node.is_pub() && self.inside_public_path { + if is_pub && self.inside_public_path { let please_inline = attrs.iter().any(|item| match item.meta_item_list() { Some(ref list) if item.has_name(sym::doc) => { list.iter().any(|i| i.has_name(sym::inline)) @@ -307,6 +280,26 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.items.push((item, renamed)) } + hir::ItemKind::Macro(ref macro_def) => { + // `#[macro_export] macro_rules!` items are handled seperately in `visit()`, + // above, since they need to be documented at the module top level. Accordingly, + // we only want to handle macros if one of three conditions holds: + // + // 1. This macro was defined by `macro`, and thus isn't covered by the case + // above. + // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered + // by the case above. + // 3. We're inlining, since a reexport where inlining has been requested + // should be inlined even if it is also documented at the top level. + + let def_id = item.def_id.to_def_id(); + let is_macro_2_0 = !macro_def.macro_rules; + let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export); + + if is_macro_2_0 || nonexported || self.inlining { + om.items.push((item, renamed)); + } + } hir::ItemKind::Mod(ref m) => { om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name)); } diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr index a564006e74f..0867b08183e 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr @@ -1,4 +1,4 @@ -error: missing documentation for macro +error: missing documentation for a macro --> $DIR/deny-missing-docs-macro.rs:6:1 | LL | macro_rules! foo { diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs new file mode 100644 index 00000000000..460785ed979 --- /dev/null +++ b/src/test/rustdoc/macro-document-private-duplicate.rs @@ -0,0 +1,23 @@ +// FIXME: If two macros in the same module have the same name +// (yes, that's a thing), rustdoc lists both of them on the index page, +// but only documents the first one on the page for the macro. +// Fortunately, this can only happen in document private items mode, +// but it still isn't ideal beahvior. +// +// See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453 +// +// compile-flags: --document-private-items + +// @has macro_document_private_duplicate/index.html 'Doc 1.' +// @has macro_document_private_duplicate/macro.a_macro.html 'Doc 1.' +/// Doc 1. +macro_rules! a_macro { + () => () +} + +// @has macro_document_private_duplicate/index.html 'Doc 2.' +// @!has macro_document_private_duplicate/macro.a_macro.html 'Doc 2.' +/// Doc 2. +macro_rules! a_macro { + () => () +} diff --git a/src/test/rustdoc/macro-document-private.rs b/src/test/rustdoc/macro-document-private.rs new file mode 100644 index 00000000000..d2496913ffc --- /dev/null +++ b/src/test/rustdoc/macro-document-private.rs @@ -0,0 +1,19 @@ +// Checks that private macros are documented when `--document-private-items` +// is present. +// +// This is a regression test for issue #73754. +// +// compile-flags: --document-private-items + +#![feature(decl_macro)] + + +// @has macro_document_private/macro.some_macro.html +macro some_macro { + (a: tt) => {} +} + +// @has macro_document_private/macro.another_macro.html +macro_rules! another_macro { + (a: tt) => {} +} diff --git a/src/test/rustdoc/macro-indirect-use.rs b/src/test/rustdoc/macro-indirect-use.rs new file mode 100644 index 00000000000..b2d9336cffc --- /dev/null +++ b/src/test/rustdoc/macro-indirect-use.rs @@ -0,0 +1,16 @@ +// Checks that it is possible to make a macro public through a `pub use` of its +// parent module. +// +// This is a regression test for issue #87257. + +#![feature(decl_macro)] + +mod outer { + pub mod inner { + pub macro some_macro() {} + } +} + +// @has macro_indirect_use/inner/index.html +// @has macro_indirect_use/inner/macro.some_macro.html +pub use outer::inner; diff --git a/src/test/ui/lint/lint-level-macro-def-mod.rs b/src/test/ui/lint/lint-level-macro-def-mod.rs new file mode 100644 index 00000000000..79f7d1206df --- /dev/null +++ b/src/test/ui/lint/lint-level-macro-def-mod.rs @@ -0,0 +1,17 @@ +// This checks that exported macros lint as part of their module of origin, not +// the root module. +// +// check-pass + +//! Top level documentation +#![deny(missing_docs)] + +#[allow(missing_docs)] +mod module { + #[macro_export] + macro_rules! hello { + () => () + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-level-macro-def.rs b/src/test/ui/lint/lint-level-macro-def.rs new file mode 100644 index 00000000000..720f4b453ab --- /dev/null +++ b/src/test/ui/lint/lint-level-macro-def.rs @@ -0,0 +1,17 @@ +// Checks that you can set a lint level specficially for a macro definition. +// +// This is a regression test for issue #59306. +// +// check-pass + + +#[deny(missing_docs)] +mod module { + #[allow(missing_docs)] + #[macro_export] + macro_rules! hello { + () => () + } +} + +fn main() {} diff --git a/src/test/ui/lint/missing-doc-private-macro.rs b/src/test/ui/lint/missing-doc-private-macro.rs index 8d1d5c56880..0d4332ed08b 100644 --- a/src/test/ui/lint/missing-doc-private-macro.rs +++ b/src/test/ui/lint/missing-doc-private-macro.rs @@ -29,13 +29,13 @@ mod submodule { #[macro_export] macro_rules! exported_to_top_level { - //~^ ERROR missing documentation for macro + //~^ ERROR missing documentation for a macro () => () } } pub macro top_level_pub_macro { - //~^ ERROR missing documentation for macro + //~^ ERROR missing documentation for a macro () => () } diff --git a/src/test/ui/lint/missing-doc-private-macro.stderr b/src/test/ui/lint/missing-doc-private-macro.stderr index a5d39faf405..979b007d0ec 100644 --- a/src/test/ui/lint/missing-doc-private-macro.stderr +++ b/src/test/ui/lint/missing-doc-private-macro.stderr @@ -1,4 +1,4 @@ -error: missing documentation for macro +error: missing documentation for a macro --> $DIR/missing-doc-private-macro.rs:31:5 | LL | macro_rules! exported_to_top_level { @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ -error: missing documentation for macro +error: missing documentation for a macro --> $DIR/missing-doc-private-macro.rs:37:1 | LL | pub macro top_level_pub_macro { diff --git a/src/test/ui/macros/macro-stability-rpass.rs b/src/test/ui/macros/macro-stability-rpass.rs index a5f538ba6b3..2d02b95288d 100644 --- a/src/test/ui/macros/macro-stability-rpass.rs +++ b/src/test/ui/macros/macro-stability-rpass.rs @@ -1,7 +1,8 @@ // run-pass // aux-build:unstable-macros.rs -#![feature(unstable_macros, local_unstable)] +#![unstable(feature = "one_two_three_testing", issue = "none")] +#![feature(staged_api, unstable_macros, local_unstable)] #[macro_use] extern crate unstable_macros; diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index d358e9fb876..940eee7a788 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -122,6 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { }, hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 977e6d966e8..667cdd83025 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -118,6 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { }, hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) | hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 6bf216cec16..e97983a2e14 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -381,6 +381,13 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { let item_ty = cx.tcx.type_of(did); println!("function of type {:#?}", item_ty); }, + hir::ItemKind::Macro(ref macro_def) => { + if macro_def.macro_rules { + println!("macro introduced by `macro_rules!`"); + } else { + println!("macro introduced by `macro`"); + } + }, hir::ItemKind::Mod(..) => println!("module"), hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi), hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),