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