From 5869e5c4d4850ad0c4d161f899e2a32b3effb2d9 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sun, 30 Nov 2025 17:02:07 +0100 Subject: [PATCH 1/4] Supress some lookup errors if a module contains `compile_error!` The problem is that when a macro expand to `compile_error!` because its input is malformed, the actual error message from the `compile_error!` might be hidden in a long list of other messages about using items that should have otherwise been generated by the macro. So suppress error about missing items in that module. --- .../rustc_builtin_macros/src/compile_error.rs | 1 + compiler/rustc_expand/src/base.rs | 4 +++ compiler/rustc_resolve/src/ident.rs | 3 +- compiler/rustc_resolve/src/macros.rs | 6 ++++ .../compile_error_macro-suppress-errors.rs | 25 +++++++++++++++++ ...compile_error_macro-suppress-errors.stderr | 28 +++++++++++++++++++ 6 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/ui/macros/compile_error_macro-suppress-errors.rs create mode 100644 tests/ui/macros/compile_error_macro-suppress-errors.stderr diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 7fc4b437c1d8d..df64d8f314dba 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -22,6 +22,7 @@ pub(crate) fn expand_compile_error<'cx>( #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] let guar = cx.dcx().span_err(sp, var.to_string()); + cx.resolver.mark_scope_with_compile_error(cx.current_expansion.lint_node_id); ExpandResult::Ready(DummyResult::any(sp, guar)) } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 946f17943fe3d..68d9a1db64d2f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1200,6 +1200,10 @@ pub trait ResolverExpand { /// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used /// to generate an item name later that does not reference placeholder macros. fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol); + + /// Mark the scope as having a compile error so that error for lookup in this scope + /// should be suppressed + fn mark_scope_with_compile_error(&mut self, parent_node: NodeId); } pub trait LintStoreExpand { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e38d4370d5d25..03f7a874a3f01 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1718,7 +1718,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { let mut module = None; - let mut module_had_parse_errors = false; + let mut module_had_parse_errors = !self.mods_with_parse_errors.is_empty() + && self.mods_with_parse_errors.contains(&parent_scope.module.nearest_parent_mod()); let mut allow_super = true; let mut second_binding = None; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6bba985d87dd7..f40fe0a41d616 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -166,6 +166,12 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.invocation_parents[&id].parent_def } + fn mark_scope_with_compile_error(&mut self, id: NodeId) { + if let Some(id) = self.opt_local_def_id(id) { + self.mods_with_parse_errors.insert(id.to_def_id()); + } + } + fn resolve_dollar_crates(&self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.rs b/tests/ui/macros/compile_error_macro-suppress-errors.rs new file mode 100644 index 0000000000000..f6f703dd3916d --- /dev/null +++ b/tests/ui/macros/compile_error_macro-suppress-errors.rs @@ -0,0 +1,25 @@ +mod some_module { + compile_error!("Error in a module"); //~ ERROR: Error in a module + + fn abc() { + let _: self::SomeType = self::Hello::new(); + let _: SomeType = Hello::new(); + } +} + +mod another_module {} + +fn main() { + // these errors are suppressed because of the compile_error! macro + + let _ = some_module::some_function(); + let _: some_module::SomeType = some_module::Hello::new(); + + // these errors are not suppressed + + let _ = another_module::some_function(); + //~^ ERROR: cannot find function `some_function` in module `another_module` + let _: another_module::SomeType = another_module::Hello::new(); + //~^ ERROR: cannot find type `SomeType` in module `another_module` + //~^^ ERROR: failed to resolve: could not find `Hello` in `another_module` +} diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.stderr b/tests/ui/macros/compile_error_macro-suppress-errors.stderr new file mode 100644 index 0000000000000..292b5fef248a0 --- /dev/null +++ b/tests/ui/macros/compile_error_macro-suppress-errors.stderr @@ -0,0 +1,28 @@ +error: Error in a module + --> $DIR/compile_error_macro-suppress-errors.rs:2:5 + | +LL | compile_error!("Error in a module"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: could not find `Hello` in `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:22:55 + | +LL | let _: another_module::SomeType = another_module::Hello::new(); + | ^^^^^ could not find `Hello` in `another_module` + +error[E0425]: cannot find function `some_function` in module `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:20:29 + | +LL | let _ = another_module::some_function(); + | ^^^^^^^^^^^^^ not found in `another_module` + +error[E0412]: cannot find type `SomeType` in module `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:22:28 + | +LL | let _: another_module::SomeType = another_module::Hello::new(); + | ^^^^^^^^ not found in `another_module` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0412, E0425, E0433. +For more information about an error, try `rustc --explain E0412`. From 12ec9f2b6b14e41e528c8f2f2c94d0b631f3267c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 9 Dec 2025 16:23:48 +0100 Subject: [PATCH 2/4] Don't put non-module ids into the table --- compiler/rustc_resolve/src/macros.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f40fe0a41d616..8f0dcb7b18318 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -167,7 +167,9 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn mark_scope_with_compile_error(&mut self, id: NodeId) { - if let Some(id) = self.opt_local_def_id(id) { + if let Some(id) = self.opt_local_def_id(id) + && self.tcx.def_kind(id).is_module_like() + { self.mods_with_parse_errors.insert(id.to_def_id()); } } From 1472a97946d1a07f9eb5eec2953c082ba2713009 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 9 Dec 2025 17:49:21 +0100 Subject: [PATCH 3/4] Attempt to be more precise when looking for poinsoned module --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++++--- .../compile_error_macro-suppress-errors.rs | 21 ++++++++++++-- ...compile_error_macro-suppress-errors.stderr | 28 +++++++++++++++---- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 03f7a874a3f01..288a9c7c0c5de 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1835,6 +1835,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let binding = if let Some(module) = module { + if !self.mods_with_parse_errors.is_empty() + && let ModuleOrUniformRoot::Module(m) = module + && m.res() + .and_then(|r| r.module_like_def_id()) + .is_some_and(|def_id| self.mods_with_parse_errors.contains(&def_id)) + { + module_had_parse_errors = true; + } self.reborrow().resolve_ident_in_module( module, ident, @@ -1867,7 +1875,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path.len() - 1, )); } - _ => Err(Determinacy::determined(finalize.is_some())), + _ => { + for rib in &ribs[ns] { + if let RibKind::Module(module) = rib.kind + && module.res().and_then(|r| r.module_like_def_id()).is_some_and( + |def_id| self.mods_with_parse_errors.contains(&def_id), + ) + { + module_had_parse_errors = true; + break; + } + } + Err(Determinacy::determined(finalize.is_some())) + } } } else { self.reborrow().resolve_ident_in_scope_set( @@ -1904,9 +1924,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); if let Some(def_id) = binding.res().module_like_def_id() { - if self.mods_with_parse_errors.contains(&def_id) { - module_had_parse_errors = true; - } module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self.reborrow(), finalize, res, id); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.rs b/tests/ui/macros/compile_error_macro-suppress-errors.rs index f6f703dd3916d..37a83e1177552 100644 --- a/tests/ui/macros/compile_error_macro-suppress-errors.rs +++ b/tests/ui/macros/compile_error_macro-suppress-errors.rs @@ -1,13 +1,28 @@ -mod some_module { +pub mod some_module { compile_error!("Error in a module"); //~ ERROR: Error in a module - fn abc() { + fn abc() -> Hello { let _: self::SomeType = self::Hello::new(); let _: SomeType = Hello::new(); } + + mod inner_module { + use super::Hello; + use crate::another_module::NotExist; //~ ERROR: unresolved import `crate::another_module::NotExist` + use crate::some_module::World; + struct Foo { + bar: super::Xyz, + error: self::MissingType, //~ ERROR: cannot find type `MissingType` in module `self` + } + } } -mod another_module {} +pub mod another_module { + use crate::some_module::NotExist; + fn error_in_this_function() { + compile_error!("Error in a function"); //~ ERROR: Error in a function + } +} fn main() { // these errors are suppressed because of the compile_error! macro diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.stderr b/tests/ui/macros/compile_error_macro-suppress-errors.stderr index 292b5fef248a0..728f82ca465d4 100644 --- a/tests/ui/macros/compile_error_macro-suppress-errors.stderr +++ b/tests/ui/macros/compile_error_macro-suppress-errors.stderr @@ -4,25 +4,43 @@ error: Error in a module LL | compile_error!("Error in a module"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: Error in a function + --> $DIR/compile_error_macro-suppress-errors.rs:23:9 + | +LL | compile_error!("Error in a function"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0432]: unresolved import `crate::another_module::NotExist` + --> $DIR/compile_error_macro-suppress-errors.rs:11:13 + | +LL | use crate::another_module::NotExist; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `NotExist` in `another_module` + error[E0433]: failed to resolve: could not find `Hello` in `another_module` - --> $DIR/compile_error_macro-suppress-errors.rs:22:55 + --> $DIR/compile_error_macro-suppress-errors.rs:37:55 | LL | let _: another_module::SomeType = another_module::Hello::new(); | ^^^^^ could not find `Hello` in `another_module` +error[E0412]: cannot find type `MissingType` in module `self` + --> $DIR/compile_error_macro-suppress-errors.rs:15:26 + | +LL | error: self::MissingType, + | ^^^^^^^^^^^ not found in `self` + error[E0425]: cannot find function `some_function` in module `another_module` - --> $DIR/compile_error_macro-suppress-errors.rs:20:29 + --> $DIR/compile_error_macro-suppress-errors.rs:35:29 | LL | let _ = another_module::some_function(); | ^^^^^^^^^^^^^ not found in `another_module` error[E0412]: cannot find type `SomeType` in module `another_module` - --> $DIR/compile_error_macro-suppress-errors.rs:22:28 + --> $DIR/compile_error_macro-suppress-errors.rs:37:28 | LL | let _: another_module::SomeType = another_module::Hello::new(); | ^^^^^^^^ not found in `another_module` -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0425, E0433. +Some errors have detailed explanations: E0412, E0425, E0432, E0433. For more information about an error, try `rustc --explain E0412`. From 9b59a87cbba72d443ec1316dbf3ed527f68521b2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 9 Dec 2025 18:01:18 +0100 Subject: [PATCH 4/4] Bless after rebase --- .../ui/macros/compile_error_macro-suppress-errors.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.stderr b/tests/ui/macros/compile_error_macro-suppress-errors.stderr index 728f82ca465d4..73b1563596247 100644 --- a/tests/ui/macros/compile_error_macro-suppress-errors.stderr +++ b/tests/ui/macros/compile_error_macro-suppress-errors.stderr @@ -22,7 +22,7 @@ error[E0433]: failed to resolve: could not find `Hello` in `another_module` LL | let _: another_module::SomeType = another_module::Hello::new(); | ^^^^^ could not find `Hello` in `another_module` -error[E0412]: cannot find type `MissingType` in module `self` +error[E0425]: cannot find type `MissingType` in module `self` --> $DIR/compile_error_macro-suppress-errors.rs:15:26 | LL | error: self::MissingType, @@ -34,7 +34,7 @@ error[E0425]: cannot find function `some_function` in module `another_module` LL | let _ = another_module::some_function(); | ^^^^^^^^^^^^^ not found in `another_module` -error[E0412]: cannot find type `SomeType` in module `another_module` +error[E0425]: cannot find type `SomeType` in module `another_module` --> $DIR/compile_error_macro-suppress-errors.rs:37:28 | LL | let _: another_module::SomeType = another_module::Hello::new(); @@ -42,5 +42,5 @@ LL | let _: another_module::SomeType = another_module::Hello::new(); error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0425, E0432, E0433. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0425, E0432, E0433. +For more information about an error, try `rustc --explain E0425`.