From e7761916b8b95ec55ecc20ba8e5b83cf69f80c6c Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 10 Sep 2025 09:07:55 +0200 Subject: [PATCH 1/4] nr: Add prelude field to NRCtx, and fill it upon encountering a prelude. gcc/rust/ChangeLog: * resolve/rust-early-name-resolver-2.0.cc (Early::finalize_glob_import): Save prelude if we find one. * resolve/rust-name-resolution-context.h: Add field. * resolve/rust-toplevel-name-resolver-2.0.cc (has_prelude_import): New function. (TopLevel::visit): Create a prelude glob import if necessary. * resolve/rust-toplevel-name-resolver-2.0.h: Allow glob imports to be prelude imports. --- .../resolve/rust-early-name-resolver-2.0.cc | 8 +++ .../resolve/rust-name-resolution-context.h | 59 ++++++++++++++++--- .../rust-toplevel-name-resolver-2.0.cc | 13 +++- .../resolve/rust-toplevel-name-resolver-2.0.h | 18 ++++-- 4 files changed, 83 insertions(+), 15 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 0dff83153311..fb63b0edbac2 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -410,6 +410,14 @@ Early::finalize_glob_import (NameResolutionContext &ctx, rust_assert (container); + if (mapping.import_kind.is_prelude) + { + rust_assert (container.value ()->get_item_kind () + == AST::Item::Kind::Module); + + ctx.prelude = container.value ()->get_node_id (); + } + GlobbingVisitor (ctx).go (container.value ()); } diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 558b3cab6647..25922bc3c93b 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -560,23 +560,63 @@ class NameResolutionContext if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ()) map_usage (Usage (seg_id), Definition (id)); }; + + tl::optional resolved = tl::nullopt; + switch (ns) { case Namespace::Values: - return values.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Types: - return types.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Macros: - return macros.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; case Namespace::Labels: - return labels.resolve_path (segments, mode, insert_segment_resolution, - collect_errors); + resolved + = labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); + break; default: rust_unreachable (); } + + // If it fails, switch to std prelude resolution if it exists + if (prelude && !resolved) + { + // TODO: Factor this with the above + switch (ns) + { + case Namespace::Values: + return values.resolve_path (segments, mode, + insert_segment_resolution, + collect_errors, *prelude); + case Namespace::Types: + return types.resolve_path (segments, mode, + insert_segment_resolution, + collect_errors, *prelude); + case Namespace::Macros: + return macros.resolve_path (segments, mode, + insert_segment_resolution, + collect_errors, *prelude); + case Namespace::Labels: + return labels.resolve_path (segments, mode, + insert_segment_resolution, + collect_errors, *prelude); + default: + rust_unreachable (); + } + } + + return resolved; } template @@ -676,6 +716,9 @@ class NameResolutionContext std::forward (args)...); } + /* If declared with #[prelude_import], the current standard library module */ + tl::optional prelude; + private: /* Map of "usage" nodes which have been resolved to a "definition" node */ std::map resolved_nodes; diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 0930f966e202..dcd1592a8373 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -496,6 +496,16 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector &paths, paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ())); } +static bool +has_prelude_import (const std::vector &attributes) +{ + for (const auto &attr : attributes) + if (attr.get_path ().as_string () == "prelude_import") + return true; + + return false; +} + void TopLevel::visit (AST::UseDeclaration &use) { @@ -523,7 +533,8 @@ TopLevel::visit (AST::UseDeclaration &use) for (auto &&glob : glob_path) imports.emplace_back ( - ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib)); + ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib, + has_prelude_import (use.get_outer_attrs ()))); for (auto &&rebind : rebind_path) imports.emplace_back ( diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index 8d3da92961ad..fca1b368b16c 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -67,10 +67,10 @@ class TopLevel : public DefaultResolver } kind; static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib, - Rib &types_rib, Rib ¯os_rib) + Rib &types_rib, Rib ¯os_rib, bool is_prelude) { return ImportKind (Kind::Glob, std::move (to_resolve), values_rib, - types_rib, macros_rib); + types_rib, macros_rib, is_prelude); } static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib, @@ -84,8 +84,10 @@ class TopLevel : public DefaultResolver AST::UseTreeRebind &&rebind, Rib &values_rib, Rib &types_rib, Rib ¯os_rib) { - return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib, - types_rib, macros_rib, std::move (rebind)); + return ImportKind ( + Kind::Rebind, std::move (to_resolve), values_rib, types_rib, macros_rib, + false /* is_prelude: rebind imports can never be preludes */, + std::move (rebind)); } // The path for `Early` to resolve. @@ -98,13 +100,17 @@ class TopLevel : public DefaultResolver Rib &types_rib; Rib ¯os_rib; + // Can only be true if we are dealing with a glob import with the + // #[prelude_import] attribute + bool is_prelude = false; + private: ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib, - Rib &types_rib, Rib ¯os_rib, + Rib &types_rib, Rib ¯os_rib, bool is_prelude = false, tl::optional &&rebind = tl::nullopt) : kind (kind), to_resolve (std::move (to_resolve)), rebind (std::move (rebind)), values_rib (values_rib), - types_rib (types_rib), macros_rib (macros_rib) + types_rib (types_rib), macros_rib (macros_rib), is_prelude (is_prelude) {} }; From 37b796903105e97b03786cf4a7c9b33778f1e3da Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 10 Sep 2025 09:39:18 +0200 Subject: [PATCH 2/4] forever-stack: Add extra path resolution from a known NodeId. gcc/rust/ChangeLog: * resolve/rust-forever-stack.h: Add new resolve_path function. * resolve/rust-forever-stack.hxx: Implement it. --- gcc/rust/resolve/rust-forever-stack.h | 18 ++++++++++++- gcc/rust/resolve/rust-forever-stack.hxx | 35 ++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 75dd87395bef..927e54705a17 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -682,6 +682,11 @@ template class ForeverStack const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors); + template + tl::optional resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, NodeId starting_point_id); // FIXME: Documentation tl::optional to_rib (NodeId rib_id); @@ -743,9 +748,19 @@ template class ForeverStack tl::optional parent; // `None` only if the node is a root }; - // private overload which allows specifying a starting point + /** + * Private overloads which allow specifying a starting point + */ + tl::optional get (Node &start, const Identifier &name); + template + tl::optional resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, + std::reference_wrapper starting_point); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { @@ -777,6 +792,7 @@ template class ForeverStack * resolution */ Node lang_prelude; + /* * The extern prelude, used for resolving external crates */ diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 848f5e61522b..c0b3041e9655 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -647,6 +647,25 @@ ForeverStack::resolve_final_segment (Node &final_node, std::string &seg_name, return final_node.rib.get (seg_name); } +template +template +tl::optional +ForeverStack::resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, NodeId starting_point_id) +{ + auto starting_point = dfs_node (root, starting_point_id); + + // We may have a prelude, but haven't visited it yet and thus it's not in our + // nodes + if (!starting_point) + return tl::nullopt; + + return resolve_path (segments, mode, insert_segment_resolution, + collect_errors, *starting_point); +} + template template tl::optional @@ -654,10 +673,24 @@ ForeverStack::resolve_path ( const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors) +{ + std::reference_wrapper starting_point = cursor (); + + return resolve_path (segments, mode, insert_segment_resolution, + collect_errors, starting_point); +} + +template +template +tl::optional +ForeverStack::resolve_path ( + const std::vector &segments, ResolutionMode mode, + std::function insert_segment_resolution, + std::vector &collect_errors, + std::reference_wrapper starting_point) { rust_assert (!segments.empty ()); - std::reference_wrapper starting_point = cursor (); switch (mode) { case ResolutionMode::Normal: From 9e474b536fd3fe826b6ae9800ca5595a01e7b8a9 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Fri, 12 Sep 2025 16:11:15 +0200 Subject: [PATCH 3/4] nr: Do prelude resolution for Identifiers gcc/rust/ChangeLog: * resolve/rust-forever-stack.h: New function. * resolve/rust-forever-stack.hxx: Implement it. * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Call it if the prelude exists and we have an unresolved Identifier Call it if the prelude exists and we have an unresolved Identifier. --- gcc/rust/resolve/rust-forever-stack.h | 2 ++ gcc/rust/resolve/rust-forever-stack.hxx | 11 +++++++++++ gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 12 +++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 927e54705a17..4e6e433e407f 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -668,6 +668,8 @@ template class ForeverStack tl::optional get (const Identifier &name); tl::optional get_lang_prelude (const Identifier &name); tl::optional get_lang_prelude (const std::string &name); + tl::optional get_from_prelude (NodeId prelude, + const Identifier &name); /** * Resolve a path to its definition in the current `ForeverStack` diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index c0b3041e9655..ffdfb871155e 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -343,6 +343,17 @@ ForeverStack::get_lang_prelude (const std::string &name) return lang_prelude.rib.get (name); } +template +tl::optional +ForeverStack::get_from_prelude (NodeId prelude, const Identifier &name) +{ + auto starting_point = dfs_node (root, prelude); + if (!starting_point) + return tl::nullopt; + + return get (*starting_point, name); +} + template <> tl::optional inline ForeverStack::get ( const Identifier &name) diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 96b38f48e4e4..f87f2515e14c 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -348,7 +348,17 @@ Late::visit (AST::IdentifierExpr &expr) { resolved = type; } - else + else if (!resolved && ctx.prelude) + { + resolved + = ctx.values.get_from_prelude (*ctx.prelude, expr.get_ident ()); + + if (!resolved) + resolved + = ctx.types.get_from_prelude (*ctx.prelude, expr.get_ident ()); + } + + if (!resolved) { rust_error_at (expr.get_locus (), ErrorCode::E0425, "cannot find value %qs in this scope", From 5368bd512e83e912327245a07e1281600cb233d5 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 1 Oct 2025 12:10:58 +0200 Subject: [PATCH 4/4] nr: Ignore errors when doing prelude resolution We only want to emit the ones from regular name resolution as otherwise they will be doubled for the user for no good reason. gcc/rust/ChangeLog: * resolve/rust-name-resolution-context.h: Co-authored-by: Owen Avery --- gcc/rust/resolve/rust-name-resolution-context.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 25922bc3c93b..1abcd6456c8d 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -592,25 +592,27 @@ class NameResolutionContext // If it fails, switch to std prelude resolution if it exists if (prelude && !resolved) { + std::vector ignore_errors = {}; + // TODO: Factor this with the above switch (ns) { case Namespace::Values: return values.resolve_path (segments, mode, insert_segment_resolution, - collect_errors, *prelude); + ignore_errors, *prelude); case Namespace::Types: return types.resolve_path (segments, mode, - insert_segment_resolution, - collect_errors, *prelude); + insert_segment_resolution, ignore_errors, + *prelude); case Namespace::Macros: return macros.resolve_path (segments, mode, insert_segment_resolution, - collect_errors, *prelude); + ignore_errors, *prelude); case Namespace::Labels: return labels.resolve_path (segments, mode, insert_segment_resolution, - collect_errors, *prelude); + ignore_errors, *prelude); default: rust_unreachable (); }