diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2021-02-21 16:32:38 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2021-03-14 18:10:29 +0300 |
| commit | a4cc3cae04525c7fd6edc8a4301a4034c82fdfad (patch) | |
| tree | 3b7942dd5f982fcc41cf3d88b2a6911204e2df32 /compiler/rustc_expand | |
| parent | 84c08f82b46986fcd5cbd1a637582bd1325fa970 (diff) | |
| download | rust-a4cc3cae04525c7fd6edc8a4301a4034c82fdfad.tar.gz rust-a4cc3cae04525c7fd6edc8a4301a4034c82fdfad.zip | |
expand: Resolve and expand inner attributes on out-of-line modules
Diffstat (limited to 'compiler/rustc_expand')
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/module.rs | 58 |
2 files changed, 52 insertions, 26 deletions
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index dd2eaa0f3d5..a1e5979f62d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1282,16 +1282,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let (file_path, dir_path, dir_ownership) = match mod_kind { ModKind::Loaded(_, inline, _) => { // Inline `mod foo { ... }`, but we still need to push directories. - assert!( - *inline == Inline::Yes, - "`mod` item is loaded from a file for the second time" - ); let (dir_path, dir_ownership) = mod_dir_path( &self.cx.sess, ident, &attrs, &self.cx.current_expansion.module, self.cx.current_expansion.dir_ownership, + *inline, ); item.attrs = attrs; (None, dir_path, dir_ownership) @@ -1322,10 +1319,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { item.attrs = attrs; if item.attrs.len() > old_attrs_len { // If we loaded an out-of-line module and added some inner attributes, - // then we need to re-configure it. - // FIXME: Attributes also need to be recollected - // for resolution and expansion. + // then we need to re-configure it and re-collect attributes for + // resolution and expansion. item = configure!(self, item); + + if let Some(attr) = self.take_first_attr(&mut item) { + return self + .collect_attr( + attr, + Annotatable::Item(item), + AstFragmentKind::Items, + ) + .make_items(); + } } (Some(file_path), dir_path, dir_ownership) } diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 2ec656d4895..c5ce0baaa8f 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,6 +1,6 @@ use crate::base::ModuleData; use rustc_ast::ptr::P; -use rustc_ast::{token, Attribute, Item}; +use rustc_ast::{token, Attribute, Inline, Item}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; @@ -83,29 +83,49 @@ crate fn mod_dir_path( attrs: &[Attribute], module: &ModuleData, mut dir_ownership: DirOwnership, + inline: Inline, ) -> (PathBuf, DirOwnership) { - if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) { - // For inline modules file path from `#[path]` is actually the directory path - // for historical reasons, so we don't pop the last segment here. - return (file_path, DirOwnership::Owned { relative: None }); - } + match inline { + Inline::Yes => { + if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) { + // For inline modules file path from `#[path]` is actually the directory path + // for historical reasons, so we don't pop the last segment here. + return (file_path, DirOwnership::Owned { relative: None }); + } - // We have to push on the current module name in the case of relative - // paths in order to ensure that any additional module paths from inline - // `mod x { ... }` come after the relative extension. - // - // For example, a `mod z { ... }` inside `x/y.rs` should set the current - // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. - let mut dir_path = module.dir_path.clone(); - if let DirOwnership::Owned { relative } = &mut dir_ownership { - if let Some(ident) = relative.take() { - // Remove the relative offset. + // We have to push on the current module name in the case of relative + // paths in order to ensure that any additional module paths from inline + // `mod x { ... }` come after the relative extension. + // + // For example, a `mod z { ... }` inside `x/y.rs` should set the current + // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. + let mut dir_path = module.dir_path.clone(); + if let DirOwnership::Owned { relative } = &mut dir_ownership { + if let Some(ident) = relative.take() { + // Remove the relative offset. + dir_path.push(&*ident.as_str()); + } + } dir_path.push(&*ident.as_str()); + + (dir_path, dir_ownership) } - } - dir_path.push(&*ident.as_str()); + Inline::No => { + // FIXME: This is a subset of `parse_external_mod` without actual parsing, + // check whether the logic for unloaded, loaded and inline modules can be unified. + let file_path = mod_file_path(sess, ident, &attrs, &module.dir_path, dir_ownership) + .map(|mp| { + dir_ownership = mp.dir_ownership; + mp.file_path + }) + .unwrap_or_default(); + + // Extract the directory path for submodules of the module. + let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); - (dir_path, dir_ownership) + (dir_path, dir_ownership) + } + } } fn mod_file_path<'a>( |
