Skip to content

Commit b1fe746

Browse files
authored
Rollup merge of rust-lang#141411 - lolbinarycat:rustdoc-link-proc-macro-91274, r=GuillaumeGomez
rustdoc: linking to a local proc macro no longer warns fixes rust-lang#91274 tried to keep the fix general in case we ever have any other kind of item that occupies multiple namespaces simultaniously.
2 parents 784e30f + 871327e commit b1fe746

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_resolve::rustdoc::{
2222
MalformedGenerics, has_primitive_or_keyword_docs, prepare_to_doc_link_resolution,
2323
source_span_for_markdown_range, strip_generics_from_path,
2424
};
25+
use rustc_session::config::CrateType;
2526
use rustc_session::lint::Lint;
2627
use rustc_span::BytePos;
2728
use rustc_span::hygiene::MacroKind;
@@ -1169,7 +1170,6 @@ impl LinkCollector<'_, '_> {
11691170
#[allow(rustc::potential_query_instability)]
11701171
pub(crate) fn resolve_ambiguities(&mut self) {
11711172
let mut ambiguous_links = mem::take(&mut self.ambiguous_links);
1172-
11731173
for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() {
11741174
for info in info_items {
11751175
info.resolved.retain(|(res, _)| match res {
@@ -2227,15 +2227,35 @@ fn ambiguity_error(
22272227
emit_error: bool,
22282228
) -> bool {
22292229
let mut descrs = FxHashSet::default();
2230-
let kinds = candidates
2230+
// proc macro can exist in multiple namespaces at once, so we need to compare `DefIds`
2231+
// to remove the candidate in the fn namespace.
2232+
let mut possible_proc_macro_id = None;
2233+
let is_proc_macro_crate = cx.tcx.crate_types() == &[CrateType::ProcMacro];
2234+
let mut kinds = candidates
22312235
.iter()
2232-
.map(
2233-
|(res, def_id)| {
2234-
if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res }
2235-
},
2236-
)
2237-
.filter(|res| descrs.insert(res.descr()))
2236+
.map(|(res, def_id)| {
2237+
let r =
2238+
if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res };
2239+
if is_proc_macro_crate && let Res::Def(DefKind::Macro(_), id) = r {
2240+
possible_proc_macro_id = Some(id);
2241+
}
2242+
r
2243+
})
22382244
.collect::<Vec<_>>();
2245+
// In order to properly dedup proc macros, we have to do it in two passes:
2246+
// 1. Completing the full traversal to find the possible duplicate in the macro namespace,
2247+
// 2. Another full traversal to eliminate the candidate in the fn namespace.
2248+
//
2249+
// Thus, we have to do an iteration after collection is finished.
2250+
//
2251+
// As an optimization, we only deduplicate if we're in a proc-macro crate,
2252+
// and only if we already found something that looks like a proc macro.
2253+
if is_proc_macro_crate && let Some(macro_id) = possible_proc_macro_id {
2254+
kinds.retain(|res| !matches!(res, Res::Def(DefKind::Fn, fn_id) if macro_id == *fn_id));
2255+
}
2256+
2257+
kinds.retain(|res| descrs.insert(res.descr()));
2258+
22392259
if descrs.len() == 1 {
22402260
// There is no way for users to disambiguate at this point, so better return the first
22412261
// candidate and not show a warning.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: --crate-type=proc-macro --document-private-items
2+
#![deny(rustdoc::broken_intra_doc_links)]
3+
4+
//! Link to [`m`].
5+
//~^ ERROR `m` is both a module and a macro
6+
7+
// test a further edge case related to https://github.com/rust-lang/rust/issues/91274
8+
9+
// we need to make sure that when there is actually an ambiguity
10+
// in a proc-macro crate, we print out a sensible error.
11+
// because proc macro crates can't normally export modules,
12+
// this can only happen in --document-private-items mode.
13+
14+
extern crate proc_macro;
15+
16+
mod m {}
17+
18+
#[proc_macro]
19+
pub fn m(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
20+
input
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: `m` is both a module and a macro
2+
--> $DIR/bad-link-to-proc-macro.rs:4:15
3+
|
4+
LL | //! Link to [`m`].
5+
| ^ ambiguous link
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/bad-link-to-proc-macro.rs:2:9
9+
|
10+
LL | #![deny(rustdoc::broken_intra_doc_links)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
help: to link to the module, prefix with `mod@`
13+
|
14+
LL | //! Link to [`mod@m`].
15+
| ++++
16+
help: to link to the macro, add an exclamation mark
17+
|
18+
LL | //! Link to [`m!`].
19+
| +
20+
21+
error: aborting due to 1 previous error
22+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ compile-flags: --crate-type=proc-macro
2+
//@ has 'foo/index.html' '//a[@href="macro.my_macro.html"]' 'my_macro'
3+
//! Link to [`my_macro`].
4+
#![crate_name = "foo"]
5+
6+
// regression test for https://github.com/rust-lang/rust/issues/91274
7+
8+
extern crate proc_macro;
9+
10+
#[proc_macro]
11+
pub fn my_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12+
input
13+
}

0 commit comments

Comments
 (0)