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_BIR_BUILDER_H
20 : #define RUST_BIR_BUILDER_H
21 :
22 : #include "rust-bir-builder-internal.h"
23 : #include "rust-bir-builder-pattern.h"
24 : #include "rust-bir-builder-expr-stmt.h"
25 :
26 : namespace Rust {
27 : namespace BIR {
28 :
29 : /** Top-level builder, which compiles a HIR function into a BIR function. */
30 36 : class Builder final : public AbstractBuilder
31 : {
32 : std::vector<std::pair<FreeRegion, FreeRegion>> universal_region_bounds;
33 :
34 : public:
35 36 : explicit Builder (BuilderContext &ctx) : AbstractBuilder (ctx) {}
36 :
37 36 : Function build (HIR::Function &function)
38 : {
39 36 : rust_debug ("BIR::Builder::build function={%s}",
40 : function.get_function_name ().as_string ().c_str ());
41 :
42 36 : auto fn_ty = lookup_type (function)->as<TyTy::FnType> ();
43 :
44 36 : handle_lifetime_params (fn_ty->get_num_lifetime_params ());
45 36 : handle_lifetime_param_constraints (fn_ty->get_region_constraints ());
46 :
47 36 : handle_return (fn_ty);
48 :
49 54 : for (auto ¶m : function.get_function_params ())
50 18 : handle_param (param);
51 :
52 36 : handle_body (function.get_definition ());
53 36 : auto region_hir_map
54 36 : = map_region_to_hir (function.get_generic_params (), ctx.fn_free_regions);
55 :
56 36 : return Function{
57 36 : std::move (ctx.place_db),
58 36 : std::move (ctx.arguments),
59 36 : std::move (ctx.basic_blocks),
60 36 : std::move (ctx.fn_free_regions),
61 36 : std::move (universal_region_bounds),
62 : std::move (region_hir_map),
63 36 : function.get_locus (),
64 36 : };
65 36 : }
66 :
67 : private:
68 : /** Instantiate `num_lifetime_params` free regions. */
69 36 : void handle_lifetime_params (size_t num_lifetime_params)
70 : {
71 36 : FreeRegions regions;
72 47 : for (size_t i = 0; i < num_lifetime_params; i++)
73 : {
74 11 : regions.push_back (ctx.place_db.get_next_free_region ());
75 : }
76 :
77 36 : rust_debug ("\tctx.fn_free_region={%s}",
78 : ctx.fn_free_regions.to_string ().c_str ());
79 36 : ctx.fn_free_regions = regions;
80 36 : }
81 :
82 36 : void handle_lifetime_param_constraints (
83 : const TyTy::RegionConstraints ®ion_constraints)
84 : {
85 36 : rust_debug ("\thandle_lifetime_param_constraints");
86 :
87 38 : for (auto bound : region_constraints.region_region)
88 : {
89 2 : rust_assert (bound.first.is_early_bound ());
90 2 : rust_assert (bound.second.is_early_bound ());
91 :
92 2 : universal_region_bounds.emplace_back (
93 : ctx.fn_free_regions[bound.first.get_index ()],
94 2 : ctx.fn_free_regions[bound.second.get_index ()]);
95 :
96 2 : auto last_bound = universal_region_bounds.back ();
97 2 : rust_debug ("\t\t %lu: %lu", (unsigned long) last_bound.first.value,
98 : (unsigned long) last_bound.second.value);
99 : }
100 :
101 : // TODO: handle type_region constraints
102 36 : }
103 :
104 36 : void handle_return (TyTy::FnType *fn_ty)
105 : {
106 36 : TyTy::BaseType *return_ty = fn_ty->get_return_type ();
107 :
108 36 : PlaceId return_place = ctx.place_db.add_temporary (return_ty);
109 36 : rust_assert (return_place == RETURN_VALUE_PLACE);
110 :
111 : // Set return place to use functions regions, not the fresh ones.
112 36 : ctx.place_db[return_place].regions
113 72 : = bind_regions (Resolver::TypeCheckContext::get ()
114 36 : ->get_variance_analysis_ctx ()
115 72 : .query_type_regions (fn_ty->get_return_type ()),
116 72 : ctx.fn_free_regions);
117 36 : }
118 :
119 18 : void handle_param (HIR::FunctionParam ¶m)
120 : {
121 18 : auto param_type = lookup_type (param.get_param_name ());
122 :
123 18 : auto &pattern = param.get_param_name ();
124 18 : if (pattern.get_pattern_type () == HIR::Pattern::IDENTIFIER
125 18 : && !static_cast<HIR::IdentifierPattern &> (pattern).get_is_ref ())
126 : {
127 : // Avoid useless temporary variable for parameter to look like MIR.
128 18 : translated = declare_variable (pattern.get_mappings ());
129 18 : ctx.arguments.push_back (translated);
130 : }
131 : else
132 : {
133 0 : translated = ctx.place_db.add_temporary (param_type);
134 0 : ctx.arguments.push_back (translated);
135 0 : PatternBindingBuilder (ctx, translated, tl::nullopt)
136 0 : .go (param.get_param_name ());
137 : }
138 :
139 : // Set parameter place to use functions regions, not the fresh ones.
140 18 : ctx.place_db[translated].regions
141 36 : = bind_regions (Resolver::TypeCheckContext::get ()
142 18 : ->get_variance_analysis_ctx ()
143 36 : .query_type_regions (param_type),
144 36 : ctx.fn_free_regions);
145 18 : }
146 :
147 36 : void handle_body (HIR::BlockExpr &body)
148 : {
149 36 : translated = ExprStmtBuilder (ctx).build (body, RETURN_VALUE_PLACE);
150 36 : if (!ctx.get_current_bb ().is_terminated ())
151 : {
152 36 : if (ctx.place_db[RETURN_VALUE_PLACE].tyty->is_unit ())
153 : {
154 28 : push_assignment (RETURN_VALUE_PLACE,
155 28 : ctx.place_db.get_constant (
156 28 : ctx.place_db[RETURN_VALUE_PLACE].tyty),
157 : body.get_end_locus ());
158 : }
159 36 : auto return_location = body.has_expr ()
160 36 : ? body.get_final_expr ().get_locus ()
161 26 : : body.get_end_locus ();
162 36 : push_return (return_location);
163 : }
164 36 : }
165 :
166 : // Maps named lifetime parameters to their respective HIR node
167 : const std::unordered_map<Polonius::Origin, HIR::LifetimeParam *>
168 36 : map_region_to_hir (
169 : const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
170 : const FreeRegions ®ions)
171 : {
172 36 : std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> result;
173 36 : size_t region_index = 0;
174 47 : for (auto &generic_param : generic_params)
175 : {
176 11 : if (generic_param->get_kind ()
177 : == HIR::GenericParam::GenericKind::LIFETIME)
178 : {
179 11 : result[regions[region_index++].value]
180 22 : = static_cast<HIR::LifetimeParam *> (generic_param.get ());
181 : }
182 : }
183 36 : return result;
184 : }
185 : };
186 :
187 : } // namespace BIR
188 : } // namespace Rust
189 :
190 : #endif // RUST_BIR_BUILDER_H
|