https://gcc.gnu.org/g:ab8a0b5cc06c23cea99124ef60d717ac198fc063

commit ab8a0b5cc06c23cea99124ef60d717ac198fc063
Author: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>
Date:   Wed Aug 21 17:14:46 2024 +0200

    Loop on expansion if a new export has been defined
    
    When a use statement requires a reexported item it cannot find it in
    the same pass, an additional pass shall be performed. This means we need
    to detect whether a new item has been reexported and resolve until the
    end.
    
    gcc/rust/ChangeLog:
    
            * resolve/rust-early-name-resolver-2.0.cc (Early::Early): Add dirty
            flag initialization.
            (Early::go): Set dirty flag using top level resolver.
            * resolve/rust-early-name-resolver-2.0.h: Add dirty flag.
            * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::TopLevel):
            Initialize dirty flag.
            (TopLevel::insert_or_error_out): Set dirty flag on successful
            namespace modification.
            * resolve/rust-toplevel-name-resolver-2.0.h: Add dirty flag.
            * rust-session-manager.cc (Session::expansion): Modify fixed point
            condition to include name resolution modifications.
    
    Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>

Diff:
---
 gcc/rust/resolve/rust-early-name-resolver-2.0.cc    | 4 +++-
 gcc/rust/resolve/rust-early-name-resolver-2.0.h     | 4 ++++
 gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc | 7 ++++---
 gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h  | 6 ++++++
 gcc/rust/rust-session-manager.cc                    | 5 ++++-
 5 files changed, 21 insertions(+), 5 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 fe6f5761c282..402af27c47be 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -26,7 +26,8 @@
 namespace Rust {
 namespace Resolver2_0 {
 
-Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
+Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx), dirty 
(false)
+{}
 
 void
 Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
@@ -61,6 +62,7 @@ Early::go (AST::Crate &crate)
   // Once this is done, we finalize their resolution
   FinalizeImports (std::move (import_mappings), toplevel, ctx).go (crate);
 
+  dirty = toplevel.is_dirty ();
   // We now proceed with resolving macros, which can be nested in almost any
   // items
   textual_scope.push ();
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 c97caaa40b32..dd199cc29090 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -34,9 +34,13 @@ class Early : public DefaultResolver
 {
   using DefaultResolver::visit;
 
+  bool dirty;
+
 public:
   Early (NameResolutionContext &ctx);
 
+  bool is_dirty () { return dirty; }
+
   void go (AST::Crate &crate);
 
   const std::vector<Error> &get_macro_resolve_errors () const
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 b4b1a851ea58..ea64e2526920 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -27,7 +27,7 @@ namespace Rust {
 namespace Resolver2_0 {
 
 TopLevel::TopLevel (NameResolutionContext &resolver)
-  : DefaultResolver (resolver)
+  : DefaultResolver (resolver), dirty (false)
 {}
 
 template <typename T>
@@ -47,8 +47,9 @@ TopLevel::insert_or_error_out (const Identifier &identifier,
   node_locations.emplace (node_id, locus);
 
   auto result = ctx.insert (identifier, node_id, ns);
-
-  if (!result && result.error ().existing != node_id)
+  if (result)
+    dirty = true;
+  else if (result.error ().existing != node_id)
     {
       rich_location rich_loc (line_table, locus);
       rich_loc.add_range (node_locations[result.error ().existing]);
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 fd26891162ed..7309e70bc90d 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -43,6 +43,8 @@ public:
 
   void go (AST::Crate &crate);
 
+  bool is_dirty () { return dirty; }
+
   // Each import will be transformed into an instance of `ImportKind`, a class
   // representing some of the data we need to resolve in the
   // `EarlyNameResolver`. Basically, for each `UseTree` that we see in
@@ -129,6 +131,10 @@ public:
                            Namespace ns);
 
 private:
+  // If a new export has been defined whilst visiting the visitor is considered
+  // dirty
+  bool dirty;
+
   // FIXME: Do we move these to our mappings?
   std::unordered_map<NodeId, location_t> node_locations;
 
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 56c8bdabd80b..2cc20ec0266f 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -928,18 +928,21 @@ Session::expansion (AST::Crate &crate, 
Resolver2_0::NameResolutionContext &ctx)
       if (saw_errors ())
        break;
 
+      bool visitor_dirty = false;
+
       if (flag_name_resolution_2_0)
        {
          Resolver2_0::Early early (ctx);
          early.go (crate);
          macro_errors = early.get_macro_resolve_errors ();
+         visitor_dirty = early.is_dirty ();
        }
       else
        Resolver::EarlyNameResolver ().go (crate);
 
       ExpandVisitor (expander).go (crate);
 
-      fixed_point_reached = !expander.has_changed ();
+      fixed_point_reached = !expander.has_changed () && !visitor_dirty;
       expander.reset_changed_state ();
       iterations++;

Reply via email to