@@ -95,6 +95,27 @@ impl<'a> Resolver<'a> {
95
95
}
96
96
}
97
97
98
+ /// Walks up the tree of definitions starting at `def_id`,
99
+ /// stopping at the first `DefKind::Mod` encountered
100
+ fn nearest_mod_parent ( & mut self , def_id : DefId ) -> Module < ' a > {
101
+ let def_key = self . cstore ( ) . def_key ( def_id) ;
102
+
103
+ let mut parent_id = DefId {
104
+ krate : def_id. krate ,
105
+ index : def_key. parent . expect ( "failed to get parent for module" ) ,
106
+ } ;
107
+ // The immediate parent may not be a module
108
+ // (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`)
109
+ // Walk up the tree until we hit a module or the crate root.
110
+ while parent_id. index != CRATE_DEF_INDEX
111
+ && self . cstore ( ) . def_kind ( parent_id) != DefKind :: Mod
112
+ {
113
+ let parent_def_key = self . cstore ( ) . def_key ( parent_id) ;
114
+ parent_id. index = parent_def_key. parent . expect ( "failed to get parent for module" ) ;
115
+ }
116
+ self . get_module ( parent_id)
117
+ }
118
+
98
119
crate fn get_module ( & mut self , def_id : DefId ) -> Module < ' a > {
99
120
// If this is a local module, it will be in `module_map`, no need to recalculate it.
100
121
if let Some ( def_id) = def_id. as_local ( ) {
@@ -116,11 +137,8 @@ impl<'a> Resolver<'a> {
116
137
. data
117
138
. get_opt_name ( )
118
139
. expect ( "given a DefId that wasn't a module" ) ;
119
- // This unwrap is safe since we know this isn't the root
120
- let parent = Some ( self . get_module ( DefId {
121
- index : def_key. parent . expect ( "failed to get parent for module" ) ,
122
- ..def_id
123
- } ) ) ;
140
+
141
+ let parent = Some ( self . nearest_mod_parent ( def_id) ) ;
124
142
( name, parent)
125
143
} ;
126
144
@@ -145,8 +163,24 @@ impl<'a> Resolver<'a> {
145
163
if let Some ( id) = def_id. as_local ( ) {
146
164
self . local_macro_def_scopes [ & id]
147
165
} else {
148
- let module_def_id = ty:: DefIdTree :: parent ( & * self , def_id) . unwrap ( ) ;
149
- self . get_module ( module_def_id)
166
+ // This is not entirely correct - a `macro_rules!` macro may occur
167
+ // inside a 'block' module:
168
+ //
169
+ // ```rust
170
+ // const _: () = {
171
+ // #[macro_export]
172
+ // macro_rules! my_macro {
173
+ // () => {};
174
+ // }
175
+ // `
176
+ // We don't record this information for external crates, so
177
+ // the module we compute here will be the closest 'mod' item
178
+ // (not necesssarily the actual parent of the `macro_rules!`
179
+ // macro). `macro_rules!` macros can't use def-site hygiene,
180
+ // so this hopefully won't be a problem.
181
+ //
182
+ // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508
183
+ self . nearest_mod_parent ( def_id)
150
184
}
151
185
}
152
186
0 commit comments