@@ -9,7 +9,7 @@ use rustc_hir::Node;
9
9
use rustc_middle:: middle:: privacy:: AccessLevel ;
10
10
use rustc_middle:: ty:: TyCtxt ;
11
11
use rustc_span;
12
- use rustc_span:: def_id:: LOCAL_CRATE ;
12
+ use rustc_span:: def_id:: { CRATE_DEF_ID , LOCAL_CRATE } ;
13
13
use rustc_span:: source_map:: Spanned ;
14
14
use rustc_span:: symbol:: { kw, sym, Symbol } ;
15
15
@@ -79,49 +79,23 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
79
79
& krate. module ( ) ,
80
80
self . cx . tcx . crate_name ( LOCAL_CRATE ) ,
81
81
) ;
82
- // Attach the crate's exported macros to the top-level module.
83
- // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
84
- // well (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by
85
- // moving them back to their correct locations.
86
- ' exported_macros: for def in krate. exported_macros ( ) {
87
- // The `def` of a macro in `exported_macros` should correspond to either:
88
- // - a `#[macro_export] macro_rules!` macro,
89
- // - a built-in `derive` (or attribute) macro such as the ones in `::core`,
90
- // - a `pub macro`.
91
- // Only the last two need to be fixed, thus:
92
- if def. ast . macro_rules {
93
- top_level_module. macros . push ( ( def, None ) ) ;
94
- continue ' exported_macros;
95
- }
96
- let tcx = self . cx . tcx ;
97
- // Note: this is not the same as `.parent_module()`. Indeed, the latter looks
98
- // for the closest module _ancestor_, which is not necessarily a direct parent
99
- // (since a direct parent isn't necessarily a module, c.f. #77828).
100
- let macro_parent_def_id = {
101
- use rustc_middle:: ty:: DefIdTree ;
102
- tcx. parent ( def. def_id . to_def_id ( ) ) . unwrap ( )
103
- } ;
104
- let macro_parent_path = tcx. def_path ( macro_parent_def_id) ;
105
- // HACK: rustdoc has no way to lookup `doctree::Module`s by their HirId. Instead,
106
- // lookup the module by its name, by looking at each path segment one at a time.
107
- let mut cur_mod = & mut top_level_module;
108
- for path_segment in macro_parent_path. data {
109
- // Path segments may refer to a module (in which case they belong to the type
110
- // namespace), which is _necessary_ for the macro to be accessible outside it
111
- // (no "associated macros" as of yet). Else we bail with an outer `continue`.
112
- let path_segment_ty_ns = match path_segment. data {
113
- rustc_hir:: definitions:: DefPathData :: TypeNs ( symbol) => symbol,
114
- _ => continue ' exported_macros,
115
- } ;
116
- // Descend into the child module that matches this path segment (if any).
117
- match cur_mod. mods . iter_mut ( ) . find ( |child| child. name == path_segment_ty_ns) {
118
- Some ( child_mod) => cur_mod = & mut * child_mod,
119
- None => continue ' exported_macros,
82
+
83
+ // `#[macro_export] macro_rules!` items are reexported at the top level of the
84
+ // crate, regardless of where they're defined. We want to document the
85
+ // top level rexport of the macro, not its original definition, since
86
+ // the rexport defines the path that a user will actually see. Accordingly,
87
+ // we add the rexport as an item here, and then skip over the original
88
+ // definition in `visit_item()` below.
89
+ for export in self . cx . tcx . module_exports ( CRATE_DEF_ID ) . unwrap_or ( & [ ] ) {
90
+ if let Res :: Def ( DefKind :: Macro ( _) , def_id) = export. res {
91
+ if let Some ( local_def_id) = def_id. as_local ( ) {
92
+ if self . cx . tcx . has_attr ( def_id, sym:: macro_export) {
93
+ let hir_id = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( local_def_id) ;
94
+ let item = self . cx . tcx . hir ( ) . expect_item ( hir_id) ;
95
+ top_level_module. items . push ( ( item, None ) ) ;
96
+ }
120
97
}
121
98
}
122
- let cur_mod_def_id = tcx. hir ( ) . local_def_id ( cur_mod. id ) . to_def_id ( ) ;
123
- assert_eq ! ( cur_mod_def_id, macro_parent_def_id) ;
124
- cur_mod. macros . push ( ( def, None ) ) ;
125
99
}
126
100
self . cx . cache . exact_paths = self . exact_paths ;
127
101
top_level_module
@@ -238,10 +212,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
238
212
self . inlining = prev;
239
213
true
240
214
}
241
- Node :: MacroDef ( def) if !glob => {
242
- om. macros . push ( ( def, renamed) ) ;
243
- true
244
- }
245
215
_ => false ,
246
216
} ;
247
217
self . view_item_stack . remove ( & res_hir_id) ;
@@ -257,7 +227,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
257
227
debug ! ( "visiting item {:?}" , item) ;
258
228
let name = renamed. unwrap_or ( item. ident . name ) ;
259
229
260
- if item. vis . node . is_pub ( ) {
230
+ let def_id = item. def_id . to_def_id ( ) ;
231
+ let is_pub = item. vis . node . is_pub ( ) || self . cx . tcx . has_attr ( def_id, sym:: macro_export) ;
232
+
233
+ if is_pub {
261
234
self . store_path ( item. def_id . to_def_id ( ) ) ;
262
235
}
263
236
@@ -269,7 +242,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
269
242
}
270
243
}
271
244
// If we're inlining, skip private items.
272
- _ if self . inlining && !item . vis . node . is_pub ( ) => { }
245
+ _ if self . inlining && !is_pub => { }
273
246
hir:: ItemKind :: GlobalAsm ( ..) => { }
274
247
hir:: ItemKind :: Use ( _, hir:: UseKind :: ListStem ) => { }
275
248
hir:: ItemKind :: Use ( ref path, kind) => {
@@ -285,7 +258,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
285
258
286
259
// If there was a private module in the current path then don't bother inlining
287
260
// anything as it will probably be stripped anyway.
288
- if item . vis . node . is_pub ( ) && self . inside_public_path {
261
+ if is_pub && self . inside_public_path {
289
262
let please_inline = attrs. iter ( ) . any ( |item| match item. meta_item_list ( ) {
290
263
Some ( ref list) if item. has_name ( sym:: doc) => {
291
264
list. iter ( ) . any ( |i| i. has_name ( sym:: inline) )
@@ -307,6 +280,26 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
307
280
308
281
om. items . push ( ( item, renamed) )
309
282
}
283
+ hir:: ItemKind :: Macro ( ref macro_def) => {
284
+ // `#[macro_export] macro_rules!` items are handled seperately in `visit()`,
285
+ // above, since they need to be documented at the module top level. Accordingly,
286
+ // we only want to handle macros if one of three conditions holds:
287
+ //
288
+ // 1. This macro was defined by `macro`, and thus isn't covered by the case
289
+ // above.
290
+ // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered
291
+ // by the case above.
292
+ // 3. We're inlining, since a reexport where inlining has been requested
293
+ // should be inlined even if it is also documented at the top level.
294
+
295
+ let def_id = item. def_id . to_def_id ( ) ;
296
+ let is_macro_2_0 = !macro_def. macro_rules ;
297
+ let nonexported = !self . cx . tcx . has_attr ( def_id, sym:: macro_export) ;
298
+
299
+ if is_macro_2_0 || nonexported || self . inlining {
300
+ om. items . push ( ( item, renamed) ) ;
301
+ }
302
+ }
310
303
hir:: ItemKind :: Mod ( ref m) => {
311
304
om. mods . push ( self . visit_mod_contents ( & item. vis , item. hir_id ( ) , m, name) ) ;
312
305
}
0 commit comments