@@ -61,20 +61,66 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
61
61
}
62
62
63
63
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 (
65
65
krate. item . span ,
66
66
& Spanned { span : rustc_span:: DUMMY_SP , node : hir:: VisibilityKind :: Public } ,
67
67
hir:: CRATE_HIR_ID ,
68
68
& krate. item . module ,
69
69
None ,
70
70
) ;
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
+ } ) ;
74
120
75
121
self . cx . renderinfo . get_mut ( ) . exact_paths = self . exact_paths ;
76
122
77
- module
123
+ top_level_module
78
124
}
79
125
80
126
fn visit_mod_contents (
0 commit comments