about summary refs log tree commit diff
path: root/compiler/rustc_expand
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-02-21 16:32:38 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-03-14 18:10:29 +0300
commita4cc3cae04525c7fd6edc8a4301a4034c82fdfad (patch)
tree3b7942dd5f982fcc41cf3d88b2a6911204e2df32 /compiler/rustc_expand
parent84c08f82b46986fcd5cbd1a637582bd1325fa970 (diff)
downloadrust-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.rs20
-rw-r--r--compiler/rustc_expand/src/module.rs58
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>(