Skip to content

Commit 39052c5

Browse files
committed
expand: Move module file path stack from global session to expansion data
Also don't push the paths on the stack directly in `fn parse_external_mod`, return them instead.
1 parent bc18eb4 commit 39052c5

File tree

7 files changed

+80
-70
lines changed

7 files changed

+80
-70
lines changed

compiler/rustc_builtin_macros/src/source_util.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub fn expand_include<'cx>(
101101
None => return DummyResult::any(sp),
102102
};
103103
// The file will be added to the code map by the parser
104-
let mut file = match cx.resolve_path(file, sp) {
104+
let file = match cx.resolve_path(file, sp) {
105105
Ok(f) => f,
106106
Err(mut err) => {
107107
err.emit();
@@ -114,10 +114,9 @@ pub fn expand_include<'cx>(
114114
// then the path of `bar.rs` should be relative to the directory of `file`.
115115
// See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
116116
// `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained.
117-
file.pop();
117+
let dir_path = file.parent().unwrap_or(&file).to_owned();
118+
cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
118119
cx.current_expansion.directory_ownership = DirectoryOwnership::Owned { relative: None };
119-
let mod_path = cx.current_expansion.module.mod_path.clone();
120-
cx.current_expansion.module = Rc::new(ModuleData { mod_path, directory: file });
121120

122121
struct ExpandResult<'a> {
123122
p: Parser<'a>,

compiler/rustc_expand/src/base.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -894,10 +894,26 @@ pub trait ResolverExpand {
894894
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
895895
}
896896

897-
#[derive(Clone)]
897+
#[derive(Clone, Default)]
898898
pub struct ModuleData {
899+
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
899900
pub mod_path: Vec<Ident>,
900-
pub directory: PathBuf,
901+
/// Stack of paths to files loaded by out-of-line module items,
902+
/// used to detect and report recursive module inclusions.
903+
pub file_path_stack: Vec<PathBuf>,
904+
/// Directory to search child module files in,
905+
/// often (but not necessarily) the parent of the top file path on the `file_path_stack`.
906+
pub dir_path: PathBuf,
907+
}
908+
909+
impl ModuleData {
910+
pub fn with_dir_path(&self, dir_path: PathBuf) -> ModuleData {
911+
ModuleData {
912+
mod_path: self.mod_path.clone(),
913+
file_path_stack: self.file_path_stack.clone(),
914+
dir_path,
915+
}
916+
}
901917
}
902918

903919
#[derive(Clone)]
@@ -946,7 +962,7 @@ impl<'a> ExtCtxt<'a> {
946962
current_expansion: ExpansionData {
947963
id: ExpnId::root(),
948964
depth: 0,
949-
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
965+
module: Default::default(),
950966
directory_ownership: DirectoryOwnership::Owned { relative: None },
951967
prior_type_ascription: None,
952968
},

compiler/rustc_expand/src/expand.rs

+36-35
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
355355
// FIXME: Avoid visiting the crate as a `Mod` item,
356356
// make crate a first class expansion target instead.
357357
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
358-
let mut module = ModuleData {
359-
mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
360-
directory: match self.cx.source_map().span_to_unmapped_path(krate.span) {
361-
FileName::Real(name) => name.into_local_path(),
362-
other => PathBuf::from(other.to_string()),
363-
},
358+
let file_path = match self.cx.source_map().span_to_unmapped_path(krate.span) {
359+
FileName::Real(name) => name.into_local_path(),
360+
other => PathBuf::from(other.to_string()),
364361
};
365-
module.directory.pop();
366-
self.cx.root_path = module.directory.clone();
367-
self.cx.current_expansion.module = Rc::new(module);
362+
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
363+
self.cx.root_path = dir_path.clone();
364+
self.cx.current_expansion.module = Rc::new(ModuleData {
365+
mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
366+
file_path_stack: vec![file_path],
367+
dir_path,
368+
});
368369

369370
let krate_item = AstFragment::Items(smallvec![P(ast::Item {
370371
attrs: krate.attrs,
@@ -1276,25 +1277,30 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
12761277
})
12771278
}
12781279
ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
1279-
let sess = &self.cx.sess.parse_sess;
1280-
let orig_ownership = self.cx.current_expansion.directory_ownership;
1281-
let mut module = (*self.cx.current_expansion.module).clone();
1282-
1283-
let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
1284-
let dir = Directory { ownership: orig_ownership, path: module.directory };
1285-
let Directory { ownership, path } = match mod_kind {
1280+
let dir = Directory {
1281+
ownership: self.cx.current_expansion.directory_ownership,
1282+
path: self.cx.current_expansion.module.dir_path.clone(),
1283+
};
1284+
let (file_path, Directory { ownership, path }) = match mod_kind {
12861285
ModKind::Loaded(_, Inline::Yes, _) => {
12871286
// Inline `mod foo { ... }`, but we still need to push directories.
1287+
let dir_path = push_directory(&self.cx.sess, ident, &attrs, dir);
12881288
item.attrs = attrs;
1289-
push_directory(&self.cx.sess, ident, &item.attrs, dir)
1289+
(None, dir_path)
12901290
}
12911291
ModKind::Loaded(_, Inline::No, _) => {
12921292
panic!("`mod` item is loaded from a file for the second time")
12931293
}
12941294
ModKind::Unloaded => {
12951295
// We have an outline `mod foo;` so we need to parse the file.
1296-
let (items, inner_span, dir) =
1297-
parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
1296+
let (items, inner_span, file_path, dir_path) = parse_external_mod(
1297+
&self.cx.sess,
1298+
ident,
1299+
span,
1300+
&self.cx.current_expansion.module.file_path_stack,
1301+
dir,
1302+
&mut attrs,
1303+
);
12981304

12991305
let krate =
13001306
ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] };
@@ -1305,34 +1311,29 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13051311
*mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
13061312
item.attrs = krate.attrs;
13071313
// File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
1308-
item = match self.configure(item) {
1309-
Some(node) => node,
1310-
None => {
1311-
if *pushed {
1312-
sess.included_mod_stack.borrow_mut().pop();
1313-
}
1314-
return Default::default();
1315-
}
1316-
};
1317-
dir
1314+
item = configure!(self, item);
1315+
(Some(file_path), dir_path)
13181316
}
13191317
};
13201318

13211319
// Set the module info before we flat map.
1322-
self.cx.current_expansion.directory_ownership = ownership;
1323-
module.directory = path;
1320+
let mut module = self.cx.current_expansion.module.with_dir_path(path);
13241321
module.mod_path.push(ident);
1322+
if let Some(file_path) = file_path {
1323+
module.file_path_stack.push(file_path);
1324+
}
1325+
13251326
let orig_module =
13261327
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
1328+
let orig_dir_ownership =
1329+
mem::replace(&mut self.cx.current_expansion.directory_ownership, ownership);
13271330

13281331
let result = noop_flat_map_item(item, self);
13291332

13301333
// Restore the module info.
1334+
self.cx.current_expansion.directory_ownership = orig_dir_ownership;
13311335
self.cx.current_expansion.module = orig_module;
1332-
self.cx.current_expansion.directory_ownership = orig_ownership;
1333-
if *pushed {
1334-
sess.included_mod_stack.borrow_mut().pop();
1335-
}
1336+
13361337
result
13371338
}
13381339
_ => {

compiler/rustc_expand/src/module.rs

+9-13
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,27 @@ crate fn parse_external_mod(
4242
sess: &Session,
4343
id: Ident,
4444
span: Span, // The span to blame on errors.
45+
file_path_stack: &[PathBuf],
4546
Directory { mut ownership, path }: Directory,
4647
attrs: &mut Vec<Attribute>,
47-
pop_mod_stack: &mut bool,
48-
) -> (Vec<P<Item>>, Span, Directory) {
48+
) -> (Vec<P<Item>>, Span, PathBuf, Directory) {
4949
// We bail on the first error, but that error does not cause a fatal error... (1)
5050
let result: PResult<'_, _> = try {
5151
// Extract the file path and the new ownership.
5252
let mp = submod_path(sess, id, span, &attrs, ownership, &path)?;
5353
ownership = mp.ownership;
5454

5555
// Ensure file paths are acyclic.
56-
let mut included_mod_stack = sess.parse_sess.included_mod_stack.borrow_mut();
57-
error_on_circular_module(&sess.parse_sess, span, &mp.path, &included_mod_stack)?;
58-
included_mod_stack.push(mp.path.clone());
59-
*pop_mod_stack = true; // We have pushed, so notify caller.
60-
drop(included_mod_stack);
56+
error_on_circular_module(&sess.parse_sess, span, &mp.path, file_path_stack)?;
6157

6258
// Actually parse the external file as a module.
6359
let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
6460
let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
6561
attrs.append(&mut inner_attrs);
66-
(items, inner_span)
62+
(items, inner_span, mp.path)
6763
};
6864
// (1) ...instead, we return a dummy module.
69-
let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default();
65+
let (items, inner_span, file_path) = result.map_err(|mut err| err.emit()).unwrap_or_default();
7066

7167
// Extract the directory path for submodules of the module.
7268
let path = sess.source_map().span_to_unmapped_path(inner_span);
@@ -76,18 +72,18 @@ crate fn parse_external_mod(
7672
};
7773
path.pop();
7874

79-
(items, inner_span, Directory { ownership, path })
75+
(items, inner_span, file_path, Directory { ownership, path })
8076
}
8177

8278
fn error_on_circular_module<'a>(
8379
sess: &'a ParseSess,
8480
span: Span,
8581
path: &Path,
86-
included_mod_stack: &[PathBuf],
82+
file_path_stack: &[PathBuf],
8783
) -> PResult<'a, ()> {
88-
if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
84+
if let Some(i) = file_path_stack.iter().position(|p| *p == path) {
8985
let mut err = String::from("circular modules: ");
90-
for p in &included_mod_stack[i..] {
86+
for p in &file_path_stack[i..] {
9187
err.push_str(&p.to_string_lossy());
9288
err.push_str(" -> ");
9389
}

compiler/rustc_session/src/parse.rs

-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use rustc_span::hygiene::ExpnId;
1313
use rustc_span::source_map::{FilePathMapping, SourceMap};
1414
use rustc_span::{MultiSpan, Span, Symbol};
1515

16-
use std::path::PathBuf;
1716
use std::str;
1817

1918
/// The set of keys (and, optionally, values) that define the compilation
@@ -122,8 +121,6 @@ pub struct ParseSess {
122121
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
123122
/// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
124123
pub raw_identifier_spans: Lock<Vec<Span>>,
125-
/// Used to determine and report recursive module inclusions.
126-
pub included_mod_stack: Lock<Vec<PathBuf>>,
127124
source_map: Lrc<SourceMap>,
128125
pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
129126
/// Contains the spans of block expressions that could have been incomplete based on the
@@ -157,7 +154,6 @@ impl ParseSess {
157154
edition: ExpnId::root().expn_data().edition,
158155
missing_fragment_specifiers: Default::default(),
159156
raw_identifier_spans: Lock::new(Vec::new()),
160-
included_mod_stack: Lock::new(vec![]),
161157
source_map,
162158
buffered_lints: Lock::new(vec![]),
163159
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
+4-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
// error-pattern: circular modules
2+
13
#[path = "circular_modules_hello.rs"]
2-
mod circular_modules_hello; //~ ERROR: circular modules
4+
mod circular_modules_hello;
35

46
pub fn hi_str() -> String {
57
"Hi!".to_string()
68
}
79

810
fn main() {
9-
circular_modules_hello::say_hello(); //~ ERROR cannot find function `say_hello` in module
11+
circular_modules_hello::say_hello();
1012
}

src/test/ui/parser/circular_modules_main.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs
2-
--> $DIR/circular_modules_main.rs:2:1
1+
error: circular modules: $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs
2+
--> $DIR/circular_modules_hello.rs:4:1
33
|
4-
LL | mod circular_modules_hello;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | mod circular_modules_main;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error[E0425]: cannot find function `say_hello` in module `circular_modules_hello`
8-
--> $DIR/circular_modules_main.rs:9:29
7+
error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
8+
--> $DIR/circular_modules_hello.rs:7:43
99
|
10-
LL | circular_modules_hello::say_hello();
11-
| ^^^^^^^^^ not found in `circular_modules_hello`
10+
LL | println!("{}", circular_modules_main::hi_str());
11+
| ^^^^^^ not found in `circular_modules_main`
1212
|
1313
help: consider importing this function
1414
|
15-
LL | use circular_modules_hello::say_hello;
15+
LL | use hi_str;
1616
|
1717

1818
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)