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 771 : 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 771 : auto args = std::vector<std::unique_ptr<Expr>> ();
42 771 : args.emplace_back (std::move (to_clone));
43 :
44 : // FIXME: Misses :: prefix to avoid collision with potential core module
45 4626 : return builder.qualified_call ({builder.get_path_start (), "clone", "Clone",
46 771 : "clone"},
47 1542 : std::move (args));
48 771 : }
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 314 : DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
58 : {
59 314 : auto block = std::unique_ptr<BlockExpr> (
60 314 : new BlockExpr ({}, std::move (clone_expr), {}, {}, tl::nullopt, loc, loc));
61 314 : auto big_self_type = builder.single_type_path ("Self");
62 :
63 314 : std::vector<std::unique_ptr<Param>> params;
64 :
65 314 : params.emplace_back (new SelfParam (tl::nullopt,
66 314 : /* is_mut */ false, loc));
67 :
68 314 : return std::unique_ptr<AssociatedItem> (
69 314 : new Function ({"clone"}, builder.fn_qualifiers (), /* generics */ {},
70 : /* function params */ std::move (params),
71 628 : std::move (big_self_type), WhereClause::create_empty (),
72 942 : std::move (block), Visibility::create_private (), {}, loc));
73 314 : }
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 314 : 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 314 : auto clone_trait_path
89 314 : = [this] () { return builder.type_path (LangItem::Kind::CLONE); };
90 :
91 314 : auto trait_items = vec (std::move (clone_fn));
92 :
93 725 : auto generics = setup_impl_generics (name, type_generics, [&, this] () {
94 97 : return builder.trait_bound (clone_trait_path ());
95 314 : });
96 :
97 628 : return builder.trait_impl (clone_trait_path (),
98 : std::move (generics.self_type),
99 : std::move (trait_items),
100 628 : std::move (generics.impl));
101 314 : }
102 :
103 314 : DeriveClone::DeriveClone (location_t loc, Builder::Source item_source)
104 314 : : DeriveVisitor (loc, item_source), expanded (nullptr)
105 314 : {}
106 :
107 : std::unique_ptr<AST::Item>
108 314 : DeriveClone::go (Item &item)
109 : {
110 314 : item.accept_vis (*this);
111 :
112 314 : rust_assert (expanded);
113 :
114 314 : return std::move (expanded);
115 : }
116 :
117 : void
118 92 : DeriveClone::visit_tuple (TupleStruct &item)
119 : {
120 92 : auto cloned_fields = std::vector<std::unique_ptr<Expr>> ();
121 :
122 538 : for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
123 446 : cloned_fields.emplace_back (
124 892 : clone_call (builder.ref (builder.tuple_idx ("self", idx))));
125 :
126 92 : auto path = std::unique_ptr<Expr> (new PathInExpression (
127 276 : builder.path_in_expression ({item.get_identifier ().as_string ()})));
128 92 : auto constructor = builder.call (std::move (path), std::move (cloned_fields));
129 :
130 184 : expanded = clone_impl (clone_fn (std::move (constructor)),
131 92 : item.get_identifier ().as_string (),
132 184 : item.get_generic_params ());
133 92 : }
134 :
135 : void
136 179 : DeriveClone::visit_struct (StructStruct &item)
137 : {
138 179 : if (item.is_unit_struct ())
139 : {
140 39 : auto unit_ctor
141 78 : = builder.struct_expr_struct (item.get_struct_name ().as_string ());
142 78 : expanded = clone_impl (clone_fn (std::move (unit_ctor)),
143 39 : item.get_struct_name ().as_string (),
144 78 : item.get_generic_params ());
145 39 : return;
146 39 : }
147 :
148 140 : auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
149 400 : for (auto &field : item.get_fields ())
150 : {
151 520 : auto name = field.get_field_name ().as_string ();
152 260 : auto expr = clone_call (
153 520 : builder.ref (builder.field_access (builder.identifier ("self"), name)));
154 :
155 260 : cloned_fields.emplace_back (
156 520 : builder.struct_expr_field (std::move (name), std::move (expr)));
157 260 : }
158 :
159 280 : auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
160 280 : std::move (cloned_fields));
161 280 : expanded = clone_impl (clone_fn (std::move (ctor)),
162 140 : item.get_struct_name ().as_string (),
163 280 : item.get_generic_params ());
164 140 : }
165 :
166 : MatchCase
167 77 : DeriveClone::clone_enum_identifier (PathInExpression variant_path,
168 : const std::unique_ptr<EnumItem> &variant)
169 : {
170 77 : auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
171 77 : std::unique_ptr<Pattern> (new PathInExpression (
172 77 : variant_path.get_segments (), {}, variant_path.get_locus (),
173 154 : variant_path.opening_scope_resolution ())),
174 154 : false, false, loc));
175 77 : auto expr = std::unique_ptr<Expr> (
176 77 : new PathInExpression (variant_path.get_segments (), {},
177 : variant_path.get_locus (),
178 77 : variant_path.opening_scope_resolution ()));
179 :
180 77 : return builder.match_case (std::move (pattern), std::move (expr));
181 77 : }
182 :
183 : MatchCase
184 43 : DeriveClone::clone_enum_tuple (PathInExpression variant_path,
185 : const EnumItemTuple &variant)
186 : {
187 43 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
188 43 : auto cloned_patterns = std::vector<std::unique_ptr<Expr>> ();
189 :
190 95 : 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 52 : auto pattern_str = "__self_" + std::to_string (i);
197 :
198 104 : 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 52 : cloned_patterns.emplace_back (
203 156 : clone_call (builder.ref (builder.identifier (pattern_str))));
204 52 : }
205 :
206 43 : auto pattern_items = std::unique_ptr<TupleStructItems> (
207 43 : new TupleStructItemsNoRest (std::move (patterns)));
208 :
209 43 : auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
210 43 : std::unique_ptr<Pattern> (new TupleStructPattern (
211 86 : PathInExpression (variant_path.get_segments (), {},
212 : variant_path.get_locus (),
213 86 : variant_path.opening_scope_resolution ()),
214 129 : std::move (pattern_items))),
215 86 : false, false, loc));
216 :
217 43 : auto expr = builder.call (std::unique_ptr<Expr> (new PathInExpression (
218 43 : variant_path.get_segments (), {},
219 : variant_path.get_locus (),
220 86 : variant_path.opening_scope_resolution ())),
221 86 : std::move (cloned_patterns));
222 :
223 43 : return builder.match_case (std::move (pattern), std::move (expr));
224 43 : }
225 :
226 : MatchCase
227 10 : DeriveClone::clone_enum_struct (PathInExpression variant_path,
228 : const EnumItemStruct &variant)
229 : {
230 10 : auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> ();
231 10 : 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 23 : 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 13 : field_patterns.emplace_back (
272 13 : std::unique_ptr<StructPatternField> (new StructPatternFieldIdent (
273 26 : field.get_field_name (), false /* is_ref? true? */, false, {}, loc)));
274 :
275 13 : cloned_fields.emplace_back (
276 13 : std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue (
277 26 : field.get_field_name (),
278 26 : clone_call (builder.ref (
279 39 : builder.identifier (field.get_field_name ().as_string ()))),
280 39 : {}, loc)));
281 : }
282 :
283 10 : auto pattern_elts = StructPatternElements (std::move (field_patterns));
284 :
285 10 : auto pattern = std::unique_ptr<Pattern> (
286 10 : new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
287 20 : variant_path, loc, pattern_elts)),
288 20 : false, false, loc));
289 :
290 10 : PathInExpression new_path (variant_path.get_segments (),
291 10 : variant_path.get_outer_attrs (),
292 : variant_path.get_locus (),
293 20 : variant_path.opening_scope_resolution ());
294 :
295 10 : auto expr = std::unique_ptr<Expr> (
296 10 : new StructExprStructFields (new_path, std::move (cloned_fields), loc));
297 :
298 10 : return builder.match_case (std::move (pattern), std::move (expr));
299 20 : }
300 :
301 : void
302 41 : 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 41 : auto cases = std::vector<MatchCase> ();
311 :
312 171 : for (const auto &variant : item.get_variants ())
313 : {
314 130 : auto path
315 260 : = builder.variant_path (item.get_identifier ().as_string (),
316 130 : variant->get_identifier ().as_string ());
317 :
318 130 : 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 77 : case EnumItem::Kind::Identifier:
323 77 : case EnumItem::Kind::Discriminant:
324 154 : cases.emplace_back (clone_enum_identifier (path, variant));
325 77 : break;
326 43 : case EnumItem::Kind::Tuple:
327 86 : cases.emplace_back (
328 86 : clone_enum_tuple (path, static_cast<EnumItemTuple &> (*variant)));
329 43 : break;
330 10 : case EnumItem::Kind::Struct:
331 20 : cases.emplace_back (
332 20 : clone_enum_struct (path, static_cast<EnumItemStruct &> (*variant)));
333 10 : break;
334 : }
335 130 : }
336 :
337 : // match self { ... }
338 41 : auto match = builder.match (builder.identifier ("self"), std::move (cases));
339 :
340 123 : expanded = clone_impl (clone_fn (std::move (match)),
341 41 : item.get_identifier ().as_string (),
342 82 : item.get_generic_params ());
343 41 : }
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
|