Skip to content

Commit 69fb612

Browse files
committed
Keep track of parse errors in mods and don't emit resolve errors for paths involving them
When we expand a `mod foo;` and parse `foo.rs`, we now track whether that file had an unrecovered parse error that reached the end of the file. If so, we keep that information around. When resolving a path like `foo::bar`, we do not emit any errors for "`bar` not found in `foo`", as we know that the parse error might have caused `bar` to not be parsed and accounted for. When this happens in an existing project, every path referencing `foo` would be an irrelevant compile error. Instead, we now skip emitting anything until `foo.rs` is fixed. Tellingly enough, we didn't have any test for errors caused by `mod` expansion. Fix #97734.
1 parent 3f52583 commit 69fb612

File tree

26 files changed

+128
-93
lines changed

26 files changed

+128
-93
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2877,7 +2877,7 @@ pub enum ModKind {
28772877
/// or with definition outlined to a separate file `mod foo;` and already loaded from it.
28782878
/// The inner span is from the first token past `{` to the last token until `}`,
28792879
/// or from the first to the last token in the loaded file.
2880-
Loaded(ThinVec<P<Item>>, Inline, ModSpans),
2880+
Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
28812881
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
28822882
Unloaded,
28832883
}

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,12 @@ impl WalkItemKind for ItemKind {
12121212
ItemKind::Mod(safety, mod_kind) => {
12131213
visit_safety(vis, safety);
12141214
match mod_kind {
1215-
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
1215+
ModKind::Loaded(
1216+
items,
1217+
_inline,
1218+
ModSpans { inner_span, inject_use_span },
1219+
_,
1220+
) => {
12161221
items.flat_map_in_place(|item| vis.flat_map_item(item));
12171222
vis.visit_span(inner_span);
12181223
vis.visit_span(inject_use_span);

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
380380
try_visit!(visitor.visit_fn(kind, span, id));
381381
}
382382
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
383-
ModKind::Loaded(items, _inline, _inner_span) => {
383+
ModKind::Loaded(items, _inline, _inner_span, _) => {
384384
walk_list!(visitor, visit_item, items);
385385
}
386386
ModKind::Unloaded => {}

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
238238
})
239239
}
240240
ItemKind::Mod(_, mod_kind) => match mod_kind {
241-
ModKind::Loaded(items, _, spans) => {
241+
ModKind::Loaded(items, _, spans, _) => {
242242
hir::ItemKind::Mod(self.lower_mod(items, spans))
243243
}
244244
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10291029
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
10301030
}
10311031
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1032-
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1032+
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
10331033
&& !attr::contains_name(&item.attrs, sym::path)
10341034
{
10351035
self.check_mod_file_item_asciionly(item.ident);

compiler/rustc_builtin_macros/src/test_harness.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
141141

142142
// We don't want to recurse into anything other than mods, since
143143
// mods or tests inside of functions will break things
144-
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
145-
item.kind
144+
if let ast::ItemKind::Mod(
145+
_,
146+
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
147+
) = item.kind
146148
{
147149
let prev_tests = mem::take(&mut self.tests);
148150
walk_item_kind(

compiler/rustc_expand/src/expand.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
723723
item_inner.kind,
724724
ItemKind::Mod(
725725
_,
726-
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
726+
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
727727
)
728728
) =>
729729
{
@@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
889889
fn visit_item(&mut self, item: &'ast ast::Item) {
890890
match &item.kind {
891891
ItemKind::Mod(_, mod_kind)
892-
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
892+
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
893893
{
894894
feature_err(
895895
self.sess,
@@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
11951195

11961196
let ecx = &mut collector.cx;
11971197
let (file_path, dir_path, dir_ownership) = match mod_kind {
1198-
ModKind::Loaded(_, inline, _) => {
1198+
ModKind::Loaded(_, inline, _, _) => {
11991199
// Inline `mod foo { ... }`, but we still need to push directories.
12001200
let (dir_path, dir_ownership) = mod_dir_path(
12011201
ecx.sess,
@@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
12171217
ModKind::Unloaded => {
12181218
// We have an outline `mod foo;` so we need to parse the file.
12191219
let old_attrs_len = attrs.len();
1220-
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
1221-
parse_external_mod(
1222-
ecx.sess,
1223-
ident,
1224-
span,
1225-
&ecx.current_expansion.module,
1226-
ecx.current_expansion.dir_ownership,
1227-
&mut attrs,
1228-
);
1220+
let ParsedExternalMod {
1221+
items,
1222+
spans,
1223+
file_path,
1224+
dir_path,
1225+
dir_ownership,
1226+
had_parse_error,
1227+
} = parse_external_mod(
1228+
ecx.sess,
1229+
ident,
1230+
span,
1231+
&ecx.current_expansion.module,
1232+
ecx.current_expansion.dir_ownership,
1233+
&mut attrs,
1234+
);
12291235

12301236
if let Some(lint_store) = ecx.lint_store {
12311237
lint_store.pre_expansion_lint(
@@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> {
12391245
);
12401246
}
12411247

1242-
*mod_kind = ModKind::Loaded(items, Inline::No, spans);
1248+
*mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
12431249
node.attrs = attrs;
12441250
if node.attrs.len() > old_attrs_len {
12451251
// If we loaded an out-of-line module and added some inner attributes,

compiler/rustc_expand/src/module.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
3737
pub file_path: PathBuf,
3838
pub dir_path: PathBuf,
3939
pub dir_ownership: DirOwnership,
40+
pub had_parse_error: Result<(), ErrorGuaranteed>,
4041
}
4142

4243
pub enum ModError<'a> {
@@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
7475
attrs.extend(inner_attrs);
7576
(items, inner_span, mp.file_path)
7677
};
78+
7779
// (1) ...instead, we return a dummy module.
78-
let (items, spans, file_path) =
79-
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
80+
let ((items, spans, file_path), had_parse_error) = match result {
81+
Err(err) => (Default::default(), Err(err.report(sess, span))),
82+
Ok(result) => (result, Ok(())),
83+
};
8084

8185
// Extract the directory path for submodules of the module.
8286
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
8387

84-
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
88+
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
8589
}
8690

8791
pub(crate) fn mod_dir_path(

compiler/rustc_lint/src/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
30383038
for item in &krate.items {
30393039
if let ast::ItemKind::Mod(
30403040
_,
3041-
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
3041+
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
30423042
) = item.kind
30433043
{
30443044
if item.attrs.iter().any(|a| a.has_name(sym::path)) {

compiler/rustc_parse/src/parser/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
4545
let (inner_attrs, items, inner_span) =
4646
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
4747
attrs.extend(inner_attrs);
48-
ModKind::Loaded(items, Inline::Yes, inner_span)
48+
ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
4949
};
5050
Ok((id, ItemKind::Mod(safety, mod_kind)))
5151
}

0 commit comments

Comments
 (0)