about summary refs log tree commit diff
path: root/compiler
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
parent84c08f82b46986fcd5cbd1a637582bd1325fa970 (diff)
downloadrust-a4cc3cae04525c7fd6edc8a4301a4034c82fdfad.tar.gz
rust-a4cc3cae04525c7fd6edc8a4301a4034c82fdfad.zip
expand: Resolve and expand inner attributes on out-of-line modules
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs20
-rw-r--r--compiler/rustc_expand/src/module.rs58
-rw-r--r--compiler/rustc_resolve/src/macros.rs27
-rw-r--r--compiler/rustc_span/src/symbol.rs1
5 files changed, 79 insertions, 29 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d6297addc0c..a934bdd7980 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2297,7 +2297,7 @@ impl FnRetTy {
     }
 }
 
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
 pub enum Inline {
     Yes,
     No,
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>(
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2d149c476a6..2e47d4cecee 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -6,7 +6,7 @@ use crate::Namespace::*;
 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
 use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
-use rustc_ast::{self as ast, NodeId};
+use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
@@ -14,6 +14,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
+use rustc_expand::base::Annotatable;
 use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
@@ -153,6 +154,26 @@ crate fn registered_attrs_and_tools(
     (registered_attrs, registered_tools)
 }
 
+// Some feature gates for inner attributes are reported as lints for backward compatibility.
+fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bool {
+    match &path.segments[..] {
+        // `#![test]`
+        [seg] if seg.ident.name == sym::test => return true,
+        // `#![rustfmt::skip]` on out-of-line modules
+        [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
+            if let InvocationKind::Attr { item, .. } = &invoc.kind {
+                if let Annotatable::Item(item) = item {
+                    if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind {
+                        return true;
+                    }
+                }
+            }
+        }
+        _ => {}
+    }
+    false
+}
+
 impl<'a> ResolverExpand for Resolver<'a> {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
@@ -267,6 +288,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
             parent_scope,
             node_id,
             force,
+            soft_custom_inner_attributes_gate(path, invoc),
         )?;
 
         let span = invoc.span();
@@ -440,6 +462,7 @@ impl<'a> Resolver<'a> {
         parent_scope: &ParentScope<'a>,
         node_id: NodeId,
         force: bool,
+        soft_custom_inner_attributes_gate: bool,
     ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
         let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
         {
@@ -507,7 +530,7 @@ impl<'a> Resolver<'a> {
                 Res::NonMacroAttr(..) => "custom inner attributes are unstable",
                 _ => unreachable!(),
             };
-            if path == &sym::test {
+            if soft_custom_inner_attributes_gate {
                 self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
             } else {
                 feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 79ca3c194cc..4fcb8b6c1b7 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1111,6 +1111,7 @@ symbols! {
         size_of,
         size_of_val,
         sized,
+        skip,
         slice,
         slice_alloc,
         slice_patterns,