Skip to content

Commit 3d0b622

Browse files
committed
expand: Less path cloning during module loading
1 parent 5bdf81d commit 3d0b622

File tree

2 files changed

+51
-37
lines changed

2 files changed

+51
-37
lines changed

compiler/rustc_expand/src/expand.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::config::StripUnconfigured;
33
use crate::configure;
44
use crate::hygiene::SyntaxContext;
55
use crate::mbe::macro_rules::annotate_err_with_kind;
6-
use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
6+
use crate::module::{parse_external_mod, push_directory, DirectoryOwnership, ParsedExternalMod};
77
use crate::placeholders::{placeholder, PlaceholderExpander};
88

99
use rustc_ast as ast;
@@ -1277,28 +1277,36 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
12771277
})
12781278
}
12791279
ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
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 {
1280+
let (file_path, dir_path, dir_ownership) = match mod_kind {
12851281
ModKind::Loaded(_, Inline::Yes, _) => {
12861282
// Inline `mod foo { ... }`, but we still need to push directories.
1287-
let dir_path = push_directory(&self.cx.sess, ident, &attrs, dir);
1283+
let (dir_path, dir_ownership) = push_directory(
1284+
&self.cx.sess,
1285+
ident,
1286+
&attrs,
1287+
&self.cx.current_expansion.module,
1288+
self.cx.current_expansion.directory_ownership,
1289+
);
12881290
item.attrs = attrs;
1289-
(None, dir_path)
1291+
(None, dir_path, dir_ownership)
12901292
}
12911293
ModKind::Loaded(_, Inline::No, _) => {
12921294
panic!("`mod` item is loaded from a file for the second time")
12931295
}
12941296
ModKind::Unloaded => {
12951297
// We have an outline `mod foo;` so we need to parse the file.
1296-
let (items, inner_span, file_path, dir_path) = parse_external_mod(
1298+
let ParsedExternalMod {
1299+
items,
1300+
inner_span,
1301+
file_path,
1302+
dir_path,
1303+
dir_ownership,
1304+
} = parse_external_mod(
12971305
&self.cx.sess,
12981306
ident,
12991307
span,
1300-
&self.cx.current_expansion.module.file_path_stack,
1301-
dir,
1308+
&self.cx.current_expansion.module,
1309+
self.cx.current_expansion.directory_ownership,
13021310
&mut attrs,
13031311
);
13041312

@@ -1312,12 +1320,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13121320
item.attrs = krate.attrs;
13131321
// File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
13141322
item = configure!(self, item);
1315-
(Some(file_path), dir_path)
1323+
(Some(file_path), dir_path, dir_ownership)
13161324
}
13171325
};
13181326

13191327
// Set the module info before we flat map.
1320-
let mut module = self.cx.current_expansion.module.with_dir_path(path);
1328+
let mut module = self.cx.current_expansion.module.with_dir_path(dir_path);
13211329
module.mod_path.push(ident);
13221330
if let Some(file_path) = file_path {
13231331
module.file_path_stack.push(file_path);
@@ -1326,7 +1334,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13261334
let orig_module =
13271335
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
13281336
let orig_dir_ownership =
1329-
mem::replace(&mut self.cx.current_expansion.directory_ownership, ownership);
1337+
mem::replace(&mut self.cx.current_expansion.directory_ownership, dir_ownership);
13301338

13311339
let result = noop_flat_map_item(item, self);
13321340

compiler/rustc_expand/src/module.rs

+29-23
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::base::ModuleData;
12
use rustc_ast::ptr::P;
23
use rustc_ast::{token, Attribute, Item};
34
use rustc_errors::{struct_span_err, PResult};
@@ -9,12 +10,6 @@ use rustc_span::Span;
910

1011
use std::path::{self, Path, PathBuf};
1112

12-
#[derive(Clone)]
13-
pub struct Directory {
14-
pub path: PathBuf,
15-
pub ownership: DirectoryOwnership,
16-
}
17-
1813
#[derive(Copy, Clone)]
1914
pub enum DirectoryOwnership {
2015
Owned {
@@ -38,22 +33,30 @@ pub struct ModulePathSuccess {
3833
pub ownership: DirectoryOwnership,
3934
}
4035

36+
crate struct ParsedExternalMod {
37+
pub items: Vec<P<Item>>,
38+
pub inner_span: Span,
39+
pub file_path: PathBuf,
40+
pub dir_path: PathBuf,
41+
pub dir_ownership: DirectoryOwnership,
42+
}
43+
4144
crate fn parse_external_mod(
4245
sess: &Session,
4346
id: Ident,
4447
span: Span, // The span to blame on errors.
45-
file_path_stack: &[PathBuf],
46-
Directory { mut ownership, path }: Directory,
48+
module: &ModuleData,
49+
mut dir_ownership: DirectoryOwnership,
4750
attrs: &mut Vec<Attribute>,
48-
) -> (Vec<P<Item>>, Span, PathBuf, Directory) {
51+
) -> ParsedExternalMod {
4952
// We bail on the first error, but that error does not cause a fatal error... (1)
5053
let result: PResult<'_, _> = try {
5154
// Extract the file path and the new ownership.
52-
let mp = submod_path(sess, id, span, &attrs, ownership, &path)?;
53-
ownership = mp.ownership;
55+
let mp = submod_path(sess, id, span, &attrs, dir_ownership, &module.dir_path)?;
56+
dir_ownership = mp.ownership;
5457

5558
// Ensure file paths are acyclic.
56-
error_on_circular_module(&sess.parse_sess, span, &mp.path, file_path_stack)?;
59+
error_on_circular_module(&sess.parse_sess, span, &mp.path, &module.file_path_stack)?;
5760

5861
// Actually parse the external file as a module.
5962
let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
@@ -65,9 +68,9 @@ crate fn parse_external_mod(
6568
let (items, inner_span, file_path) = result.map_err(|mut err| err.emit()).unwrap_or_default();
6669

6770
// Extract the directory path for submodules of the module.
68-
let path = file_path.parent().unwrap_or(&file_path).to_owned();
71+
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
6972

70-
(items, inner_span, file_path, Directory { ownership, path })
73+
ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership }
7174
}
7275

7376
fn error_on_circular_module<'a>(
@@ -92,27 +95,30 @@ crate fn push_directory(
9295
sess: &Session,
9396
id: Ident,
9497
attrs: &[Attribute],
95-
Directory { mut ownership, mut path }: Directory,
96-
) -> Directory {
97-
if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
98-
path.push(&*filename.as_str());
99-
ownership = DirectoryOwnership::Owned { relative: None };
98+
module: &ModuleData,
99+
mut dir_ownership: DirectoryOwnership,
100+
) -> (PathBuf, DirectoryOwnership) {
101+
let mut dir_path = module.dir_path.clone();
102+
if let Some(file_path) = sess.first_attr_value_str_by_name(attrs, sym::path) {
103+
dir_path.push(&*file_path.as_str());
104+
dir_ownership = DirectoryOwnership::Owned { relative: None };
100105
} else {
101106
// We have to push on the current module name in the case of relative
102107
// paths in order to ensure that any additional module paths from inline
103108
// `mod x { ... }` come after the relative extension.
104109
//
105110
// For example, a `mod z { ... }` inside `x/y.rs` should set the current
106111
// directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
107-
if let DirectoryOwnership::Owned { relative } = &mut ownership {
112+
if let DirectoryOwnership::Owned { relative } = &mut dir_ownership {
108113
if let Some(ident) = relative.take() {
109114
// Remove the relative offset.
110-
path.push(&*ident.as_str());
115+
dir_path.push(&*ident.as_str());
111116
}
112117
}
113-
path.push(&*id.as_str());
118+
dir_path.push(&*id.as_str());
114119
}
115-
Directory { ownership, path }
120+
121+
(dir_path, dir_ownership)
116122
}
117123

118124
fn submod_path<'a>(

0 commit comments

Comments
 (0)