Skip to content

Commit 0bee802

Browse files
Rustdoc: Fix macros 2.0 and built-in derives being shown at the wrong path.
Fixes #74355 The issue with the built-in derives may be related to: #55482 (comment)
1 parent 8fec6c7 commit 0bee802

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/librustdoc/visit_ast.rs

+51-5
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,66 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
6161
}
6262

6363
crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
64-
let mut module = self.visit_mod_contents(
64+
let mut top_level_module = self.visit_mod_contents(
6565
krate.item.span,
6666
&Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public },
6767
hir::CRATE_HIR_ID,
6868
&krate.item.module,
6969
None,
7070
);
71-
// Attach the crate's exported macros to the top-level module:
72-
module.macros.extend(krate.exported_macros.iter().map(|def| (def, None)));
73-
module.is_crate = true;
71+
top_level_module.is_crate = true;
72+
// Attach the crate's exported macros to the top-level module.
73+
// In the case of macros 2.0 (`pub macro`), and for built-in `derive`s as well
74+
// (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by
75+
// moving them back to their correct locations.
76+
krate.exported_macros.iter().for_each(|def| {
77+
macro_rules! try_some {($($body:tt)*) => ({
78+
fn fn_once<R, F: FnOnce() -> R> (f: F) -> F { f }
79+
fn_once(|| Some({ $($body)* }))()
80+
})}
81+
// In the case of dummy items, some of the following operations may fail. We propagate
82+
// that within a `?`-capturing block, so as to fallback to the basic behavior.
83+
let containing_module_of_def = try_some! {
84+
// The `def` of a macro in `exported_macros` should correspond to either:
85+
// - a `#[macro-export] macro_rules!` macro,
86+
// - a built-in `derive` macro such as the ones in `::core`,
87+
// - a `pub macro`.
88+
// Only the last two need to be fixed, thus:
89+
if def.ast.macro_rules {
90+
return None;
91+
}
92+
let macro_parent_module = self.cx.tcx.def_path({
93+
use rustc_middle::ty::DefIdTree;
94+
self.cx
95+
.tcx
96+
/* Because of #77828 we cannot do the simpler:
97+
.parent_module(def.hir_id).to_def_id()
98+
// and instead have to do: */
99+
.parent(self.cx.tcx.hir().local_def_id(def.hir_id).to_def_id())?
100+
});
101+
let mut cur_mod = &mut top_level_module;
102+
for path_segment in macro_parent_module.data {
103+
let path_segment = path_segment.to_string();
104+
cur_mod = cur_mod.mods.iter_mut().find(|module| {
105+
matches!(
106+
module.name, Some(symbol)
107+
if symbol.with(|mod_name| mod_name == path_segment)
108+
)
109+
})?;
110+
}
111+
cur_mod
112+
};
113+
if let Some(module) = containing_module_of_def {
114+
&mut module.macros
115+
} else {
116+
&mut top_level_module.macros
117+
}
118+
.push(self.visit_local_macro(def, None));
119+
});
74120

75121
self.cx.renderinfo.get_mut().exact_paths = self.exact_paths;
76122

77-
module
123+
top_level_module
78124
}
79125

80126
fn visit_mod_contents(
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! See issue #74355
2+
#![crate_name = "krate"]
3+
#![feature(decl_macro)]
4+
5+
// @has krate/some_module/macro.my_macro.html
6+
pub mod some_module {
7+
//
8+
pub macro my_macro() {}
9+
}

0 commit comments

Comments
 (0)