From: Jayant Chauhan <[email protected]>

This patch implements the `reconstruct` pattern for the `Path` hierarchy and its
constituents (segments, generic args, qualified paths).

Previously, derive expansion macros (like `derive(PartialEq)`) had to manually
rebuild paths field-by-field to ensure fresh NodeIDs. This change moves that
logic into the AST classes themselves, allowing paths to be deeply reconstructed
uniformly. This ensures that expanded code has unique NodeIDs, which is critical
for correct name resolution.

gcc/rust/ChangeLog:

        * ast/rust-path.h (GenericArgsBinding::reconstruct): New method.
        (GenericArg::reconstruct): New method.
        (GenericArgs::reconstruct): New method.
        (PathExprSegment::reconstruct): New method.
        (PathInExpression::reconstruct): New method.
        (TypePathSegmentGeneric::reconstruct_impl): New method.
        (TypePathFunction::reconstruct): New method.
        (TypePathSegmentFunction::reconstruct_impl): New method.
        (QualifiedPathType::reconstruct): New method.
        (QualifiedPathInExpression::reconstruct): New method.
        (QualifiedPathInType::reconstruct_impl): New method.
        * expand/rust-derive-cmp-common.cc (EnumMatchBuilder::tuple): Use 
path.reconstruct().
        (EnumMatchBuilder::strukt): Use path.reconstruct().

Signed-off-by: Jayant Chauhan <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/c4e6d706e616a38b1a2adbcaf5b03a8255d14399

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4395

 gcc/rust/ast/rust-path.h                  | 122 +++++++++++++++++++++-
 gcc/rust/expand/rust-derive-cmp-common.cc |  10 +-
 2 files changed, 125 insertions(+), 7 deletions(-)

diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 2e13bea08..09baba1d8 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -84,6 +84,15 @@ public:
     // and also identifier is empty, but cheaper computation
   }
 
+  GenericArgsBinding reconstruct () const
+  {
+    std::unique_ptr<Type> new_type = nullptr;
+    if (type)
+      new_type = type->reconstruct ();
+
+    return GenericArgsBinding (identifier, std::move (new_type), locus);
+  }
+
   // Creates an error state generic args binding.
   static GenericArgsBinding create_error ()
   {
@@ -190,6 +199,22 @@ public:
     return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, 
locus);
   }
 
+  GenericArg reconstruct () const
+  {
+    switch (kind)
+      {
+      case Kind::Type:
+       return create_type (type->reconstruct ());
+      case Kind::Const:
+       // FIXME: Use reconstruct_expr when available
+       return create_const (expression->clone_expr ());
+      case Kind::Either:
+      default:
+       // For ambiguous or error states, copy constructs are sufficient
+       return GenericArg (*this);
+      }
+  }
+
   GenericArg (const GenericArg &other)
     : path (other.path), kind (other.kind), locus (other.locus)
   {
@@ -460,6 +485,23 @@ public:
 
   ~GenericArgs () = default;
 
+  GenericArgs reconstruct () const
+  {
+    std::vector<GenericArg> new_args;
+    new_args.reserve (generic_args.size ());
+    for (const auto &arg : generic_args)
+      new_args.push_back (arg.reconstruct ());
+
+    std::vector<GenericArgsBinding> new_bindings;
+    new_bindings.reserve (binding_args.size ());
+    for (const auto &binding : binding_args)
+      new_bindings.push_back (binding.reconstruct ());
+
+    // Lifetimes are values, so they can be copied directly
+    return GenericArgs (lifetime_args, std::move (new_args),
+                       std::move (new_bindings), locus);
+  }
+
   // overloaded assignment operator to vector clone
   GenericArgs &operator= (GenericArgs const &other)
   {
@@ -563,6 +605,11 @@ public:
 
   NodeId get_node_id () const { return node_id; }
 
+  PathExprSegment reconstruct () const
+  {
+    return PathExprSegment (segment_name, locus, generic_args.reconstruct ());
+  }
+
   bool is_super_path_seg () const
   {
     return !has_generic_args () && get_ident_segment ().is_super_path_seg ();
@@ -705,6 +752,20 @@ public:
     return convert_to_simple_path (has_opening_scope_resolution);
   }
 
+  std::unique_ptr<PathInExpression> reconstruct () const
+  {
+    std::vector<PathExprSegment> new_segments;
+    new_segments.reserve (segments.size ());
+    for (const auto &seg : segments)
+      new_segments.push_back (seg.reconstruct ());
+
+    auto *new_path
+      = new PathInExpression (std::move (new_segments), outer_attrs, locus,
+                             has_opening_scope_resolution);
+
+    return std::unique_ptr<PathInExpression> (new_path);
+  }
+
   location_t get_locus () const override final { return locus; }
 
   void accept_vis (ASTVisitor &vis) override;
@@ -1004,6 +1065,14 @@ public:
   {
     return new TypePathSegmentGeneric (*this);
   }
+
+  TypePathSegmentGeneric *reconstruct_impl () const override
+  {
+    return new TypePathSegmentGeneric (get_ident_segment (),
+                                      has_separating_scope_resolution,
+                                      generic_args.reconstruct (),
+                                      get_locus ());
+  }
 };
 
 // A function as represented in a type path
@@ -1112,6 +1181,21 @@ public:
     return return_type;
   }
 
+  TypePathFunction reconstruct () const
+  {
+    std::vector<std::unique_ptr<Type>> new_inputs;
+    new_inputs.reserve (inputs.size ());
+    for (const auto &e : inputs)
+      new_inputs.push_back (e->reconstruct ());
+
+    std::unique_ptr<Type> new_ret = nullptr;
+    if (return_type)
+      new_ret = return_type->reconstruct ();
+
+    return TypePathFunction (std::move (new_inputs), locus,
+                            std::move (new_ret));
+  }
+
   location_t get_locus () const { return locus; }
 };
 
@@ -1159,6 +1243,14 @@ public:
   {
     return new TypePathSegmentFunction (*this);
   }
+
+  TypePathSegmentFunction *reconstruct_impl () const override
+  {
+    return new TypePathSegmentFunction (get_ident_segment (),
+                                       has_separating_scope_resolution,
+                                       function_path.reconstruct (),
+                                       get_locus ());
+  }
 };
 
 class TypePath : public TypeNoBounds
@@ -1327,6 +1419,20 @@ public:
   QualifiedPathType (QualifiedPathType &&other) = default;
   QualifiedPathType &operator= (QualifiedPathType &&other) = default;
 
+  QualifiedPathType reconstruct () const
+  {
+    auto new_type = type_to_invoke_on->reconstruct ();
+
+    // trait_path is stored by value, but reconstruct returns a unique_ptr.
+    // We must dereference it to pass to the constructor.
+    // This is safe because the constructor makes its own copy/move.
+    auto new_trait_path_ptr = trait_path.reconstruct ();
+    TypePath *concrete_ptr
+      = static_cast<TypePath *> (new_trait_path_ptr.get ());
+
+    return QualifiedPathType (std::move (new_type), locus, *concrete_ptr);
+  }
+
   // Returns whether the qualified path type has a rebind as clause.
   bool has_as_clause () const { return !trait_path.is_error (); }
 
@@ -1433,6 +1539,20 @@ public:
     return Expr::Kind::QualifiedPathInExpression;
   }
 
+  std::unique_ptr<QualifiedPathInExpression> reconstruct () const
+  {
+    std::vector<PathExprSegment> new_segments;
+    new_segments.reserve (segments.size ());
+    for (const auto &seg : segments)
+      new_segments.push_back (seg.reconstruct ());
+
+    auto *new_path = new QualifiedPathInExpression (path_type.reconstruct (),
+                                                   std::move (new_segments),
+                                                   outer_attrs, locus);
+
+    return std::unique_ptr<QualifiedPathInExpression> (new_path);
+  }
+
 protected:
   /* Use covariance to implement clone function as returning this object
    * rather than base */
@@ -1474,7 +1594,7 @@ protected:
   }
   QualifiedPathInType *reconstruct_impl () const override
   {
-    return new QualifiedPathInType (path_type,
+    return new QualifiedPathInType (path_type.reconstruct (),
                                    associated_segment->reconstruct (),
                                    reconstruct_vec (segments), locus);
   }
diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc 
b/gcc/rust/expand/rust-derive-cmp-common.cc
index 99100023d..3b8bf6da6 100644
--- a/gcc/rust/expand/rust-derive-cmp-common.cc
+++ b/gcc/rust/expand/rust-derive-cmp-common.cc
@@ -96,9 +96,8 @@ EnumMatchBuilder::tuple (EnumItem &variant_raw)
       });
     }
 
-  // TODO: Replace with `reconstruct()` instead of building these twice
   auto self_variant_path = builder.variant_path (enum_path, variant_path);
-  auto other_variant_path = builder.variant_path (enum_path, variant_path);
+  auto other_variant_path = self_variant_path.reconstruct ();
 
   auto self_pattern_items = std::unique_ptr<TupleStructItems> (
     new TupleStructItemsNoRest (std::move (self_patterns)));
@@ -111,7 +110,7 @@ EnumMatchBuilder::tuple (EnumItem &variant_raw)
                          false, false, builder.loc));
   auto other_pattern = std::unique_ptr<Pattern> (new ReferencePattern (
     std::unique_ptr<Pattern> (new TupleStructPattern (
-      other_variant_path, std::move (other_pattern_items))),
+      *other_variant_path, std::move (other_pattern_items))),
     false, false, builder.loc));
 
   auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
@@ -159,9 +158,8 @@ EnumMatchBuilder::strukt (EnumItem &variant_raw)
       });
     }
 
-  // TODO: Replace with `reconstruct()` instead of building these twice
   auto self_variant_path = builder.variant_path (enum_path, variant_path);
-  auto other_variant_path = builder.variant_path (enum_path, variant_path);
+  auto other_variant_path = self_variant_path.reconstruct ();
 
   auto self_elts = StructPatternElements (std::move (self_fields));
   auto other_elts = StructPatternElements (std::move (other_fields));
@@ -172,7 +170,7 @@ EnumMatchBuilder::strukt (EnumItem &variant_raw)
     false, false, builder.loc));
   auto other_pattern = std::unique_ptr<Pattern> (
     new ReferencePattern (std::unique_ptr<Pattern> (
-                           new StructPattern (other_variant_path, builder.loc,
+                           new StructPattern (*other_variant_path, builder.loc,
                                               std::move (other_elts))),
                          false, false, builder.loc));
 

base-commit: 9cb6b939046eeb3983425d930923a3df2a32f07c
-- 
2.53.0

Reply via email to