https://gcc.gnu.org/g:e2e16df3b1074eb082c4101e4546130a386f5412
commit r16-2835-ge2e16df3b1074eb082c4101e4546130a386f5412 Author: Owen Avery <powerboat9.ga...@gmail.com> Date: Thu May 8 20:44:47 2025 -0400 gccrs: nr2.0: Improve visibility path handling gcc/rust/ChangeLog: * resolve/rust-forever-stack.h (enum ResolutionMode): New. (ForeverStack::get): Add a private overload that takes a starting node as a parameter. (ForeverStack::resolve_path): Replace boolean parameter has_opening_scope_resolution with ResolutionMode parameter mode. * resolve/rust-forever-stack.hxx (ForeverStack::resolve_path): Likewise. (ForeverStack::get): Add a private overload that takes a starting node as a parameter. * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add Visibility visitor. * resolve/rust-late-name-resolver-2.0.h (Late::visit): Likewise. * resolve/rust-name-resolution-context.h (NameResolutionContext::resolve_path): Rework overloading a bit and accept ResolutionMode parameter. gcc/testsuite/ChangeLog: * rust/compile/nr2/exclude: Remove entries. Signed-off-by: Owen Avery <powerboat9.ga...@gmail.com> Diff: --- gcc/rust/resolve/rust-forever-stack.h | 12 ++- gcc/rust/resolve/rust-forever-stack.hxx | 103 ++++++++++++------------ gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 56 +++++++++++++ gcc/rust/resolve/rust-late-name-resolver-2.0.h | 1 + gcc/rust/resolve/rust-name-resolution-context.h | 93 ++++++++++++--------- gcc/testsuite/rust/compile/nr2/exclude | 2 - 6 files changed, 174 insertions(+), 93 deletions(-) diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 81468e5c386f..3f6f002da688 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -543,6 +543,13 @@ private: Node root; }; +enum class ResolutionMode +{ + Normal, + FromRoot, + FromExtern, // extern prelude +}; + template <Namespace N> class ForeverStack { public: @@ -672,7 +679,7 @@ public: */ template <typename S> tl::optional<Rib::Definition> resolve_path ( - const std::vector<S> &segments, bool has_opening_scope_resolution, + const std::vector<S> &segments, ResolutionMode mode, std::function<void (const S &, NodeId)> insert_segment_resolution, std::vector<Error> &collect_errors); @@ -739,6 +746,9 @@ private: tl::optional<Node &> parent; // `None` only if the node is a root }; + // private overload which allows specifying a starting point + tl::optional<Rib::Definition> get (Node &start, const Identifier &name); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 17136b86ffcd..d568682786c2 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -291,12 +291,12 @@ ForeverStack<N>::update_cursor (Node &new_cursor) template <Namespace N> tl::optional<Rib::Definition> -ForeverStack<N>::get (const Identifier &name) +ForeverStack<N>::get (Node &start, const Identifier &name) { tl::optional<Rib::Definition> resolved_definition = tl::nullopt; // TODO: Can we improve the API? have `reverse_iter` return an optional? - reverse_iter ([&resolved_definition, &name] (Node ¤t) { + reverse_iter (start, [&resolved_definition, &name] (Node ¤t) { auto candidate = current.rib.get (name.as_string ()); return candidate.map_or ( @@ -318,6 +318,13 @@ ForeverStack<N>::get (const Identifier &name) return resolved_definition; } +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get (const Identifier &name) +{ + return get (cursor (), name); +} + template <Namespace N> tl::optional<Rib::Definition> ForeverStack<N>::get_lang_prelude (const Identifier &name) @@ -625,23 +632,25 @@ template <Namespace N> template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( - const std::vector<S> &segments, bool has_opening_scope_resolution, + const std::vector<S> &segments, ResolutionMode mode, std::function<void (const S &, NodeId)> insert_segment_resolution, std::vector<Error> &collect_errors) { rust_assert (!segments.empty ()); - // handle paths with opening scopes - std::function<void (void)> cleanup_current = [] () {}; - if (has_opening_scope_resolution) + std::reference_wrapper<Node> starting_point = cursor (); + switch (mode) { - Node *last_current = &cursor_reference.get (); - if (get_rust_edition () == Edition::E2015) - cursor_reference = root; - else - cursor_reference = extern_prelude; - cleanup_current - = [this, last_current] () { cursor_reference = *last_current; }; + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = root; + break; + case ResolutionMode::FromExtern: + starting_point = extern_prelude; + break; + default: + rust_unreachable (); } // if there's only one segment, we just use `get` @@ -654,13 +663,13 @@ ForeverStack<N>::resolve_path ( lang_item.value ()); insert_segment_resolution (seg, seg_id); - cleanup_current (); // TODO: does NonShadowable matter? return Rib::Definition::NonShadowable (seg_id); } tl::optional<Rib::Definition> res - = get (unwrap_type_segment (segments.back ()).as_string ()); + = get (starting_point.get (), + unwrap_type_segment (segments.back ()).as_string ()); if (!res) res = get_lang_prelude ( @@ -668,45 +677,39 @@ ForeverStack<N>::resolve_path ( if (res && !res->is_ambiguous ()) insert_segment_resolution (segments.back (), res->get_node_id ()); - cleanup_current (); return res; } - std::reference_wrapper<Node> starting_point = cursor (); + return find_starting_point (segments, starting_point, + insert_segment_resolution, collect_errors) + .and_then ( + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector<S>::const_iterator iterator) { + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors); + }) + .and_then ([this, &segments, &insert_segment_resolution] ( + Node &final_node) -> tl::optional<Rib::Definition> { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional<Rib::Definition> res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); - auto res - = find_starting_point (segments, starting_point, insert_segment_resolution, - collect_errors) - .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution, - &collect_errors] (typename std::vector<S>::const_iterator iterator) { - return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution, collect_errors); - }) - .and_then ([this, &segments, &insert_segment_resolution] ( - Node &final_node) -> tl::optional<Rib::Definition> { - // leave resolution within impl blocks to type checker - if (final_node.rib.kind == Rib::Kind::TraitOrImpl) - return tl::nullopt; - - auto &seg = unwrap_type_segment (segments.back ()); - std::string seg_name = seg.as_string (); - - // assuming this can't be a lang item segment - tl::optional<Rib::Definition> res - = resolve_final_segment (final_node, seg_name, - seg.is_lower_self_seg ()); - // Ok we didn't find it in the rib, Lets try the prelude... - if (!res) - res = get_lang_prelude (seg_name); - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - - return res; - }); - cleanup_current (); - return res; + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; + }); } template <Namespace N> 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 3bb364e071dc..062c6f2d0b1c 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -515,6 +515,62 @@ Late::visit (AST::TypePath &type) Definition (resolved->get_node_id ())); } +void +Late::visit (AST::Visibility &vis) +{ + if (!vis.has_path ()) + return; + + AST::SimplePath &path = vis.get_path (); + + rust_assert (path.get_segments ().size ()); + auto &first_seg = path.get_segments ()[0]; + + auto mode = ResolutionMode::Normal; + + if (path.has_opening_scope_resolution ()) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg () + && !first_seg.is_lower_self_seg ()) + { + if (get_rust_edition () == Edition::E2015) + { + mode = ResolutionMode::FromRoot; + } + else + { + rust_error_at (path.get_locus (), + "relative paths are not supported in visibilities in " + "2018 edition or later"); + return; + } + } + + auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types); + + if (!res.has_value ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0433, + "could not resolve path %qs", path.as_string ().c_str ()); + return; + } + + // TODO: is this possible? + if (res->is_ambiguous ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + path.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ())); +} + void Late::visit (AST::Trait &trait) { diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 4b7b1b874112..5b5637d48a91 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -60,6 +60,7 @@ public: void visit (AST::LoopLabel &) override; void visit (AST::PathInExpression &) override; void visit (AST::TypePath &) override; + void visit (AST::Visibility &) override; void visit (AST::Trait &) override; void visit (AST::StructExprStruct &) override; void visit (AST::StructExprStructBase &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index cf87c8f1c79b..1509857739e8 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -280,8 +280,7 @@ public: template <typename S> tl::optional<Rib::Definition> - resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector<S> &segments, ResolutionMode mode, std::vector<Error> &collect_errors, Namespace ns) { std::function<void (const S &, NodeId)> insert_segment_resolution @@ -293,17 +292,17 @@ public: switch (ns) { case Namespace::Values: - return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Types: - return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Macros: - return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Labels: - return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); default: rust_unreachable (); } @@ -311,8 +310,7 @@ public: template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector<S> &segments, ResolutionMode mode, tl::optional<std::vector<Error> &> collect_errors, Namespace ns_first, Args... ns_args) { @@ -321,8 +319,7 @@ public: for (auto ns : namespaces) { std::vector<Error> collect_errors_inner; - if (auto ret = resolve_path (segments, has_opening_scope_resolution, - collect_errors_inner, ns)) + if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns)) return ret; if (!collect_errors_inner.empty ()) { @@ -344,52 +341,68 @@ public: return tl::nullopt; } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::SimplePath &path, + resolve_path (const std::vector<S> &path_segments, + bool has_opening_scope_resolution, tl::optional<std::vector<Error> &> collect_errors, Namespace ns_first, Args... ns_args) { - return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), collect_errors, - ns_first, ns_args...); + auto mode = ResolutionMode::Normal; + if (has_opening_scope_resolution) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + return resolve_path (path_segments, mode, collect_errors, ns_first, + ns_args...); } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::PathInExpression &path, - tl::optional<std::vector<Error> &> collect_errors, - Namespace ns_first, Args... ns_args) + resolve_path (const std::vector<S> &path_segments, + bool has_opening_scope_resolution, Namespace ns_first, + Args... ns_args) { - return resolve_path (path.get_segments (), path.opening_scope_resolution (), - collect_errors, ns_first, ns_args...); + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::TypePath &path, - tl::optional<std::vector<Error> &> collect_errors, + resolve_path (const std::vector<S> &path_segments, ResolutionMode mode, Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, mode, tl::nullopt, ns_first, + ns_args...); + } + + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, + Args &&...args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), - collect_errors, ns_first, ns_args...); + path.has_opening_scope_resolution (), + std::forward<Args> (args)...); } - template <typename P, typename... Args> - tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, - Args... ns_args) + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, + Args &&...args) { - return resolve_path (path, tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + std::forward<Args> (args)...); } - template <typename P, typename... Args> - tl::optional<Rib::Definition> - resolve_path (const P &path_segments, bool has_opening_scope_resolution, - Namespace ns_first, Args... ns_args) + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, + Args &&...args) { - return resolve_path (path_segments, has_opening_scope_resolution, - tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + std::forward<Args> (args)...); } private: diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index d4e066a5f723..70c59f9abdd4 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -1,10 +1,8 @@ canonical_paths1.rs issue-3315-2.rs -privacy5.rs privacy8.rs pub_restricted_1.rs pub_restricted_2.rs -pub_restricted_3.rs issue-2905-2.rs torture/alt_patterns1.rs torture/name_resolve1.rs