From a4cc3cae04525c7fd6edc8a4301a4034c82fdfad Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 21 Feb 2021 16:32:38 +0300 Subject: expand: Resolve and expand inner attributes on out-of-line modules --- compiler/rustc_expand/src/expand.rs | 20 ++++++++----- compiler/rustc_expand/src/module.rs | 58 +++++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 26 deletions(-) (limited to 'compiler/rustc_expand') 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>( -- cgit 1.4.1-3-g733a5