From: Owen Avery <powerboat9.ga...@gmail.com> gcc/rust/ChangeLog:
* resolve/rust-early-name-resolver-2.0.cc (Early::build_import_mapping): Avoid outputting an "unresolved import" error if other errors are outputted during resolution. * resolve/rust-early-name-resolver-2.0.h (Early::resolve_path_in_all_ns): Collect path resolution errors while avoiding duplicate errors for resolutions in each namespace. * resolve/rust-forever-stack.h (ForeverStack::resolve_path): Add parameter for collecting errors. (ForeverStack::find_starting_point): Likewise. (ForeverStack::resolve_segments): Likewise. * resolve/rust-forever-stack.hxx (check_leading_kw_at_start): Likewise. (ForeverStack::find_starting_point): Likewise. (ForeverStack::resolve_segments): Likewise. (ForeverStack::resolve_path): Likewise. * resolve/rust-name-resolution-context.h (NameResolutionContext::resolve_path): Add optional parameter for collecting errors. gcc/testsuite/ChangeLog: * rust/compile/nr2/exclude: Remove entry. Signed-off-by: Owen Avery <powerboat9.ga...@gmail.com> --- .../resolve/rust-early-name-resolver-2.0.cc | 6 +- .../resolve/rust-early-name-resolver-2.0.h | 16 +++- gcc/rust/resolve/rust-forever-stack.h | 9 +- gcc/rust/resolve/rust-forever-stack.hxx | 45 ++++++---- .../resolve/rust-name-resolution-context.h | 87 ++++++++++++++----- gcc/testsuite/rust/compile/nr2/exclude | 1 - 6 files changed, 115 insertions(+), 49 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 36456e10ff2..7d048ea8289 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -141,6 +141,10 @@ Early::build_import_mapping ( // be moved into the newly created import mappings auto path = import.to_resolve; + // used to skip the "unresolved import" error + // if we output other errors during resolution + size_t old_error_count = macro_resolve_errors.size (); + switch (import.kind) { case TopLevel::ImportKind::Kind::Glob: @@ -154,7 +158,7 @@ Early::build_import_mapping ( break; } - if (!found) + if (!found && old_error_count == macro_resolve_errors.size ()) collect_error (Error (path.get_final_segment ().get_locus (), ErrorCode::E0433, "unresolved import %qs", path.as_string ().c_str ())); 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 c4226fe9ea8..e78bec0199a 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -218,7 +218,6 @@ private: std::vector<std::pair<Rib::Definition, Namespace>> resolve_path_in_all_ns (const P &path) { - const auto &segments = path.get_segments (); std::vector<std::pair<Rib::Definition, Namespace>> resolved; // Pair a definition with the namespace it was found in @@ -229,13 +228,22 @@ private: }; }; - ctx.resolve_path (segments, Namespace::Values) + std::vector<Error> value_errors; + std::vector<Error> type_errors; + std::vector<Error> macro_errors; + + ctx.resolve_path (path, value_errors, Namespace::Values) .map (pair_with_ns (Namespace::Values)); - ctx.resolve_path (segments, Namespace::Types) + ctx.resolve_path (path, type_errors, Namespace::Types) .map (pair_with_ns (Namespace::Types)); - ctx.resolve_path (segments, Namespace::Macros) + ctx.resolve_path (path, macro_errors, Namespace::Macros) .map (pair_with_ns (Namespace::Macros)); + if (!value_errors.empty () && !type_errors.empty () + && !macro_errors.empty ()) + for (auto &ent : value_errors) + collect_error (std::move (ent)); + return resolved; } diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index cf0265140de..75d8c1d9b59 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -673,7 +673,8 @@ public: template <typename S> tl::optional<Rib::Definition> resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // FIXME: Documentation tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; @@ -792,13 +793,15 @@ private: tl::optional<SegIterator<S>> find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); template <typename S> tl::optional<Node &> resolve_segments ( Node &starting_point, const std::vector<S> &segments, SegIterator<S> iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); tl::optional<Rib::Definition> resolve_final_segment (Node &final_node, std::string &seg_name, diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 31a33016f09..069111eeb0e 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -398,12 +398,14 @@ ForeverStack<N>::find_closest_module (Node &starting_point) * segments */ template <typename S> static inline bool -check_leading_kw_at_start (const S &segment, bool condition) +check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment, + bool condition) { if (condition) - rust_error_at (segment.get_locus (), ErrorCode::E0433, - "%qs in paths can only be used in start position", - segment.as_string ().c_str ()); + collect_errors.emplace_back ( + segment.get_locus (), ErrorCode::E0433, + "%qs in paths can only be used in start position", + segment.as_string ().c_str ()); return condition; } @@ -418,7 +420,8 @@ template <typename S> tl::optional<typename std::vector<S>::const_iterator> ForeverStack<N>::find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { auto iterator = segments.begin (); @@ -435,8 +438,9 @@ ForeverStack<N>::find_starting_point ( // if we're after the first path segment and meet `self` or `crate`, it's // an error - we should only be seeing `super` keywords at this point - if (check_leading_kw_at_start (seg, !is_start (iterator, segments) - && is_self_or_crate)) + if (check_leading_kw_at_start (collect_errors, seg, + !is_start (iterator, segments) + && is_self_or_crate)) return tl::nullopt; if (seg.is_crate_path_seg ()) @@ -459,8 +463,9 @@ ForeverStack<N>::find_starting_point ( starting_point = find_closest_module (starting_point); if (starting_point.get ().is_root ()) { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "too many leading %<super%> keywords"); + collect_errors.emplace_back ( + seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); return tl::nullopt; } @@ -486,7 +491,8 @@ tl::optional<typename ForeverStack<N>::Node &> ForeverStack<N>::resolve_segments ( Node &starting_point, const std::vector<S> &segments, typename std::vector<S>::const_iterator iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) @@ -508,9 +514,10 @@ ForeverStack<N>::resolve_segments ( rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ()); // check that we don't encounter *any* leading keywords afterwards - if (check_leading_kw_at_start (seg, seg.is_crate_path_seg () - || seg.is_super_path_seg () - || seg.is_lower_self_seg ())) + if (check_leading_kw_at_start (collect_errors, seg, + seg.is_crate_path_seg () + || seg.is_super_path_seg () + || seg.is_lower_self_seg ())) return tl::nullopt; tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt; @@ -619,7 +626,8 @@ template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { // TODO: What to do if segments.empty() ? @@ -667,12 +675,13 @@ ForeverStack<N>::resolve_path ( std::reference_wrapper<Node> starting_point = cursor (); auto res - = find_starting_point (segments, starting_point, insert_segment_resolution) + = find_starting_point (segments, starting_point, insert_segment_resolution, + collect_errors) .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution] ( - typename std::vector<S>::const_iterator iterator) { + [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); + insert_segment_resolution, collect_errors); }) .and_then ([this, &segments, &insert_segment_resolution] ( Node &final_node) -> tl::optional<Rib::Definition> { diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 84c0800ac4a..51c08efe3df 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -220,9 +220,10 @@ public: tl::optional<NodeId> lookup (NodeId usage) const; template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Namespace ns) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + std::vector<Error> &collect_errors, Namespace ns) { std::function<void (const S &, NodeId)> insert_segment_resolution = [this] (const S &seg, NodeId id) { @@ -234,60 +235,102 @@ public: { case Namespace::Values: return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Types: return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Macros: return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Labels: return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); default: rust_unreachable (); } } template <typename S, typename... Args> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { - std::initializer_list<Namespace> namespaces = {ns_args...}; + std::initializer_list<Namespace> namespaces = {ns_first, ns_args...}; for (auto ns : namespaces) { - if (auto ret - = resolve_path (segments, has_opening_scope_resolution, ns)) + std::vector<Error> collect_errors_inner; + if (auto ret = resolve_path (segments, has_opening_scope_resolution, + collect_errors_inner, ns)) return ret; + if (!collect_errors_inner.empty ()) + { + if (collect_errors.has_value ()) + { + std::move (collect_errors_inner.begin (), + collect_errors_inner.end (), + std::back_inserter (collect_errors.value ())); + } + else + { + for (auto &e : collect_errors_inner) + e.emit (); + } + return tl::nullopt; + } } return tl::nullopt; } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::SimplePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), ns_args...); + path.has_opening_scope_resolution (), collect_errors, + ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::PathInExpression &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), path.opening_scope_resolution (), - ns_args...); + collect_errors, ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::TypePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), ns_args...); + path.has_opening_scope_resolution_op (), + collect_errors, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, + Args... ns_args) + { + return resolve_path (path, tl::nullopt, ns_first, ns_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) + { + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } private: diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index f94cbe46679..d3efe08a531 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -17,7 +17,6 @@ derive-default1.rs derive-eq-invalid.rs torture/alt_patterns1.rs torture/name_resolve1.rs -issue-3568.rs issue-3663.rs issue-3671.rs issue-3652.rs -- 2.49.0