Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-derive-clone.h"
20 : #include "rust-ast.h"
21 : #include "rust-expr.h"
22 : #include "rust-item.h"
23 : #include "rust-path.h"
24 : #include "rust-pattern.h"
25 : #include "rust-system.h"
26 :
27 : namespace Rust {
28 : namespace AST {
29 :
30 : std::unique_ptr<Expr>
31 684 : DeriveClone::clone_call (std::unique_ptr<Expr> &&to_clone)
32 : {
33 : // Interestingly, later versions of Rust have a `clone_fn` lang item which
34 : // corresponds to this. But because we are first targeting 1.49, we cannot use
35 : // it yet. Once we target a new, more recent version of the language, we'll
36 : // have figured out how to compile and distribute `core`, meaning we'll be
37 : // able to directly call `::core::clone::Clone::clone()`
38 :
39 : // Not sure how to call it properly in the meantime...
40 :
41 684 : auto args = std::vector<std::unique_ptr<Expr>> ();
42 684 : args.emplace_back (std::move (to_clone));
43 :
44 : // FIXME: Misses :: prefix to avoid collision with potential core module
45 4104 : return builder.qualified_call ({builder.get_path_start (), "clone", "Clone",
46 684 : "clone"},
47 1368 : std::move (args));
48 684 : }
49 :
50 : /**
51 : * Create the actual "clone" function of the implementation, so
52 : *
53 : * fn clone(&self) -> Self { <clone_expr> }
54 : *
55 : */
56 : std::unique_ptr<AssociatedItem>
57 243 : DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
58 : {
59 243 : auto block = std::unique_ptr<BlockExpr> (
60 243 : new BlockExpr ({}, std::move (clone_expr), {}, {}, tl::nullopt, loc, loc));
61 243 : auto big_self_type = builder.single_type_path ("Self");
62 :
63 243 : std::vector<std::unique_ptr<Param>> params;
64 :
65 243 : params.emplace_back (new SelfParam (tl::nullopt,
66 243 : /* is_mut */ false, loc));
67 :
68 243 : return std::unique_ptr<AssociatedItem> (
69 243 : new Function ({"clone"}, builder.fn_qualifiers (), /* generics */ {},
70 : /* function params */ std::move (params),
71 486 : std::move (big_self_type), WhereClause::create_empty (),
72 729 : std::move (block), Visibility::create_private (), {}, loc));
73 243 : }
74 :
75 : /**
76 : * Create the Clone trait implementation for a type
77 : *
78 : * impl Clone for <type> {
79 : * <clone_fn>
80 : * }
81 : *
82 : */
83 : std::unique_ptr<Item>
84 243 : DeriveClone::clone_impl (
85 : std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
86 : const std::vector<std::unique_ptr<GenericParam>> &type_generics)
87 : {
88 243 : auto clone_trait_path
89 243 : = [this] () { return builder.type_path (LangItem::Kind::CLONE); };
90 :
91 243 : auto trait_items = vec (std::move (clone_fn));
92 :
93 552 : auto generics = setup_impl_generics (name, type_generics, [&, this] () {
94 66 : return builder.trait_bound (clone_trait_path ());
95 243 : });
96 :
97 486 : return builder.trait_impl (clone_trait_path (),
98 : std::move (generics.self_type),
99 : std::move (trait_items),
100 486 : std::move (generics.impl));
101 243 : }
102 :
103 243 : DeriveClone::DeriveClone (location_t loc, Builder::Source item_source)
104 243 : : DeriveVisitor (loc, item_source), expanded (nullptr)
105 243 : {}
106 :
107 : std::unique_ptr<AST::Item>
108 243 : DeriveClone::go (Item &item)
109 : {
110 243 : item.accept_vis (*this);
111 :
112 243 : rust_assert (expanded);
113 :
114 243 : return std::move (expanded);
115 : }
116 :
117 : void
118 89 : DeriveClone::visit_tuple (TupleStruct &item)
119 : {
120 89 : auto cloned_fields = std::vector<std::unique_ptr<Expr>> ();
121 :
122 532 : for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
123 443 : cloned_fields.emplace_back (
124 886 : clone_call (builder.ref (builder.tuple_idx ("self", idx))));
125 :
126 89 : auto path = std::unique_ptr<Expr> (new PathInExpression (
127 267 : builder.path_in_expression ({item.get_identifier ().as_string ()})));
128 89 : auto constructor = builder.call (std::move (path), std::move (cloned_fields));
129 :
130 178 : expanded = clone_impl (clone_fn (std::move (constructor)),
131 89 : item.get_identifier ().as_string (),
132 178 : item.get_generic_params ());
133 89 : }
134 :
135 : void
136 121 : DeriveClone::visit_struct (StructStruct &item)
137 : {
138 121 : if (item.is_unit_struct ())
139 : {
140 24 : auto unit_ctor
141 48 : = builder.struct_expr_struct (item.get_struct_name ().as_string ());
142 48 : expanded = clone_impl (clone_fn (std::move (unit_ctor)),
143 24 : item.get_struct_name ().as_string (),
144 48 : item.get_generic_params ());
145 24 : return;
146 24 : }
147 :
148 97 : auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
149 288 : for (auto &field : item.get_fields ())
150 : {
151 382 : auto name = field.get_field_name ().as_string ();
152 191 : auto expr = clone_call (
153 382 : builder.ref (builder.field_access (builder.identifier ("self"), name)));
154 :
155 191 : cloned_fields.emplace_back (
156 382 : builder.struct_expr_field (std::move (name), std::move (expr)));
157 191 : }
158 :
159 194 : auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
160 194 : std::move (cloned_fields));
161 194 : expanded = clone_impl (clone_fn (std::move (ctor)),
162 97 : item.get_struct_name ().as_string (),
163 194 : item.get_generic_params ());
164 97 : }
165 :
166 : MatchCase
167 60 : DeriveClone::clone_enum_identifier (PathInExpression variant_path,
168 : const std::unique_ptr<EnumItem> &variant)
169 : {
170 60 : auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
171 60 : std::unique_ptr<Pattern> (new PathInExpression (
172 60 : variant_path.get_segments (), {}, variant_path.get_locus (),
173 120 : variant_path.opening_scope_resolution ())),
174 120 : false, false, loc));
175 60 : auto expr = std::unique_ptr<Expr> (
176 60 : new PathInExpression (variant_path.get_segments (), {},
177 : variant_path.get_locus (),
178 60 : variant_path.opening_scope_resolution ()));
179 :
180 60 : return builder.match_case (std::move (pattern), std::move (expr));
181 60 : }
182 :
183 : MatchCase
184 32 : DeriveClone::clone_enum_tuple (PathInExpression variant_path,
185 : const EnumItemTuple &variant)
186 : {
187 32 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
188 32 : auto cloned_patterns = std::vector<std::unique_ptr<Expr>> ();
189 :
190 71 : for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
191 : {
192 : // The pattern we're creating for each field is `self_<i>` where `i` is
193 : // the index of the field. It doesn't actually matter what we use, as long
194 : // as it's ordered, unique, and that we can reuse it in the match case's
195 : // return expression to clone the field.
196 39 : auto pattern_str = "__self_" + std::to_string (i);
197 :
198 78 : patterns.emplace_back (builder.identifier_pattern (pattern_str));
199 :
200 : // Now, for each tuple's element, we create a new expression calling
201 : // `clone` on it for the match case's return expression
202 39 : cloned_patterns.emplace_back (
203 117 : clone_call (builder.ref (builder.identifier (pattern_str))));
204 39 : }
205 :
206 32 : auto pattern_items = std::unique_ptr<TupleStructItems> (
207 32 : new TupleStructItemsNoRest (std::move (patterns)));
208 :
209 32 : auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
210 32 : std::unique_ptr<Pattern> (new TupleStructPattern (
211 64 : PathInExpression (variant_path.get_segments (), {},
212 : variant_path.get_locus (),
213 64 : variant_path.opening_scope_resolution ()),
214 96 : std::move (pattern_items))),
215 64 : false, false, loc));
216 :
217 32 : auto expr = builder.call (std::unique_ptr<Expr> (new PathInExpression (
218 32 : variant_path.get_segments (), {},
219 : variant_path.get_locus (),
220 64 : variant_path.opening_scope_resolution ())),
221 64 : std::move (cloned_patterns));
222 :
223 32 : return builder.match_case (std::move (pattern), std::move (expr));
224 32 : }
225 :
226 : MatchCase
227 9 : DeriveClone::clone_enum_struct (PathInExpression variant_path,
228 : const EnumItemStruct &variant)
229 : {
230 9 : auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> ();
231 9 : auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
232 :
233 : #if 0
234 : // NOTE: We currently do not support compiling struct patterns where an
235 : // identifier is assigned a new pattern, e.g. Bloop { f0: x }
236 : // This is the code we should eventually produce as it mimics what rustc does
237 : // - which is probably here for a good reason. In the meantime, we can just
238 : // use the field's identifier as the pattern: Bloop { f0 }
239 : // We can then clone the field directly instead of calling `clone()` on the
240 : // new pattern.
241 : // TODO: Figure out if that is actually needed and why rustc does it?
242 :
243 : for (size_t i = 0; i < variant.get_struct_fields ().size (); i++)
244 : {
245 : auto &field = variant.get_struct_fields ()[i];
246 :
247 : // Just like for tuples, the pattern we're creating for each field is
248 : // `self_<i>` where `i` is the index of the field. It doesn't actually
249 : // matter what we use, as long as it's ordered, unique, and that we can
250 : // reuse it in the match case's return expression to clone the field.
251 : auto pattern_str = "__self_" + std::to_string (i);
252 :
253 : field_patterns.emplace_back (
254 : std::unique_ptr<StructPatternField> (new StructPatternFieldIdentPat (
255 : field.get_field_name (), builder.identifier_pattern (pattern_str), {},
256 : loc)));
257 :
258 : cloned_fields.emplace_back (
259 : std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue (
260 : field.get_field_name (),
261 : clone_call (builder.ref (builder.identifier (pattern_str))), {},
262 : loc)));
263 : }
264 : #endif
265 :
266 20 : for (const auto &field : variant.get_struct_fields ())
267 : {
268 : // We match on the struct's fields, and then recreate an instance of that
269 : // struct, cloning each field
270 :
271 11 : field_patterns.emplace_back (
272 11 : std::unique_ptr<StructPatternField> (new StructPatternFieldIdent (
273 22 : field.get_field_name (), false /* is_ref? true? */, false, {}, loc)));
274 :
275 11 : cloned_fields.emplace_back (
276 11 : std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue (
277 22 : field.get_field_name (),
278 22 : clone_call (builder.ref (
279 33 : builder.identifier (field.get_field_name ().as_string ()))),
280 33 : {}, loc)));
281 : }
282 :
283 9 : auto pattern_elts = StructPatternElements (std::move (field_patterns));
284 :
285 9 : auto pattern = std::unique_ptr<Pattern> (
286 9 : new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
287 18 : variant_path, loc, pattern_elts)),
288 18 : false, false, loc));
289 :
290 9 : PathInExpression new_path (variant_path.get_segments (),
291 9 : variant_path.get_outer_attrs (),
292 : variant_path.get_locus (),
293 18 : variant_path.opening_scope_resolution ());
294 :
295 9 : auto expr = std::unique_ptr<Expr> (
296 9 : new StructExprStructFields (new_path, std::move (cloned_fields), loc));
297 :
298 9 : return builder.match_case (std::move (pattern), std::move (expr));
299 18 : }
300 :
301 : void
302 31 : DeriveClone::visit_enum (Enum &item)
303 : {
304 : // Create an arm for each variant of the enum:
305 : // - For enum item variants (simple identifiers), just create the same
306 : // variant.
307 : // - For struct and tuple variants, destructure the pattern and call clone for
308 : // each field.
309 :
310 31 : auto cases = std::vector<MatchCase> ();
311 :
312 132 : for (const auto &variant : item.get_variants ())
313 : {
314 101 : auto path
315 202 : = builder.variant_path (item.get_identifier ().as_string (),
316 101 : variant->get_identifier ().as_string ());
317 :
318 101 : switch (variant->get_enum_item_kind ())
319 : {
320 : // Identifiers and discriminated variants are the same for a clone - we
321 : // just return the same variant
322 60 : case EnumItem::Kind::Identifier:
323 60 : case EnumItem::Kind::Discriminant:
324 120 : cases.emplace_back (clone_enum_identifier (path, variant));
325 60 : break;
326 32 : case EnumItem::Kind::Tuple:
327 64 : cases.emplace_back (
328 64 : clone_enum_tuple (path, static_cast<EnumItemTuple &> (*variant)));
329 32 : break;
330 9 : case EnumItem::Kind::Struct:
331 18 : cases.emplace_back (
332 18 : clone_enum_struct (path, static_cast<EnumItemStruct &> (*variant)));
333 9 : break;
334 : }
335 101 : }
336 :
337 : // match self { ... }
338 31 : auto match = builder.match (builder.identifier ("self"), std::move (cases));
339 :
340 93 : expanded = clone_impl (clone_fn (std::move (match)),
341 31 : item.get_identifier ().as_string (),
342 62 : item.get_generic_params ());
343 31 : }
344 :
345 : void
346 2 : DeriveClone::visit_union (Union &item)
347 : {
348 : // FIXME: Should be $crate::core::clone::AssertParamIsCopy (or similar)
349 : // (Rust-GCC#3329)
350 :
351 2 : auto copy_path = builder.type_path (LangItem::Kind::COPY);
352 2 : auto sized_path = builder.type_path (LangItem::Kind::SIZED);
353 :
354 2 : auto copy_bound = std::unique_ptr<TypeParamBound> (
355 2 : new TraitBound (copy_path, item.get_locus ()));
356 2 : auto sized_bound = std::unique_ptr<TypeParamBound> (
357 : new TraitBound (sized_path, item.get_locus (), false,
358 2 : true /* opening_question_mark */));
359 :
360 2 : auto bounds = vec (std::move (copy_bound), std::move (sized_bound));
361 :
362 : // struct AssertParamIsCopy<T: Copy + ?Sized> { _t: PhantomData<T> }
363 2 : auto assert_param_is_copy = "AssertParamIsCopy";
364 2 : auto t = std::unique_ptr<GenericParam> (
365 4 : new TypeParam (Identifier ("T"), item.get_locus (), std::move (bounds)));
366 6 : auto assert_param_is_copy_struct = builder.struct_struct (
367 4 : assert_param_is_copy, vec (std::move (t)),
368 : {StructField (
369 6 : Identifier ("_t"),
370 4 : builder.single_generic_type_path (
371 : LangItem::Kind::PHANTOM_DATA,
372 2 : GenericArgs (
373 6 : {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})),
374 6 : Visibility::create_private (), item.get_locus ())});
375 :
376 : // <Self>
377 2 : auto arg = GenericArg::create_type (builder.single_type_path ("Self"));
378 :
379 : // AssertParamIsCopy::<Self>
380 2 : auto type = std::unique_ptr<TypePathSegment> (
381 4 : new TypePathSegmentGeneric (PathIdentSegment (assert_param_is_copy, loc),
382 8 : false, GenericArgs ({}, {arg}, {}, loc), loc));
383 2 : auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> ();
384 2 : type_paths.emplace_back (std::move (type));
385 :
386 2 : auto full_path
387 2 : = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc));
388 :
389 2 : auto tail_expr = builder.deref (builder.identifier ("self"));
390 :
391 2 : auto stmts
392 : = vec (std::move (assert_param_is_copy_struct),
393 2 : builder.let (builder.wildcard (), std::move (full_path), nullptr));
394 :
395 2 : auto block = builder.block (std::move (stmts), std::move (tail_expr));
396 :
397 6 : expanded = clone_impl (clone_fn (std::move (block)),
398 2 : item.get_identifier ().as_string (),
399 4 : item.get_generic_params ());
400 2 : }
401 :
402 : } // namespace AST
403 : } // namespace Rust
|