Keep track of parse errors in mod
s 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.
This commit is contained in:
parent
3f52583c6a
commit
69fb612608
26 changed files with 128 additions and 93 deletions
|
@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
item_inner.kind,
|
||||
ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
|
||||
)
|
||||
) =>
|
||||
{
|
||||
|
@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||
match &item.kind {
|
||||
ItemKind::Mod(_, mod_kind)
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
||||
{
|
||||
feature_err(
|
||||
self.sess,
|
||||
|
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
|
||||
let ecx = &mut collector.cx;
|
||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
||||
ModKind::Loaded(_, inline, _) => {
|
||||
ModKind::Loaded(_, inline, _, _) => {
|
||||
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||
let (dir_path, dir_ownership) = mod_dir_path(
|
||||
ecx.sess,
|
||||
|
@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
ModKind::Unloaded => {
|
||||
// We have an outline `mod foo;` so we need to parse the file.
|
||||
let old_attrs_len = attrs.len();
|
||||
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
|
||||
parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
let ParsedExternalMod {
|
||||
items,
|
||||
spans,
|
||||
file_path,
|
||||
dir_path,
|
||||
dir_ownership,
|
||||
had_parse_error,
|
||||
} = parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
|
||||
if let Some(lint_store) = ecx.lint_store {
|
||||
lint_store.pre_expansion_lint(
|
||||
|
@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
);
|
||||
}
|
||||
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans);
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
|
||||
node.attrs = attrs;
|
||||
if node.attrs.len() > old_attrs_len {
|
||||
// If we loaded an out-of-line module and added some inner attributes,
|
||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
|
|||
pub file_path: PathBuf,
|
||||
pub dir_path: PathBuf,
|
||||
pub dir_ownership: DirOwnership,
|
||||
pub had_parse_error: Result<(), ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
pub enum ModError<'a> {
|
||||
|
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
|
|||
attrs.extend(inner_attrs);
|
||||
(items, inner_span, mp.file_path)
|
||||
};
|
||||
|
||||
// (1) ...instead, we return a dummy module.
|
||||
let (items, spans, file_path) =
|
||||
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
|
||||
let ((items, spans, file_path), had_parse_error) = match result {
|
||||
Err(err) => (Default::default(), Err(err.report(sess, span))),
|
||||
Ok(result) => (result, Ok(())),
|
||||
};
|
||||
|
||||
// Extract the directory path for submodules of the module.
|
||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
||||
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
|
||||
}
|
||||
|
||||
pub(crate) fn mod_dir_path(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue