]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: ast: Implement reconstruct() logic for Path hierarchy
authorJayant Chauhan <0001jayant@gmail.com>
Fri, 16 Jan 2026 17:34:00 +0000 (23:04 +0530)
committerArthur Cohen <arthur.cohen@embecosm.com>
Fri, 20 Mar 2026 17:10:39 +0000 (18:10 +0100)
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 <0001jayant@gmail.com>
gcc/rust/ast/rust-path.h
gcc/rust/expand/rust-derive-cmp-common.cc

index 2e13bea08514b680f0cfdd3d595529451eb8edf1..09baba1d8e2099d7bd41f7ba5c6bfe244a581777 100644 (file)
@@ -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);
   }
index 99100023d36c27fd0a8747668672724b1b3aed22..3b8bf6da6e0395e294b5b02bf0cd0859b61a6a0d 100644 (file)
@@ -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));