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 : #ifndef RUST_COMPILE_VAR_DECL
20 : #define RUST_COMPILE_VAR_DECL
21 :
22 : #include "rust-compile-base.h"
23 : #include "rust-compile-type.h"
24 : #include "rust-hir-visitor.h"
25 :
26 : namespace Rust {
27 : namespace Compile {
28 :
29 27438 : class CompileVarDecl : public HIRCompileBase, public HIR::HIRPatternVisitor
30 : {
31 : using HIR::HIRPatternVisitor::visit;
32 :
33 : public:
34 13719 : static std::vector<Bvariable *> compile (tree fndecl, tree translated_type,
35 : HIR::Pattern *pattern, Context *ctx)
36 : {
37 13719 : CompileVarDecl compiler (ctx, fndecl, translated_type);
38 13719 : pattern->accept_vis (compiler);
39 13719 : return compiler.vars;
40 13719 : }
41 :
42 12993 : void visit (HIR::IdentifierPattern &pattern) override
43 : {
44 12993 : if (!pattern.is_mut ())
45 12026 : translated_type = Backend::immutable_type (translated_type);
46 :
47 12993 : tree bind_tree = ctx->peek_enclosing_scope ();
48 25986 : std::string identifier = pattern.get_identifier ().as_string ();
49 12993 : tree decl
50 12993 : = build_decl (pattern.get_locus (), VAR_DECL,
51 : Backend::get_identifier_node (identifier), translated_type);
52 12993 : DECL_CONTEXT (decl) = fndecl;
53 :
54 12993 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
55 12993 : tree block_tree = BIND_EXPR_BLOCK (bind_tree);
56 12993 : gcc_assert (TREE_CODE (block_tree) == BLOCK);
57 12993 : DECL_CHAIN (decl) = BLOCK_VARS (block_tree);
58 12993 : BLOCK_VARS (block_tree) = decl;
59 12993 : BIND_EXPR_VARS (bind_tree) = BLOCK_VARS (block_tree);
60 :
61 12993 : rust_preserve_from_gc (decl);
62 12993 : Bvariable *var = new Bvariable (decl);
63 :
64 12993 : HirId stmt_id = pattern.get_mappings ().get_hirid ();
65 12993 : ctx->insert_var_decl (stmt_id, var);
66 :
67 12993 : vars.push_back (var);
68 :
69 12993 : if (pattern.has_subpattern ())
70 : {
71 16 : auto subpattern_vars
72 : = CompileVarDecl::compile (fndecl, translated_type,
73 16 : &pattern.get_subpattern (), ctx);
74 16 : vars.insert (vars.end (), subpattern_vars.begin (),
75 : subpattern_vars.end ());
76 16 : }
77 12993 : }
78 :
79 375 : void visit (HIR::TuplePattern &pattern) override
80 : {
81 375 : rust_assert (TREE_CODE (translated_type) == RECORD_TYPE);
82 375 : switch (pattern.get_items ().get_item_type ())
83 : {
84 370 : case HIR::TuplePatternItems::ItemType::NO_REST:
85 370 : {
86 370 : auto &items_no_rest = static_cast<HIR::TuplePatternItemsNoRest &> (
87 370 : pattern.get_items ());
88 :
89 370 : tree field = TYPE_FIELDS (translated_type);
90 1122 : for (auto &sub : items_no_rest.get_patterns ())
91 : {
92 752 : gcc_assert (field != NULL_TREE);
93 752 : tree sub_ty = TREE_TYPE (field);
94 752 : CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
95 752 : field = DECL_CHAIN (field);
96 : }
97 : }
98 : break;
99 :
100 5 : case HIR::TuplePatternItems::ItemType::HAS_REST:
101 5 : {
102 5 : auto &items_has_rest = static_cast<HIR::TuplePatternItemsHasRest &> (
103 5 : pattern.get_items ());
104 :
105 : // count total fields in translated_type
106 5 : size_t total_fields = 0;
107 17 : for (tree t = TYPE_FIELDS (translated_type); t; t = DECL_CHAIN (t))
108 : {
109 12 : total_fields++;
110 : }
111 :
112 : // process lower patterns
113 5 : tree field = TYPE_FIELDS (translated_type);
114 8 : for (auto &sub : items_has_rest.get_lower_patterns ())
115 : {
116 3 : gcc_assert (field != NULL_TREE);
117 3 : tree sub_ty = TREE_TYPE (field);
118 3 : CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
119 3 : field = DECL_CHAIN (field);
120 : }
121 :
122 : // process upper patterns
123 5 : if (!items_has_rest.get_upper_patterns ().empty ())
124 : {
125 3 : size_t upper_start
126 3 : = total_fields - items_has_rest.get_upper_patterns ().size ();
127 3 : field = TYPE_FIELDS (translated_type);
128 8 : for (size_t i = 0; i < upper_start; i++)
129 : {
130 5 : field = DECL_CHAIN (field);
131 5 : gcc_assert (field != NULL_TREE);
132 : }
133 :
134 6 : for (auto &sub : items_has_rest.get_upper_patterns ())
135 : {
136 3 : gcc_assert (field != NULL_TREE);
137 3 : tree sub_ty = TREE_TYPE (field);
138 3 : CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
139 3 : field = DECL_CHAIN (field);
140 : }
141 : }
142 : }
143 : break;
144 :
145 : default:
146 : break;
147 : }
148 375 : }
149 :
150 32 : void visit (HIR::StructPattern &pattern) override
151 : {
152 : // lookup the type
153 32 : TyTy::BaseType *lookup = nullptr;
154 32 : bool ok = ctx->get_tyctx ()->lookup_type (
155 32 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
156 32 : rust_assert (ok);
157 :
158 32 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
159 32 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
160 :
161 : // only structs and single-variant enums are irrefutable, this check should
162 : // already be handled by type check
163 32 : rust_assert (adt->number_of_variants () == 1);
164 :
165 32 : int variant_index = 0;
166 32 : TyTy::VariantDef *variant = nullptr;
167 32 : if (adt->is_enum ())
168 : {
169 : // lookup the variant
170 0 : HirId variant_id = UNKNOWN_HIRID;
171 0 : bool ok = ctx->get_tyctx ()->lookup_variant_definition (
172 0 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
173 0 : rust_assert (ok);
174 :
175 0 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
176 0 : rust_assert (ok);
177 : }
178 : else
179 : {
180 32 : variant = adt->get_variants ().at (0);
181 : }
182 :
183 32 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
184 65 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
185 : {
186 33 : switch (field->get_item_type ())
187 : {
188 8 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
189 8 : {
190 8 : HIR::StructPatternFieldTuplePat &tuple_pat
191 8 : = static_cast<HIR::StructPatternFieldTuplePat &> (*field);
192 8 : TyTy::StructFieldType *field_ty = nullptr;
193 8 : ok = variant->lookup_field (std::to_string (
194 : tuple_pat.get_index ()),
195 : &field_ty, nullptr);
196 8 : rust_assert (ok);
197 8 : tree sub_ty
198 8 : = TyTyResolveCompile::compile (ctx,
199 8 : field_ty->get_field_type ());
200 8 : auto sub_vars
201 : = CompileVarDecl::compile (fndecl, sub_ty,
202 8 : &tuple_pat.get_tuple_pattern (),
203 8 : ctx);
204 8 : vars.insert (vars.end (), sub_vars.begin (), sub_vars.end ());
205 8 : }
206 8 : break;
207 17 : case HIR::StructPatternField::ItemType::IDENT_PAT:
208 17 : {
209 17 : HIR::StructPatternFieldIdentPat &ident_pat
210 17 : = static_cast<HIR::StructPatternFieldIdentPat &> (*field);
211 17 : TyTy::StructFieldType *field_ty = nullptr;
212 17 : ok = variant->lookup_field (
213 17 : ident_pat.get_identifier ().as_string (), &field_ty, nullptr);
214 17 : rust_assert (ok);
215 17 : tree sub_ty
216 17 : = TyTyResolveCompile::compile (ctx,
217 17 : field_ty->get_field_type ());
218 17 : auto sub_vars
219 : = CompileVarDecl::compile (fndecl, sub_ty,
220 17 : &ident_pat.get_pattern (), ctx);
221 17 : vars.insert (vars.end (), sub_vars.begin (), sub_vars.end ());
222 17 : }
223 17 : break;
224 8 : case HIR::StructPatternField::ItemType::IDENT:
225 8 : {
226 8 : HIR::StructPatternFieldIdent &ident
227 8 : = static_cast<HIR::StructPatternFieldIdent &> (*field);
228 8 : TyTy::StructFieldType *field_ty = nullptr;
229 8 : ok = variant->lookup_field (ident.get_identifier ().as_string (),
230 : &field_ty, nullptr);
231 8 : rust_assert (ok);
232 8 : tree sub_ty
233 8 : = TyTyResolveCompile::compile (ctx,
234 8 : field_ty->get_field_type ());
235 :
236 : // code below is pretty much copied from
237 : // visit(IdentifierPattern) above
238 8 : if (!ident.is_mut ())
239 8 : sub_ty = Backend::immutable_type (sub_ty);
240 :
241 8 : tree bind_tree = ctx->peek_enclosing_scope ();
242 16 : std::string identifier = ident.get_identifier ().as_string ();
243 8 : tree decl = build_decl (ident.get_locus (), VAR_DECL,
244 : Backend::get_identifier_node (identifier),
245 : sub_ty);
246 8 : DECL_CONTEXT (decl) = fndecl;
247 8 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
248 8 : tree block_tree = BIND_EXPR_BLOCK (bind_tree);
249 8 : gcc_assert (TREE_CODE (block_tree) == BLOCK);
250 8 : DECL_CHAIN (decl) = BLOCK_VARS (block_tree);
251 8 : BLOCK_VARS (block_tree) = decl;
252 8 : BIND_EXPR_VARS (bind_tree) = BLOCK_VARS (block_tree);
253 8 : rust_preserve_from_gc (decl);
254 8 : Bvariable *var = new Bvariable (decl);
255 :
256 8 : HirId stmt_id = ident.get_mappings ().get_hirid ();
257 8 : ctx->insert_var_decl (stmt_id, var);
258 8 : vars.push_back (var);
259 8 : }
260 8 : break;
261 : }
262 : }
263 32 : }
264 :
265 : // Empty visit for unused Pattern HIR nodes.
266 0 : void visit (HIR::AltPattern &) override {}
267 0 : void visit (HIR::LiteralPattern &) override {}
268 0 : void visit (HIR::PathInExpression &) override {}
269 0 : void visit (HIR::QualifiedPathInExpression &) override {}
270 0 : void visit (HIR::RangePattern &) override {}
271 3 : void visit (HIR::ReferencePattern &) override {}
272 0 : void visit (HIR::SlicePattern &) override {}
273 1 : void visit (HIR::TupleStructPattern &) override {}
274 315 : void visit (HIR::WildcardPattern &) override {}
275 :
276 : private:
277 13719 : CompileVarDecl (Context *ctx, tree fndecl, tree translated_type)
278 13719 : : HIRCompileBase (ctx), fndecl (fndecl), translated_type (translated_type)
279 : {}
280 :
281 : tree fndecl;
282 : tree translated_type;
283 :
284 : std::vector<Bvariable *> vars;
285 : };
286 :
287 : } // namespace Compile
288 : } // namespace Rust
289 :
290 : #endif // RUST_COMPILE_VAR_DECL
|