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