@@ -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 (
0 commit comments