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_CONTEXT
20 : #define RUST_COMPILE_CONTEXT
21 :
22 : #include "optional.h"
23 : #include "rust-system.h"
24 : #include "rust-compile-drop-candidate.h"
25 : #include "rust-hir-map.h"
26 : #include "rust-name-resolver.h"
27 : #include "rust-hir-type-check.h"
28 : #include "rust-backend.h"
29 : #include "rust-hir-full.h"
30 : #include "rust-mangle.h"
31 : #include "rust-tree.h"
32 : #include "rust-finalized-name-resolution-context.h"
33 :
34 : namespace Rust {
35 : namespace Compile {
36 :
37 : struct fncontext
38 : {
39 16211 : fncontext (tree fndecl, ::Bvariable *ret_addr, TyTy::BaseType *retty)
40 16211 : : fndecl (fndecl), ret_addr (ret_addr), retty (retty)
41 : {}
42 :
43 : tree fndecl;
44 : ::Bvariable *ret_addr;
45 : TyTy::BaseType *retty;
46 : };
47 :
48 0 : struct CustomDeriveInfo
49 : {
50 : tree fndecl;
51 : std::string trait_name;
52 : std::vector<std::string> attributes;
53 : };
54 :
55 : class DropBuilder;
56 :
57 : class Context
58 : {
59 : public:
60 : static Context *get ();
61 :
62 : void setup_builtins ();
63 :
64 : bool lookup_compiled_types (tree t, tree *type)
65 : {
66 : hashval_t h = type_hasher (t);
67 : auto it = compiled_type_map.find (h);
68 : if (it == compiled_type_map.end ())
69 : return false;
70 :
71 : *type = it->second;
72 : return true;
73 : }
74 :
75 292866 : tree insert_compiled_type (tree type)
76 : {
77 292866 : hashval_t h = type_hasher (type);
78 292866 : auto it = compiled_type_map.find (h);
79 292866 : if (it != compiled_type_map.end ())
80 201508 : return it->second;
81 :
82 91358 : compiled_type_map.insert ({h, type});
83 :
84 91358 : if (TYPE_NAME (type) != NULL)
85 91358 : push_type (type);
86 :
87 : return type;
88 : }
89 :
90 13861 : tree insert_main_variant (tree type)
91 : {
92 13861 : hashval_t h = type_hasher (type);
93 13861 : auto it = main_variants.find (h);
94 13861 : if (it != main_variants.end ())
95 8876 : return it->second;
96 :
97 4985 : main_variants.insert ({h, type});
98 4985 : return type;
99 : }
100 :
101 391907 : Resolver::TypeCheckContext *get_tyctx () { return tyctx; }
102 248684 : Analysis::Mappings &get_mappings () { return mappings; }
103 :
104 46105 : void push_block (tree scope)
105 : {
106 46105 : scope_stack.push_back (scope);
107 46105 : statements.push_back ({});
108 46105 : block_drop_candidates.emplace_back ();
109 46105 : }
110 :
111 6845 : tree pop_block () { return pop_block_impl (NULL_TREE, UNKNOWN_LOCATION); }
112 :
113 39244 : tree pop_block_with_cleanup (tree cleanup, location_t cleanup_locus)
114 : {
115 39244 : return pop_block_impl (cleanup, cleanup_locus);
116 : }
117 :
118 30367 : tree peek_enclosing_scope ()
119 : {
120 30367 : if (scope_stack.size () == 0)
121 : return nullptr;
122 :
123 30367 : return scope_stack.back ();
124 : }
125 :
126 : void add_statement_to_enclosing_scope (tree stmt)
127 : {
128 : statements.at (statements.size () - 2).push_back (stmt);
129 : }
130 :
131 126716 : void add_statement (tree stmt) { statements.back ().push_back (stmt); }
132 :
133 26489 : void insert_var_decl (HirId id, ::Bvariable *decl)
134 : {
135 26489 : compiled_var_decls[id] = decl;
136 : }
137 :
138 58411 : bool lookup_var_decl (HirId id, ::Bvariable **decl)
139 : {
140 58411 : auto it = compiled_var_decls.find (id);
141 58411 : if (it == compiled_var_decls.end ())
142 : return false;
143 :
144 44524 : *decl = it->second;
145 44524 : return true;
146 : }
147 :
148 1 : void insert_drop_flag (HirId id, ::Bvariable *flag)
149 : {
150 1 : drop_flags[{peek_fn ().fndecl, id}] = flag;
151 1 : }
152 :
153 12015 : bool lookup_drop_flag (HirId id, ::Bvariable **flag)
154 : {
155 12015 : auto it = drop_flags.find ({peek_fn ().fndecl, id});
156 12015 : if (it == drop_flags.end ())
157 : return false;
158 :
159 4 : *flag = it->second;
160 4 : return true;
161 : }
162 :
163 15881 : void insert_function_decl (const TyTy::FnType *ref, tree fn)
164 : {
165 15881 : auto id = ref->get_ty_ref ();
166 15881 : auto dId = ref->get_id ();
167 :
168 15881 : rust_assert (compiled_fn_map.find (id) == compiled_fn_map.end ());
169 15881 : compiled_fn_map[id] = fn;
170 :
171 15881 : auto it = mono_fns.find (dId);
172 15881 : if (it == mono_fns.end ())
173 15616 : mono_fns[dId] = {};
174 :
175 15881 : mono_fns[dId].emplace_back (ref, fn);
176 15881 : }
177 :
178 61 : void insert_closure_decl (const TyTy::ClosureType *ref, tree fn)
179 : {
180 61 : auto dId = ref->get_def_id ();
181 61 : auto it = mono_closure_fns.find (dId);
182 61 : if (it == mono_closure_fns.end ())
183 61 : mono_closure_fns[dId] = {};
184 :
185 61 : mono_closure_fns[dId].emplace_back (ref, fn);
186 61 : }
187 :
188 : tree lookup_closure_decl (const TyTy::ClosureType *ref)
189 : {
190 : auto dId = ref->get_def_id ();
191 : auto it = mono_closure_fns.find (dId);
192 : if (it == mono_closure_fns.end ())
193 : return error_mark_node;
194 :
195 : for (auto &i : it->second)
196 : {
197 : const TyTy::ClosureType *t = i.first;
198 : tree fn = i.second;
199 :
200 : if (ref->is_equal (*t))
201 : return fn;
202 : }
203 :
204 : return error_mark_node;
205 : }
206 :
207 34760 : bool lookup_function_decl (HirId id, tree *fn, DefId dId = UNKNOWN_DEFID,
208 : const TyTy::BaseType *ref = nullptr,
209 : const std::string &asm_name = std::string ())
210 : {
211 : // for for any monomorphized fns
212 34760 : if (ref != nullptr)
213 : {
214 23343 : rust_assert (dId != UNKNOWN_DEFID);
215 :
216 23343 : auto it = mono_fns.find (dId);
217 23343 : if (it == mono_fns.end ())
218 : return false;
219 :
220 4907 : for (auto &e : mono_fns[dId])
221 : {
222 4649 : const TyTy::BaseType *r = e.first;
223 4649 : tree f = e.second;
224 :
225 4649 : if (ref->is_equal (*r))
226 : {
227 4277 : *fn = f;
228 4277 : return true;
229 : }
230 :
231 372 : if (DECL_ASSEMBLER_NAME_SET_P (f) && !asm_name.empty ())
232 : {
233 333 : tree raw = DECL_ASSEMBLER_NAME_RAW (f);
234 333 : const char *rptr = IDENTIFIER_POINTER (raw);
235 :
236 333 : bool lengths_match_p
237 333 : = IDENTIFIER_LENGTH (raw) == asm_name.size ();
238 333 : if (lengths_match_p
239 333 : && strncmp (rptr, asm_name.c_str (),
240 332 : IDENTIFIER_LENGTH (raw))
241 : == 0)
242 : {
243 1 : *fn = f;
244 1 : return true;
245 : }
246 : }
247 : }
248 : return false;
249 : }
250 :
251 11417 : auto it = compiled_fn_map.find (id);
252 11417 : if (it == compiled_fn_map.end ())
253 : return false;
254 :
255 5876 : *fn = it->second;
256 5876 : return true;
257 : }
258 :
259 527 : void insert_const_decl (HirId id, tree expr) { compiled_consts[id] = expr; }
260 :
261 47524 : bool lookup_const_decl (HirId id, tree *expr)
262 : {
263 47524 : auto it = compiled_consts.find (id);
264 47524 : if (it == compiled_consts.end ())
265 : return false;
266 :
267 639 : *expr = it->second;
268 639 : return true;
269 : }
270 :
271 : void insert_label_decl (HirId id, tree label) { compiled_labels[id] = label; }
272 :
273 0 : bool lookup_label_decl (HirId id, tree *label)
274 : {
275 0 : auto it = compiled_labels.find (id);
276 0 : if (it == compiled_labels.end ())
277 : return false;
278 :
279 0 : *label = it->second;
280 0 : return true;
281 : }
282 :
283 54 : void insert_break_label (HirId id, tree label)
284 : {
285 54 : compiled_break_labels[id] = label;
286 : }
287 :
288 33 : tl::optional<tree> lookup_break_label (HirId id)
289 : {
290 33 : auto it = compiled_break_labels.find (id);
291 33 : if (it == compiled_break_labels.end ())
292 0 : return tl::nullopt;
293 33 : return it->second;
294 : }
295 :
296 51 : void insert_continue_label (HirId id, tree label)
297 : {
298 51 : compiled_continue_labels[id] = label;
299 : }
300 :
301 6 : tl::optional<tree> lookup_continue_label (HirId id)
302 : {
303 6 : auto it = compiled_continue_labels.find (id);
304 6 : if (it == compiled_continue_labels.end ())
305 0 : return tl::nullopt;
306 6 : return it->second;
307 : }
308 :
309 933 : void insert_pattern_binding (HirId id, tree binding)
310 : {
311 933 : implicit_pattern_bindings[id] = binding;
312 : }
313 :
314 13833 : bool lookup_pattern_binding (HirId id, tree *binding)
315 : {
316 13833 : auto it = implicit_pattern_bindings.find (id);
317 13833 : if (it == implicit_pattern_bindings.end ())
318 : return false;
319 :
320 877 : *binding = it->second;
321 877 : return true;
322 : }
323 :
324 167 : void insert_vtable (std::pair<size_t, size_t> pair, ::Bvariable *vtable)
325 : {
326 167 : compiled_vtables[pair] = vtable;
327 : }
328 :
329 174 : bool lookup_vtable (std::pair<size_t, size_t> pair, ::Bvariable **vtable)
330 : {
331 174 : auto it = compiled_vtables.find (pair);
332 174 : if (it == compiled_vtables.end ())
333 : return false;
334 :
335 7 : *vtable = it->second;
336 7 : return true;
337 : }
338 :
339 16211 : void push_fn (tree fn, ::Bvariable *ret_addr, TyTy::BaseType *retty)
340 : {
341 16211 : fn_stack.emplace_back (fn, ret_addr, retty);
342 : }
343 16211 : void pop_fn () { fn_stack.pop_back (); }
344 :
345 4420 : bool in_fn () { return fn_stack.size () != 0; }
346 :
347 : // Note: it is undefined behavior to call peek_fn () if fn_stack is empty.
348 71447 : fncontext peek_fn ()
349 : {
350 71447 : rust_assert (!fn_stack.empty ());
351 71447 : return fn_stack.back ();
352 : }
353 :
354 91358 : void push_type (tree t) { type_decls.push_back (t); }
355 221 : void push_var (::Bvariable *v) { var_decls.push_back (v); }
356 527 : void push_const (tree c) { const_decls.push_back (c); }
357 17603 : void push_function (tree f) { func_decls.push_back (f); }
358 :
359 4390 : void write_to_backend ()
360 : {
361 4390 : Backend::write_global_definitions (type_decls, const_decls, func_decls,
362 4390 : var_decls);
363 : }
364 :
365 0 : bool function_completed (tree fn)
366 : {
367 0 : for (auto it = func_decls.begin (); it != func_decls.end (); it++)
368 : {
369 0 : tree i = (*it);
370 0 : if (i == fn)
371 : {
372 : return true;
373 : }
374 : }
375 : return false;
376 : }
377 :
378 244 : void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); }
379 :
380 42 : bool have_loop_context () const { return !loop_value_stack.empty (); }
381 :
382 17 : Bvariable *peek_loop_context ()
383 : {
384 17 : rust_assert (!loop_value_stack.empty ());
385 17 : return loop_value_stack.back ();
386 : }
387 :
388 147 : Bvariable *pop_loop_context ()
389 : {
390 147 : auto back = loop_value_stack.back ();
391 147 : loop_value_stack.pop_back ();
392 147 : return back;
393 : }
394 :
395 244 : void push_loop_begin_label (tree label)
396 : {
397 244 : loop_begin_labels.push_back (label);
398 : }
399 :
400 25 : tree peek_loop_begin_label ()
401 : {
402 25 : rust_assert (!loop_begin_labels.empty ());
403 25 : return loop_begin_labels.back ();
404 : }
405 :
406 244 : tree pop_loop_begin_label ()
407 : {
408 244 : tree pop = loop_begin_labels.back ();
409 244 : loop_begin_labels.pop_back ();
410 244 : return pop;
411 : }
412 :
413 244 : void push_loop_end_label (tree label) { loop_end_labels.push_back (label); }
414 :
415 : tree peek_loop_end_label ()
416 : {
417 : rust_assert (!loop_end_labels.empty ());
418 : return loop_end_labels.back ();
419 : }
420 :
421 244 : tree pop_loop_end_label ()
422 : {
423 244 : rust_assert (!loop_end_labels.empty ());
424 244 : tree pop = loop_end_labels.back ();
425 244 : loop_end_labels.pop_back ();
426 244 : return pop;
427 : }
428 :
429 3908 : void push_const_context (void) { const_context++; }
430 3908 : void pop_const_context (void)
431 : {
432 3908 : if (const_context > 0)
433 3908 : const_context--;
434 : }
435 27421 : bool const_context_p (void) { return (const_context > 0); }
436 :
437 35061 : std::string mangle_item (const TyTy::BaseType *ty,
438 : const Resolver::CanonicalPath &path)
439 : {
440 35061 : return mangler.mangle_item (this, ty, path);
441 : }
442 :
443 : void push_closure_context (HirId id);
444 : void pop_closure_context ();
445 : void insert_closure_binding (HirId id, tree expr);
446 : bool lookup_closure_binding (HirId id, tree *expr);
447 :
448 : std::vector<tree> &get_type_decls () { return type_decls; }
449 4368 : std::vector<::Bvariable *> &get_var_decls () { return var_decls; }
450 4368 : std::vector<tree> &get_const_decls () { return const_decls; }
451 4368 : std::vector<tree> &get_func_decls () { return func_decls; }
452 :
453 : static hashval_t type_hasher (tree type);
454 :
455 0 : void collect_attribute_proc_macro (tree fndecl)
456 : {
457 0 : attribute_macros.push_back (fndecl);
458 : }
459 :
460 0 : void collect_bang_proc_macro (tree fndecl) { bang_macros.push_back (fndecl); }
461 :
462 0 : void collect_derive_proc_macro (CustomDeriveInfo macro)
463 : {
464 0 : custom_derive_macros.push_back (macro);
465 : }
466 :
467 0 : const std::vector<tree> &get_bang_proc_macros () const { return bang_macros; }
468 : const std::vector<tree> &get_attribute_proc_macros () const
469 : {
470 0 : return attribute_macros;
471 : }
472 : const std::vector<CustomDeriveInfo> &get_derive_proc_macros () const
473 : {
474 0 : return custom_derive_macros;
475 : }
476 :
477 : private:
478 : friend class DropBuilder;
479 : Context ();
480 :
481 46089 : tree pop_block_impl (tree cleanup, location_t cleanup_locus)
482 : {
483 46089 : auto block = scope_stack.back ();
484 46089 : scope_stack.pop_back ();
485 :
486 46089 : auto stmts = statements.back ();
487 46089 : statements.pop_back ();
488 :
489 46089 : rust_assert (!block_drop_candidates.empty ());
490 46089 : block_drop_candidates.pop_back ();
491 :
492 46089 : if (cleanup != NULL_TREE)
493 : {
494 50 : tree body = Backend::statement_list (stmts);
495 50 : if (body == NULL_TREE)
496 0 : body = build_empty_stmt (cleanup_locus);
497 :
498 50 : tree exceptional_cleanup = build_empty_stmt (cleanup_locus);
499 50 : tree cleanup_selector
500 50 : = build2_loc (cleanup_locus, EH_ELSE_EXPR, void_type_node, cleanup,
501 : exceptional_cleanup);
502 :
503 50 : tree try_finally
504 50 : = Backend::exception_handler_statement (body, NULL_TREE,
505 : cleanup_selector,
506 : cleanup_locus);
507 50 : Backend::block_add_statements (block, {try_finally});
508 : }
509 : else
510 46039 : Backend::block_add_statements (block, stmts);
511 :
512 46089 : return block;
513 46089 : }
514 :
515 : Resolver::TypeCheckContext *tyctx;
516 : Analysis::Mappings &mappings;
517 : Mangler mangler;
518 :
519 : // state
520 : std::vector<fncontext> fn_stack;
521 : std::map<HirId, ::Bvariable *> compiled_var_decls;
522 : std::map<std::pair<tree, HirId>, ::Bvariable *> drop_flags;
523 : std::map<hashval_t, tree> compiled_type_map;
524 : std::map<HirId, tree> compiled_fn_map;
525 : std::map<HirId, tree> compiled_consts;
526 : std::map<HirId, tree> compiled_labels;
527 : std::map<std::pair<size_t, size_t>, ::Bvariable *> compiled_vtables;
528 : std::map<HirId, tree> compiled_break_labels;
529 : std::map<HirId, tree> compiled_continue_labels;
530 : std::vector<::std::vector<tree>> statements;
531 : std::vector<tree> scope_stack;
532 : std::vector<::std::vector<DropCandidate>> block_drop_candidates;
533 : std::vector<::Bvariable *> loop_value_stack;
534 : std::vector<tree> loop_begin_labels;
535 : std::vector<tree> loop_end_labels;
536 : std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
537 : mono_fns;
538 : std::map<DefId, std::vector<std::pair<const TyTy::ClosureType *, tree>>>
539 : mono_closure_fns;
540 : std::map<HirId, tree> implicit_pattern_bindings;
541 : std::map<hashval_t, tree> main_variants;
542 :
543 : std::vector<CustomDeriveInfo> custom_derive_macros;
544 : std::vector<tree> attribute_macros;
545 : std::vector<tree> bang_macros;
546 :
547 : // closure bindings
548 : std::vector<HirId> closure_scope_bindings;
549 : std::map<HirId, std::map<HirId, tree>> closure_bindings;
550 :
551 : // To GCC middle-end
552 : std::vector<tree> type_decls;
553 : std::vector<::Bvariable *> var_decls;
554 : std::vector<tree> const_decls;
555 : std::vector<tree> func_decls;
556 :
557 : // Nonzero iff we are currently compiling something inside a constant context.
558 : unsigned int const_context = 0;
559 : };
560 :
561 : } // namespace Compile
562 : } // namespace Rust
563 :
564 : #endif // RUST_COMPILE_CONTEXT
|