about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2022-11-12 21:46:05 -0700
committerMichael Howell <michael@notriddle.com>2023-01-20 14:52:24 -0700
commite9d8d238ef76c7991b316bbfbd9f857d84bd39cf (patch)
treed3afc52cc337d3f1372f9858e7dcdb7593094bf6
parent5ce39f42bd2c8bca9c570f0560ebe1fce4eddb14 (diff)
downloadrust-e9d8d238ef76c7991b316bbfbd9f857d84bd39cf.tar.gz
rust-e9d8d238ef76c7991b316bbfbd9f857d84bd39cf.zip
diagnostics: suggest changing `s@self::{macro}@::macro` for exported
Fixes #99695
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs30
-rw-r--r--tests/ui/imports/issue-99695.fixed17
-rw-r--r--tests/ui/imports/issue-99695.rs16
-rw-r--r--tests/ui/imports/issue-99695.stderr16
4 files changed, 78 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f24e405018b..2a5cc288380 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 00000000000..6bf228b23aa
--- /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 00000000000..f7199f1497a
--- /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 00000000000..0ef762e1c82
--- /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`.