Skip to content

Commit 569d29d

Browse files
authored
Rollup merge of rust-lang#77984 - Aaron1011:fix/macro-mod-weird-parent, r=petrochenkov
Compute proper module parent during resolution Fixes rust-lang#75982 The direct parent of a module may not be a module (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`). To find the parent of a module for purposes of resolution, we need to walk up the tree until we hit a module or a crate root.
2 parents 3e0dd24 + 283053a commit 569d29d

File tree

5 files changed

+73
-7
lines changed

5 files changed

+73
-7
lines changed

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_ast as ast;
88
use rustc_ast::expand::allocator::AllocatorKind;
99
use rustc_data_structures::svh::Svh;
1010
use rustc_hir as hir;
11+
use rustc_hir::def::DefKind;
1112
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
1213
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
1314
use rustc_middle::hir::exports::Export;
@@ -487,6 +488,10 @@ impl CrateStore for CStore {
487488
self.get_crate_data(def.krate).def_key(def.index)
488489
}
489490

491+
fn def_kind(&self, def: DefId) -> DefKind {
492+
self.get_crate_data(def.krate).def_kind(def.index)
493+
}
494+
490495
fn def_path(&self, def: DefId) -> DefPath {
491496
self.get_crate_data(def.krate).def_path(def.index)
492497
}

Diff for: compiler/rustc_middle/src/middle/cstore.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_ast as ast;
88
use rustc_ast::expand::allocator::AllocatorKind;
99
use rustc_data_structures::svh::Svh;
1010
use rustc_data_structures::sync::{self, MetadataRef};
11+
use rustc_hir::def::DefKind;
1112
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
1213
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
1314
use rustc_macros::HashStable;
@@ -185,6 +186,7 @@ pub trait CrateStore {
185186

186187
// resolve
187188
fn def_key(&self, def: DefId) -> DefKey;
189+
fn def_kind(&self, def: DefId) -> DefKind;
188190
fn def_path(&self, def: DefId) -> DefPath;
189191
fn def_path_hash(&self, def: DefId) -> DefPathHash;
190192
fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>;

Diff for: compiler/rustc_resolve/src/build_reduced_graph.rs

+41-7
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ impl<'a> Resolver<'a> {
9595
}
9696
}
9797

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+
98119
crate fn get_module(&mut self, def_id: DefId) -> Module<'a> {
99120
// If this is a local module, it will be in `module_map`, no need to recalculate it.
100121
if let Some(def_id) = def_id.as_local() {
@@ -116,11 +137,8 @@ impl<'a> Resolver<'a> {
116137
.data
117138
.get_opt_name()
118139
.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));
124142
(name, parent)
125143
};
126144

@@ -145,8 +163,24 @@ impl<'a> Resolver<'a> {
145163
if let Some(id) = def_id.as_local() {
146164
self.local_macro_def_scopes[&id]
147165
} 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)
150184
}
151185
}
152186

Diff for: src/test/ui/macros/auxiliary/issue-75982.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const _: () = {
2+
#[macro_export]
3+
macro_rules! first_macro {
4+
() => {}
5+
}
6+
mod foo {
7+
#[macro_export]
8+
macro_rules! second_macro {
9+
() => {}
10+
}
11+
}
12+
};
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// aux-build:issue-75982.rs
2+
// check-pass
3+
4+
// Regression test for issue #75982
5+
// Tests that don't ICE when invoking a foreign macro
6+
// that occurs inside a module with a weird parent.
7+
8+
extern crate issue_75982;
9+
10+
fn main() {
11+
issue_75982::first_macro!();
12+
issue_75982::second_macro!();
13+
}

0 commit comments

Comments
 (0)