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