From: Utkarsh Bahuguna <[email protected]>

In the 2015 edition use paths start at the crate root, but we resolved
them from the current module, so `use foo::bar` in a submodule failed.
Work out the resolution mode of each import path and pass it to
resolve_path.

Fixes Rust-GCC/gccrs#4589

Assisted-by: Claude Opus 5.5 (Anthropic)

gcc/rust/ChangeLog:

        * resolve/rust-early-name-resolver-2.0.h
        (Early::import_resolution_mode): Declare.
        (Early::resolve_path_in_all_ns): Use it.
        * resolve/rust-early-name-resolver-2.0.cc
        (Early::import_resolution_mode): New function.
        (Early::resolve_glob_import): Use it.

gcc/testsuite/ChangeLog:

        * rust/compile/issue-4589.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/7db682a89f216f2ee95989cc486505969a164169

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4589: https://github.com/Rust-GCC/gccrs/issues/4589

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4954

 .../resolve/rust-early-name-resolver-2.0.cc   | 26 +++++++++++-
 .../resolve/rust-early-name-resolver-2.0.h    | 16 ++++++--
 gcc/testsuite/rust/compile/issue-4589.rs      | 41 +++++++++++++++++++
 3 files changed, 79 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4589.rs

diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 4860163be..1422a300d 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -31,6 +31,7 @@
 #include "rust-attribute-values.h"
 #include "rust-identifier-path.h"
 #include "rust-session-manager.h"
+#include "rust-edition.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -86,10 +87,33 @@ Early::go (AST::Crate &crate)
   IdentifierPathPass::go (crate, ctx, std::move (ident_path_to_convert));
 }
 
+ResolutionMode
+Early::import_resolution_mode (const AST::SimplePath &path)
+{
+  bool is_2015 = get_rust_edition () == Edition::E2015;
+
+  if (path.has_opening_scope_resolution ())
+    return is_2015 ? ResolutionMode::FromRoot : ResolutionMode::FromExtern;
+
+  if (!is_2015)
+    return ResolutionMode::Normal;
+
+  // `use *;` has no segments, and imports from the crate root as well
+  auto &segments = path.get_segments ();
+  if (!segments.empty ()
+      && (segments.front ().is_lower_self_seg ()
+         || segments.front ().is_super_path_seg ()))
+    return ResolutionMode::Normal;
+
+  return ResolutionMode::FromRoot;
+}
+
 bool
 Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
 {
-  auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types);
+  auto resolved = ctx.resolve_path (glob.to_resolve.get_segments (),
+                                   import_resolution_mode (glob.to_resolve),
+                                   Namespace::Types);
   if (!resolved.has_value ())
     return false;
 
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h 
b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
index f2297d58e..c8cfe3891 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -212,10 +212,17 @@ private:
   bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
   bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind 
&&import);
 
+  // In the 2015 edition, a use path is relative to the crate root unless it
+  // starts with self or super.
+  static ResolutionMode import_resolution_mode (const AST::SimplePath &path);
+
   template <typename P>
   std::vector<NameResolutionContext::NamespacedDefinition>
   resolve_path_in_all_ns (const P &path)
   {
+    auto &segments = path.get_segments ();
+    auto mode = import_resolution_mode (path);
+
     std::vector<NameResolutionContext::NamespacedDefinition> resolved;
 
     std::vector<Error> value_errors;
@@ -227,9 +234,12 @@ private:
          resolved.emplace_back (new_def);
        };
 
-    ctx.resolve_path (path, value_errors, Namespace::Values).map (resolved_fn);
-    ctx.resolve_path (path, type_errors, Namespace::Types).map (resolved_fn);
-    ctx.resolve_path (path, macro_errors, Namespace::Macros).map (resolved_fn);
+    ctx.resolve_path (segments, mode, value_errors, Namespace::Values)
+      .map (resolved_fn);
+    ctx.resolve_path (segments, mode, type_errors, Namespace::Types)
+      .map (resolved_fn);
+    ctx.resolve_path (segments, mode, macro_errors, Namespace::Macros)
+      .map (resolved_fn);
 
     if (!value_errors.empty () && !type_errors.empty ()
        && !macro_errors.empty ())
diff --git a/gcc/testsuite/rust/compile/issue-4589.rs 
b/gcc/testsuite/rust/compile/issue-4589.rs
new file mode 100644
index 000000000..b218b1896
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4589.rs
@@ -0,0 +1,41 @@
+// { dg-additional-options "-frust-edition=2015" }
+
+#![feature(no_core)]
+#![no_core]
+
+pub mod foo {
+    pub fn bar() {}
+}
+
+pub mod baz {
+    pub use foo::bar;
+
+    pub mod inner {
+        pub use self::nested::f;
+        pub use super::bar as g;
+
+        pub mod nested {
+            pub fn f() {}
+        }
+    }
+}
+
+pub mod qux {
+    pub use foo::*;
+}
+
+pub mod quux {
+    use *;
+
+    pub fn h() {
+        foo::bar();
+    }
+}
+
+fn main() {
+    baz::bar();
+    baz::inner::f();
+    baz::inner::g();
+    qux::bar();
+    quux::h();
+}

base-commit: f42ee1fd2b71c2865ed579c1547adbeb26a700ae
-- 
2.55.0

Reply via email to