about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-02-17 00:56:07 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-02-18 13:07:49 +0300
commit4a8816512477513f57986685738cd065e72c4908 (patch)
tree264d04ccc27f50e8b7f3e91402ba228e97af43c6
parenteb65f15c7800930c3f74288974689d9884e51ba0 (diff)
downloadrust-4a8816512477513f57986685738cd065e72c4908.tar.gz
rust-4a8816512477513f57986685738cd065e72c4908.zip
ast: Keep expansion status for out-of-line module items
Also remove `ast::Mod` which is mostly redundant now
-rw-r--r--compiler/rustc_ast/src/ast.rs33
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs18
-rw-r--r--compiler/rustc_ast/src/visit.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs6
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs42
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs13
-rw-r--r--compiler/rustc_expand/src/expand.rs90
-rw-r--r--compiler/rustc_expand/src/module.rs23
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs4
-rw-r--r--compiler/rustc_parse/src/parser/item.rs12
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/ast_utils.rs9
14 files changed, 147 insertions, 125 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b01e8ccd677..3550055ac10 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2299,21 +2299,22 @@ impl FnRetTy {
     }
 }
 
-/// Module declaration.
-///
-/// E.g., `mod foo;` or `mod foo { .. }`.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
+pub enum Inline {
+    Yes,
+    No,
+}
+
+/// Module item kind.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct Mod {
-    /// A span from the first token past `{` to the last token until `}`.
-    /// For `mod foo;`, the inner span ranges from the first token
-    /// to the last token in the external file.
-    pub inner: Span,
-    /// `unsafe` keyword accepted syntactically for macro DSLs, but not
-    /// semantically by Rust.
-    pub unsafety: Unsafe,
-    pub items: Vec<P<Item>>,
-    /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
-    pub inline: bool,
+pub enum ModKind {
+    /// Module with inlined definition `mod foo { ... }`,
+    /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
+    /// The inner span is from the first token past `{` to the last token until `}`,
+    /// or from the first to the last token in the loaded file.
+    Loaded(Vec<P<Item>>, Inline, Span),
+    /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
+    Unloaded,
 }
 
 /// Foreign module declaration.
@@ -2710,7 +2711,9 @@ pub enum ItemKind {
     /// A module declaration (`mod`).
     ///
     /// E.g., `mod foo;` or `mod foo { .. }`.
-    Mod(Mod),
+    /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
+    /// semantically by Rust.
+    Mod(Unsafe, ModKind),
     /// An external module (`extern`).
     ///
     /// E.g., `extern {}` or `extern "C" {}`.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 5333da07aa0..c286738811c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -913,11 +913,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
             vis.visit_generics(generics);
             visit_opt(body, |body| vis.visit_block(body));
         }
-        ItemKind::Mod(m) => {
-            let Mod { inner, unsafety: _, items, inline: _ } = m;
-            vis.visit_span(inner);
-            items.flat_map_in_place(|item| vis.flat_map_item(item));
-        }
+        ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, inner_span) => {
+                vis.visit_span(inner_span);
+                items.flat_map_in_place(|item| vis.flat_map_item(item));
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
         ItemKind::GlobalAsm(_ga) => {}
         ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
@@ -1010,7 +1012,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
             id: DUMMY_NODE_ID,
             vis: item_vis,
             span,
-            kind: ItemKind::Mod(Mod { inner: span, unsafety: Unsafe::No, items, inline: true }),
+            kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
             tokens: None,
         });
         let items = vis.flat_map_item(item);
@@ -1021,7 +1023,9 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
         } else if len == 1 {
             let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
             match kind {
-                ItemKind::Mod(module) => Crate { attrs, items: module.items, span, proc_macros },
+                ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
+                    Crate { attrs, items, span, proc_macros }
+                }
                 _ => panic!("visitor converted a module to not a module"),
             }
         } else {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 3fa53bb391f..32b9dd46bae 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -290,7 +290,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id)
         }
-        ItemKind::Mod(ref module) => walk_list!(visitor, visit_item, &module.items),
+        ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, _inner_span) => {
+                walk_list!(visitor, visit_item, items)
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(ref foreign_module) => {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 5bdf0fd50ae..8b740b77740 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -314,7 +314,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ItemKind::Fn(sig, generics, body_id)
                 })
             }
-            ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(&m.items, m.inner)),
+            ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+                ModKind::Loaded(items, _, inner_span) => {
+                    hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
+                }
+                ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
+            },
             ItemKind::ForeignMod(ref fm) => {
                 if fm.abi.is_none() {
                     self.maybe_lint_missing_abi(span, id, abi::Abi::C);
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 8defd91c688..563bcda5190 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1054,12 +1054,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
-            ItemKind::Mod(Mod { inline, unsafety, .. }) => {
+            ItemKind::Mod(unsafety, ref mod_kind) => {
                 if let Unsafe::Yes(span) = unsafety {
                     self.err_handler().span_err(span, "module cannot be declared unsafe");
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !inline && !self.session.contains_name(&item.attrs, sym::path) {
+                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
+                    && !self.session.contains_name(&item.attrs, sym::path)
+                {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index bd9c209b659..2189e6eaa02 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -9,7 +9,7 @@ use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericArg, MacArgs, ModKind};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -87,7 +87,6 @@ pub struct State<'a> {
     pub s: pp::Printer,
     comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn + 'a),
-    is_expanded: bool,
 }
 
 crate const INDENT_UNIT: usize = 4;
@@ -103,12 +102,8 @@ pub fn print_crate<'a>(
     is_expanded: bool,
     edition: Edition,
 ) -> String {
-    let mut s = State {
-        s: pp::mk_printer(),
-        comments: Some(Comments::new(sm, filename, input)),
-        ann,
-        is_expanded,
-    };
+    let mut s =
+        State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
 
     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -856,7 +851,7 @@ impl<'a> PrintState<'a> for State<'a> {
 
 impl<'a> State<'a> {
     pub fn new() -> State<'a> {
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }
+        State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
     }
 
     // Synthesizes a comment that was not textually present in the original source
@@ -1134,26 +1129,29 @@ impl<'a> State<'a> {
                 let body = body.as_deref();
                 self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
             }
-            ast::ItemKind::Mod(ref _mod) => {
+            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
                 self.head(self.to_string(|s| {
                     s.print_visibility(&item.vis);
-                    s.print_unsafety(_mod.unsafety);
+                    s.print_unsafety(unsafety);
                     s.word("mod");
                 }));
                 self.print_ident(item.ident);
 
-                if _mod.inline || self.is_expanded {
-                    self.nbsp();
-                    self.bopen();
-                    self.print_inner_attributes(&item.attrs);
-                    for item in &_mod.items {
-                        self.print_item(item);
+                match mod_kind {
+                    ModKind::Loaded(items, ..) => {
+                        self.nbsp();
+                        self.bopen();
+                        self.print_inner_attributes(&item.attrs);
+                        for item in items {
+                            self.print_item(item);
+                        }
+                        self.bclose(item.span);
+                    }
+                    ModKind::Unloaded => {
+                        self.s.word(";");
+                        self.end(); // end inner head-block
+                        self.end(); // end outer head-block
                     }
-                    self.bclose(item.span);
-                } else {
-                    self.s.word(";");
-                    self.end(); // end inner head-block
-                    self.end(); // end outer head-block
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 8c5431a47db..28e82597843 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -1,10 +1,10 @@
 // Code that generates a test runner to run all the tests in a crate
 
 use rustc_ast as ast;
-use rustc_ast::attr;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
+use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
@@ -106,10 +106,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         if let ast::ItemKind::Mod(..) = item.kind {
             let tests = mem::take(&mut self.tests);
             noop_visit_item_kind(&mut item.kind, self);
-            let module = match item.kind {
-                ast::ItemKind::Mod(module) => module,
-                _ => unreachable!(),
-            };
             let mut tests = mem::replace(&mut self.tests, tests);
 
             if !tests.is_empty() {
@@ -117,8 +113,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
                     if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
                 // Create an identifier that will hygienically resolve the test
                 // case name, even in another module.
+                let inner_span = match item.kind {
+                    ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
+                    _ => unreachable!(),
+                };
                 let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
-                    module.inner,
+                    inner_span,
                     AstPass::TestHarness,
                     &[],
                     Some(parent),
@@ -130,7 +130,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
                 }
                 self.cx.test_cases.extend(tests);
             }
-            item.kind = ast::ItemKind::Mod(module);
         }
         smallvec![P(item)]
     }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c570cc1ff35..5a4737842f0 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -12,8 +12,8 @@ use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
 use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
@@ -367,12 +367,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let krate_item = AstFragment::Items(smallvec![P(ast::Item {
             attrs: krate.attrs,
             span: krate.span,
-            kind: ast::ItemKind::Mod(ast::Mod {
-                inner: krate.span,
-                unsafety: Unsafe::No,
-                items: krate.items,
-                inline: true
-            }),
+            kind: ast::ItemKind::Mod(
+                Unsafe::No,
+                ModKind::Loaded(krate.items, Inline::Yes, krate.span)
+            ),
             ident: Ident::invalid(),
             id: ast::DUMMY_NODE_ID,
             vis: ast::Visibility {
@@ -384,9 +382,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         })]);
 
         match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
-            Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => {
+            Some(ast::Item {
+                attrs,
+                kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
+                ..
+            }) => {
                 krate.attrs = attrs;
-                krate.items = module.items;
+                krate.items = items;
             }
             None => {
                 // Resolution failed so we return an empty expansion
@@ -809,7 +811,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
-                    ast::ItemKind::Mod(module) if !module.inline => {
+                    ast::ItemKind::Mod(_, mod_kind)
+                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
+                    {
                         feature_err(
                             self.parse_sess,
                             sym::proc_macro_hygiene,
@@ -1266,47 +1270,47 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
+            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
                 let sess = &self.cx.sess.parse_sess;
                 let orig_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
 
                 let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
                 let dir = Directory { ownership: orig_ownership, path: module.directory };
-                let Directory { ownership, path } = if old_mod.inline {
-                    // Inline `mod foo { ... }`, but we still need to push directories.
-                    item.attrs = attrs;
-                    push_directory(&self.cx.sess, ident, &item.attrs, dir)
-                } else {
-                    // We have an outline `mod foo;` so we need to parse the file.
-                    let (ast::Mod { unsafety, inline, items, inner }, dir) = parse_external_mod(
-                        &self.cx.sess,
-                        ident,
-                        span,
-                        old_mod.unsafety,
-                        dir,
-                        &mut attrs,
-                        pushed,
-                    );
-
-                    let krate = ast::Crate { attrs, items, span: inner, proc_macros: vec![] };
-                    if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
-                        extern_mod_loaded(&krate, ident);
+                let Directory { ownership, path } = match mod_kind {
+                    ModKind::Loaded(_, Inline::Yes, _) => {
+                        // Inline `mod foo { ... }`, but we still need to push directories.
+                        item.attrs = attrs;
+                        push_directory(&self.cx.sess, ident, &item.attrs, dir)
+                    }
+                    ModKind::Loaded(_, Inline::No, _) => {
+                        panic!("`mod` item is loaded from a file for the second time")
                     }
+                    ModKind::Unloaded => {
+                        // We have an outline `mod foo;` so we need to parse the file.
+                        let (items, inner_span, dir) =
+                            parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
+
+                        let krate =
+                            ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] };
+                        if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
+                            extern_mod_loaded(&krate, ident);
+                        }
 
-                    *old_mod = ast::Mod { unsafety, inline, items: krate.items, inner };
-                    item.attrs = krate.attrs;
-                    // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
-                    item = match self.configure(item) {
-                        Some(node) => node,
-                        None => {
-                            if *pushed {
-                                sess.included_mod_stack.borrow_mut().pop();
+                        *mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
+                        item.attrs = krate.attrs;
+                        // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
+                        item = match self.configure(item) {
+                            Some(node) => node,
+                            None => {
+                                if *pushed {
+                                    sess.included_mod_stack.borrow_mut().pop();
+                                }
+                                return Default::default();
                             }
-                            return Default::default();
-                        }
-                    };
-                    dir
+                        };
+                        dir
+                    }
                 };
 
                 // Set the module info before we flat map.
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index d63625fea46..076d3b02be9 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -1,4 +1,5 @@
-use rustc_ast::{token, Attribute, Mod, Unsafe};
+use rustc_ast::ptr::P;
+use rustc_ast::{token, Attribute, Item};
 use rustc_errors::{struct_span_err, PResult};
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
@@ -42,11 +43,10 @@ crate fn parse_external_mod(
     sess: &Session,
     id: Ident,
     span: Span, // The span to blame on errors.
-    unsafety: Unsafe,
     Directory { mut ownership, path }: Directory,
     attrs: &mut Vec<Attribute>,
     pop_mod_stack: &mut bool,
-) -> (Mod, Directory) {
+) -> (Vec<P<Item>>, Span, Directory) {
     // We bail on the first error, but that error does not cause a fatal error... (1)
     let result: PResult<'_, _> = try {
         // Extract the file path and the new ownership.
@@ -62,25 +62,22 @@ crate fn parse_external_mod(
 
         // Actually parse the external file as a module.
         let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
-        let (inner_attrs, items, inner) = parser.parse_mod(&token::Eof)?;
-        (Mod { unsafety, inline: false, items, inner }, inner_attrs)
+        let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
+        attrs.append(&mut inner_attrs);
+        (items, inner_span)
     };
     // (1) ...instead, we return a dummy module.
-    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
-        let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
-        (module, Vec::new())
-    });
-    attrs.append(&mut new_attrs);
+    let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default();
 
-    // Extract the directory path for submodules of `module`.
-    let path = sess.source_map().span_to_unmapped_path(module.inner);
+    // Extract the directory path for submodules of  the module.
+    let path = sess.source_map().span_to_unmapped_path(inner_span);
     let mut path = match path {
         FileName::Real(name) => name.into_local_path(),
         other => PathBuf::from(other.to_string()),
     };
     path.pop();
 
-    (module, Directory { ownership, path })
+    (items, inner_span, Directory { ownership, path })
 }
 
 fn error_on_circular_module<'a>(
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index f4fcaf5c0a4..56f25ffdb01 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -309,8 +309,8 @@ fn out_of_line_mod() {
         .unwrap()
         .unwrap();
 
-        if let ast::ItemKind::Mod(ref m) = item.kind {
-            assert!(m.items.len() == 2);
+        if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
+            assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
         } else {
             panic!();
         }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c0464c3edbc..0f907859a19 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -35,14 +35,16 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
-        let ((mut inner_attrs, items, inner), inline) = if self.eat(&token::Semi) {
-            ((Vec::new(), Vec::new(), Span::default()), false)
+        let mod_kind = if self.eat(&token::Semi) {
+            ModKind::Unloaded
         } else {
             self.expect(&token::OpenDelim(token::Brace))?;
-            (self.parse_mod(&token::CloseDelim(token::Brace))?, true)
+            let (mut inner_attrs, items, inner_span) =
+                self.parse_mod(&token::CloseDelim(token::Brace))?;
+            attrs.append(&mut inner_attrs);
+            ModKind::Loaded(items, Inline::Yes, inner_span)
         };
-        attrs.append(&mut inner_attrs);
-        Ok((id, ItemKind::Mod(Mod { unsafety, inline, items, inner })))
+        Ok((id, ItemKind::Mod(unsafety, mod_kind)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index cca40a793dd..09ab84eaeb6 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1023,7 +1023,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 });
             }
 
-            ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
+            ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
                 self.with_scope(item.id, |this| {
                     visit::walk_item(this, item);
                 });
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 81407004719..77fbbaa1532 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -29,7 +29,7 @@ use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast::{self as ast, NodeId};
 use rustc_ast::{Crate, CRATE_NODE_ID};
-use rustc_ast::{ItemKind, Path};
+use rustc_ast::{ItemKind, ModKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
@@ -339,8 +339,8 @@ impl UsePlacementFinder {
 
 impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     fn visit_item(&mut self, item: &'tcx ast::Item) {
-        if let ItemKind::Mod(module) = &item.kind {
-            if let ControlFlow::Break(..) = self.check_mod(&module.items, item.id) {
+        if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind {
+            if let ControlFlow::Break(..) = self.check_mod(items, item.id) {
                 return;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
index 64232646972..9ff7ef7cc3b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
@@ -241,9 +241,12 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 && eq_generics(lg, rg)
                 && both(lb, rb, |l, r| eq_block(l, r))
         }
-        (Mod(l), Mod(r)) => {
-            l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind))
-        }
+        (Mod(lu, lmk), Mod(ru, rmk)) => lu == ru && match (lmk, rmk) {
+            (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) =>
+                linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)),
+            (ModKind::Unloaded, ModKind::Unloaded) => true,
+            _ => false,
+        },
         (ForeignMod(l), ForeignMod(r)) => {
             both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
                 && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))