@@ -22,6 +22,7 @@ use rustc_resolve::rustdoc::{
22
22
MalformedGenerics , has_primitive_or_keyword_docs, prepare_to_doc_link_resolution,
23
23
source_span_for_markdown_range, strip_generics_from_path,
24
24
} ;
25
+ use rustc_session:: config:: CrateType ;
25
26
use rustc_session:: lint:: Lint ;
26
27
use rustc_span:: BytePos ;
27
28
use rustc_span:: hygiene:: MacroKind ;
@@ -1169,7 +1170,6 @@ impl LinkCollector<'_, '_> {
1169
1170
#[ allow( rustc:: potential_query_instability) ]
1170
1171
pub ( crate ) fn resolve_ambiguities ( & mut self ) {
1171
1172
let mut ambiguous_links = mem:: take ( & mut self . ambiguous_links ) ;
1172
-
1173
1173
for ( ( item_id, path_str) , info_items) in ambiguous_links. iter_mut ( ) {
1174
1174
for info in info_items {
1175
1175
info. resolved . retain ( |( res, _) | match res {
@@ -2227,15 +2227,35 @@ fn ambiguity_error(
2227
2227
emit_error : bool ,
2228
2228
) -> bool {
2229
2229
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
2231
2235
. 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
+ } )
2238
2244
. 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
+
2239
2259
if descrs. len ( ) == 1 {
2240
2260
// There is no way for users to disambiguate at this point, so better return the first
2241
2261
// candidate and not show a warning.
0 commit comments