Branch data Line data Source code
1 : : // Copyright (C) 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-default.h"
20 : : #include "rust-ast.h"
21 : : #include "rust-diagnostics.h"
22 : : #include "rust-path.h"
23 : : #include "rust-system.h"
24 : :
25 : : namespace Rust {
26 : : namespace AST {
27 : :
28 : 15 : DeriveDefault::DeriveDefault (location_t loc)
29 : 15 : : DeriveVisitor (loc), expanded (nullptr)
30 : 15 : {}
31 : :
32 : : std::unique_ptr<Item>
33 : 15 : DeriveDefault::go (Item &item)
34 : : {
35 : 15 : item.accept_vis (*this);
36 : :
37 : 15 : rust_assert (expanded);
38 : :
39 : 15 : return std::move (expanded);
40 : : }
41 : :
42 : : std::unique_ptr<Expr>
43 : 17 : DeriveDefault::default_call (std::unique_ptr<Type> &&type)
44 : : {
45 : 17 : auto default_trait = builder.type_path ({"core", "default", "Default"}, true);
46 : :
47 : 17 : auto default_fn
48 : 34 : = builder.qualified_path_in_expression (std::move (type), default_trait,
49 : 51 : builder.path_segment ("default"));
50 : :
51 : 17 : return builder.call (std::move (default_fn));
52 : 17 : }
53 : :
54 : : std::unique_ptr<AssociatedItem>
55 : 15 : DeriveDefault::default_fn (std::unique_ptr<Expr> &&return_expr)
56 : : {
57 : 15 : auto self_ty
58 : 15 : = std::unique_ptr<Type> (new TypePath (builder.type_path ("Self")));
59 : :
60 : 15 : auto block = std::unique_ptr<BlockExpr> (
61 : 15 : new BlockExpr ({}, std::move (return_expr), {}, {}, tl::nullopt, loc, loc));
62 : :
63 : 30 : return builder.function ("default", {}, std::move (self_ty),
64 : 15 : std::move (block));
65 : 15 : }
66 : :
67 : : std::unique_ptr<Item>
68 : 15 : DeriveDefault::default_impl (
69 : : std::unique_ptr<AssociatedItem> &&default_fn, std::string name,
70 : : const std::vector<std::unique_ptr<GenericParam>> &type_generics)
71 : : {
72 : 15 : auto default_path = builder.type_path ({"core", "default", "Default"}, true);
73 : :
74 : 15 : auto trait_items = vec (std::move (default_fn));
75 : :
76 : 15 : auto generics = setup_impl_generics (name, type_generics,
77 : 30 : builder.trait_bound (default_path));
78 : :
79 : 30 : return builder.trait_impl (default_path, std::move (generics.self_type),
80 : : std::move (trait_items),
81 : 15 : std::move (generics.impl));
82 : 15 : }
83 : :
84 : : void
85 : 8 : DeriveDefault::visit_struct (StructStruct &item)
86 : : {
87 : 8 : if (item.is_unit_struct ())
88 : : {
89 : 0 : auto unit_ctor
90 : 0 : = builder.struct_expr_struct (item.get_struct_name ().as_string ());
91 : 0 : expanded = default_impl (default_fn (std::move (unit_ctor)),
92 : 0 : item.get_struct_name ().as_string (),
93 : 0 : item.get_generic_params ());
94 : 0 : return;
95 : 0 : }
96 : :
97 : 8 : auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
98 : 18 : for (auto &field : item.get_fields ())
99 : : {
100 : 20 : auto name = field.get_field_name ().as_string ();
101 : 10 : auto type = field.get_field_type ().reconstruct ();
102 : 10 : auto expr = default_call (std::move (type));
103 : :
104 : 10 : cloned_fields.emplace_back (
105 : 20 : builder.struct_expr_field (std::move (name), std::move (expr)));
106 : 10 : }
107 : :
108 : 16 : auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
109 : 16 : std::move (cloned_fields));
110 : :
111 : 16 : expanded = default_impl (default_fn (std::move (ctor)),
112 : 8 : item.get_struct_name ().as_string (),
113 : 16 : item.get_generic_params ());
114 : 8 : }
115 : :
116 : : void
117 : 7 : DeriveDefault::visit_tuple (TupleStruct &tuple_item)
118 : : {
119 : 7 : auto defaulted_fields = std::vector<std::unique_ptr<Expr>> ();
120 : :
121 : 14 : for (auto &field : tuple_item.get_fields ())
122 : : {
123 : 7 : auto type = field.get_field_type ().reconstruct ();
124 : :
125 : 7 : defaulted_fields.emplace_back (default_call (std::move (type)));
126 : 7 : }
127 : :
128 : 7 : auto return_expr
129 : 14 : = builder.call (builder.identifier (
130 : 7 : tuple_item.get_struct_name ().as_string ()),
131 : 14 : std::move (defaulted_fields));
132 : :
133 : 14 : expanded = default_impl (default_fn (std::move (return_expr)),
134 : 7 : tuple_item.get_struct_name ().as_string (),
135 : 14 : tuple_item.get_generic_params ());
136 : 7 : }
137 : :
138 : : void
139 : 0 : DeriveDefault::visit_enum (Enum &enum_item)
140 : : {
141 : : // This is no longer the case in later Rust versions where you can choose a
142 : : // default variant to emit using the `#[default]` attribute:
143 : : //
144 : : // ```rust
145 : : // #[derive(Default)]
146 : : // enum Baz {
147 : : // #[default]
148 : : // A,
149 : : // B(i32),
150 : : // C { a: i32 }
151 : : // }
152 : : // ```
153 : : //
154 : : // will emit the following impl
155 : : //
156 : : // ```rust
157 : : // impl ::core::default::Default for Baz {
158 : : // #[inline]
159 : : // fn default() -> Baz { Self::A }
160 : : // }
161 : : // ```
162 : 0 : rust_error_at (loc, ErrorCode::E0665,
163 : : "%<Default%> cannot be derived for enums, only structs");
164 : 0 : }
165 : :
166 : : void
167 : 0 : DeriveDefault::visit_union (Union &enum_item)
168 : : {
169 : 0 : rust_error_at (loc, "derive(Default) cannot be used on unions");
170 : 0 : }
171 : :
172 : : } // namespace AST
173 : : } // namespace Rust
|