diff options
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 10 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_intra_doc_links/early.rs | 23 | ||||
| -rw-r--r-- | src/test/rustdoc-ui/intra-doc/macro-rules-error.rs | 27 | ||||
| -rw-r--r-- | src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr | 22 | ||||
| -rw-r--r-- | src/test/rustdoc-ui/intra-doc/macro-rules.rs | 15 |
6 files changed, 99 insertions, 4 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 650a0dc82ce..f1e07de77f8 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1267,13 +1267,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.insert_unused_macro(ident, def_id, item.id); } self.r.visibilities.insert(def_id, vis); - self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( + let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding { parent_macro_rules_scope: parent_scope.macro_rules, binding, ident, }), - )) + )); + self.r.macro_rules_scopes.insert(def_id, scope); + scope } else { let module = parent_scope.module; let vis = match item.kind { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6142283e2e1..c917ea5a08f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -145,7 +145,7 @@ enum ScopeSet<'a> { pub struct ParentScope<'a> { pub module: Module<'a>, expansion: LocalExpnId, - macro_rules: MacroRulesScopeRef<'a>, + pub macro_rules: MacroRulesScopeRef<'a>, derives: &'a [ast::Path], } @@ -990,6 +990,8 @@ pub struct Resolver<'a> { /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'a>>, + /// `macro_rules` scopes produced by `macro_rules` item definitions. + macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'a>>, /// Helper attributes that are in scope for the given expansion. helper_attrs: FxHashMap<LocalExpnId, Vec<Ident>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute @@ -1361,6 +1363,7 @@ impl<'a> Resolver<'a> { non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())), invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), + macro_rules_scopes: Default::default(), helper_attrs: Default::default(), derive_data: Default::default(), local_macro_def_scopes: FxHashMap::default(), @@ -1919,6 +1922,11 @@ impl<'a> Resolver<'a> { } } + /// For rustdoc. + pub fn macro_rules_scope(&self, def_id: LocalDefId) -> MacroRulesScopeRef<'a> { + *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item") + } + /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. #[inline] pub fn opt_span(&self, def_id: DefId) -> Option<Span> { diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 974ef7a537a..3858c1cb056 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{DefIdTree, Visibility}; use rustc_resolve::{ParentScope, Resolver}; use rustc_session::config::Externs; use rustc_session::Session; +use rustc_span::symbol::sym; use rustc_span::{Symbol, SyntaxContext}; use std::collections::hash_map::Entry; @@ -216,6 +217,8 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { ns: Namespace, parent_scope: &ParentScope<'ra>, ) -> bool { + // FIXME: This caching may be incorrect in case of multiple `macro_rules` + // items with the same name in the same module. self.doc_link_resolutions .entry((Symbol::intern(path_str), ns, parent_scope.module.def_id())) .or_insert_with_key(|(path, ns, _)| { @@ -307,18 +310,30 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> { let module_def_id = self.resolver.local_def_id(item.id).to_def_id(); let module = self.resolver.expect_module(module_def_id); let old_module = mem::replace(&mut self.parent_scope.module, module); + let old_macro_rules = self.parent_scope.macro_rules; self.resolve_doc_links_local(&item.attrs); // Inner attribute scope self.process_module_children_or_reexports(module_def_id); visit::walk_item(self, item); + if item + .attrs + .iter() + .all(|attr| !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape)) + { + self.parent_scope.macro_rules = old_macro_rules; + } self.parent_scope.module = old_module; } else { - match item.kind { + match &item.kind { ItemKind::Trait(..) => { self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id()); } ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => { self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id()); } + ItemKind::MacroDef(macro_def) if macro_def.macro_rules => { + self.parent_scope.macro_rules = + self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id)); + } _ => {} } visit::walk_item(self, item); @@ -345,6 +360,12 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> { visit::walk_field_def(self, field) } + fn visit_block(&mut self, block: &ast::Block) { + let old_macro_rules = self.parent_scope.macro_rules; + visit::walk_block(self, block); + self.parent_scope.macro_rules = old_macro_rules; + } + // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters), // then this will have to implement other visitor methods too. } diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs new file mode 100644 index 00000000000..84d63c20aa8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs @@ -0,0 +1,27 @@ +// `macro_rules` scopes are respected during doc link resolution. + +// compile-flags: --document-private-items + +#![deny(rustdoc::broken_intra_doc_links)] + +mod no_escape { + macro_rules! before_but_limited_to_module { + () => {}; + } +} + +/// [before_but_limited_to_module] FIXME: This error should be reported +// ERROR unresolved link to `before_but_limited_to_module` +/// [after] FIXME: This error should be reported +// ERROR unresolved link to `after` +/// [str] FIXME: This error shouldn not be reported +//~^ ERROR `str` is both a builtin type and a macro +fn check() {} + +macro_rules! after { + () => {}; +} + +macro_rules! str { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr new file mode 100644 index 00000000000..4b984f4f6c0 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr @@ -0,0 +1,22 @@ +error: `str` is both a builtin type and a macro + --> $DIR/macro-rules-error.rs:17:6 + | +LL | /// [str] FIXME: This error shouldn not be reported + | ^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/macro-rules-error.rs:5:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` + | +LL | /// [prim@str] FIXME: This error shouldn not be reported + | +++++ +help: to link to the macro, add an exclamation mark + | +LL | /// [str!] FIXME: This error shouldn not be reported + | + + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules.rs b/src/test/rustdoc-ui/intra-doc/macro-rules.rs index a14e4bdf1d7..3aeb370ef6d 100644 --- a/src/test/rustdoc-ui/intra-doc/macro-rules.rs +++ b/src/test/rustdoc-ui/intra-doc/macro-rules.rs @@ -7,3 +7,18 @@ macro_rules! foo { /// [foo!] pub fn baz() {} + +#[macro_use] +mod macros { + macro_rules! escaping { + () => {}; + } +} + +pub mod inner { + /// [foo!] + /// [escaping] + pub fn baz() { + foo!(); + } +} |
