diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f24e405018b74..2a5cc288380f4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2125,9 +2125,31 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let source_map = self.r.session.source_map(); + // Make sure this is actually crate-relative. + let use_and_crate = import.use_span.with_hi(after_crate_name.lo()); + let is_definitely_crate = + source_map.span_to_snippet(use_and_crate).map_or(false, |s| { + let mut s = s.trim(); + debug!("check_for_module_export_macro: s={s:?}",); + s = s + .split_whitespace() + .rev() + .next() + .expect("split_whitespace always yields at least once"); + debug!("check_for_module_export_macro: s={s:?}",); + if s.ends_with("::") { + s = &s[..s.len() - 2]; + } else { + return false; + } + s = s.trim(); + debug!("check_for_module_export_macro: s={s:?}",); + s != "self" && s != "super" + }); + // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); - if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) { corrections.push(( start_point, if has_nested { @@ -2139,6 +2161,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { format!("{{{}, {}", import_snippet, start_snippet) }, )); + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + source_map.start_point(import.use_span).shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } // Add a `};` to the end if nested, matching the `{` added at the start. diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed new file mode 100644 index 0000000000000..6bf228b23aad2 --- /dev/null +++ b/tests/ui/imports/issue-99695.fixed @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + use ::nu; +pub use self::{other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs new file mode 100644 index 0000000000000..f7199f1497ab0 --- /dev/null +++ b/tests/ui/imports/issue-99695.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + pub use self::{nu, other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.stderr new file mode 100644 index 0000000000000..0ef762e1c8230 --- /dev/null +++ b/tests/ui/imports/issue-99695.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `self::nu` + --> $DIR/issue-99695.rs:11:20 + | +LL | pub use self::{nu, other_item as _}; + | ^^ no `nu` in `m` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL ~ use ::nu; +LL ~ pub use self::{other_item as _}; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`.