https://gcc.gnu.org/g:b6a0e55603f4497210ccbf9b49f18db1901cc68b
commit r17-5706-gb6a0e55603f4497210ccbf9b49f18db1901cc68b Author: Utkarsh Bahuguna <[email protected]> Date: Sat Oct 3 13:31:45 2026 +0530 gccrs: Resolve 2015 use paths from the crate root 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]> Diff: --- gcc/rust/resolve/rust-early-name-resolver-2.0.cc | 26 ++++++++++++++- gcc/rust/resolve/rust-early-name-resolver-2.0.h | 16 +++++++-- gcc/testsuite/rust/compile/issue-4589.rs | 41 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) 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 4860163beb64..1422a300d5d6 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 f2297d58eb8e..c8cfe38911c5 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 000000000000..b218b1896efd --- /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(); +}
