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