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

Reply via email to