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.

Fixes issue 68838
This commit is contained in:
Olivier Goffart 2025-11-30 17:02:07 +01:00
parent 621d76794c
commit f3e73dced1
6 changed files with 101 additions and 1 deletions

View file

@ -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))
}

View file

@ -1173,6 +1173,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 {

View file

@ -1711,7 +1711,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;

View file

@ -166,6 +166,14 @@ 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.tcx.def_kind(id).is_module_like()
{
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));

View file

@ -0,0 +1,40 @@
pub mod some_module {
compile_error!("Error in a module"); //~ ERROR: Error in a module
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: crate::some_module::Xyz,
error: self::MissingType, //~ ERROR: cannot find type `MissingType` in module `self`
}
}
}
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
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`
}

View file

@ -0,0 +1,46 @@
error: Error in a module
--> $DIR/compile_error_macro-suppress-errors.rs:2:5
|
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:37:55
|
LL | let _: another_module::SomeType = another_module::Hello::new();
| ^^^^^ could not find `Hello` in `another_module`
error[E0425]: 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:35:29
|
LL | let _ = another_module::some_function();
| ^^^^^^^^^^^^^ not found in `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();
| ^^^^^^^^ not found in `another_module`
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0425, E0432, E0433.
For more information about an error, try `rustc --explain E0425`.