Branch data Line data Source code
1 : : // Copyright (C) 2020-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-compile.h"
20 : : #include "rust-compile-item.h"
21 : : #include "rust-compile-implitem.h"
22 : : #include "rust-hir-type-bounds.h"
23 : : #include "rust-compile-type.h"
24 : : #include "rust-substitution-mapper.h"
25 : : #include "rust-type-util.h"
26 : : #include "rust-session-manager.h"
27 : :
28 : : namespace Rust {
29 : : namespace Compile {
30 : :
31 : 4032 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
32 : 4032 : : crate (crate), ctx (ctx)
33 : 4032 : {}
34 : :
35 : 4032 : CompileCrate::~CompileCrate () {}
36 : :
37 : : void
38 : 4032 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
39 : : {
40 : 4032 : CompileCrate c (crate, ctx);
41 : 4032 : c.go ();
42 : 4032 : }
43 : :
44 : : void
45 : 4032 : CompileCrate::go ()
46 : : {
47 : 20812 : for (auto &item : crate.get_items ())
48 : 16780 : CompileItem::compile (item.get (), ctx);
49 : 4032 : auto crate_type
50 : 4032 : = Rust::Session::get_instance ().options.target_data.get_crate_type ();
51 : 4032 : if (crate_type == TargetOptions::CrateType::PROC_MACRO)
52 : 0 : add_proc_macro_symbols ();
53 : 4032 : }
54 : :
55 : : // Shared methods in compilation
56 : :
57 : : tree
58 : 42639 : HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval,
59 : : TyTy::BaseType *lval, location_t lvalue_locus,
60 : : location_t rvalue_locus)
61 : : {
62 : 42639 : std::vector<Resolver::Adjustment> *adjustments = nullptr;
63 : 42639 : bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
64 : 42639 : if (ok)
65 : : {
66 : 29694 : rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
67 : : }
68 : :
69 : 42639 : return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
70 : : }
71 : :
72 : : tree
73 : 48586 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
74 : : TyTy::BaseType *lval, location_t lvalue_locus,
75 : : location_t rvalue_locus)
76 : : {
77 : 48586 : if (rvalue == error_mark_node)
78 : : return error_mark_node;
79 : :
80 : 48483 : TyTy::BaseType *actual = rval->destructure ();
81 : 48483 : TyTy::BaseType *expected = lval->destructure ();
82 : :
83 : 48483 : if (expected->get_kind () == TyTy::TypeKind::REF)
84 : : {
85 : : // this is a dyn object
86 : 4260 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
87 : : {
88 : : return rvalue;
89 : : }
90 : :
91 : : // bad coercion... of something to a reference
92 : 1913 : if (actual->get_kind () != TyTy::TypeKind::REF)
93 : 0 : return error_mark_node;
94 : :
95 : 1913 : const TyTy::ReferenceType *exp
96 : : = static_cast<const TyTy::ReferenceType *> (expected);
97 : 1913 : const TyTy::ReferenceType *act
98 : : = static_cast<const TyTy::ReferenceType *> (actual);
99 : :
100 : 1913 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
101 : 1913 : tree coerced
102 : 1913 : = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
103 : : lvalue_locus, rvalue_locus);
104 : 1913 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
105 : : return coerced;
106 : :
107 : 1913 : return address_expression (coerced, rvalue_locus);
108 : : }
109 : 44223 : else if (expected->get_kind () == TyTy::TypeKind::POINTER)
110 : : {
111 : : // this is a dyn object
112 : 5155 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
113 : : {
114 : : return rvalue;
115 : : }
116 : :
117 : : // bad coercion... of something to a reference
118 : 4034 : bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
119 : 4034 : || actual->get_kind () == TyTy::TypeKind::POINTER;
120 : 4034 : if (!valid_coercion)
121 : 0 : return error_mark_node;
122 : :
123 : 4034 : const TyTy::PointerType *exp
124 : : = static_cast<const TyTy::PointerType *> (expected);
125 : :
126 : 4034 : TyTy::BaseType *actual_base = nullptr;
127 : 4034 : if (actual->get_kind () == TyTy::TypeKind::REF)
128 : : {
129 : 268 : const TyTy::ReferenceType *act
130 : : = static_cast<const TyTy::ReferenceType *> (actual);
131 : :
132 : 268 : actual_base = act->get_base ();
133 : : }
134 : 3766 : else if (actual->get_kind () == TyTy::TypeKind::POINTER)
135 : : {
136 : 3766 : const TyTy::PointerType *act
137 : : = static_cast<const TyTy::PointerType *> (actual);
138 : :
139 : 3766 : actual_base = act->get_base ();
140 : : }
141 : 4034 : rust_assert (actual_base != nullptr);
142 : :
143 : 4034 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
144 : 4034 : tree coerced
145 : 4034 : = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
146 : : lvalue_locus, rvalue_locus);
147 : :
148 : 4034 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
149 : : return coerced;
150 : :
151 : 4034 : return address_expression (coerced, rvalue_locus);
152 : : }
153 : 39068 : else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
154 : : {
155 : 846 : if (actual->get_kind () != TyTy::TypeKind::ARRAY)
156 : 0 : return error_mark_node;
157 : :
158 : 846 : tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
159 : 846 : tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
160 : 846 : if (!verify_array_capacities (tree_lval_type, tree_rval_type,
161 : : lvalue_locus, rvalue_locus))
162 : 0 : return error_mark_node;
163 : : }
164 : 38222 : else if (expected->get_kind () == TyTy::TypeKind::SLICE)
165 : : {
166 : : // bad coercion
167 : 0 : bool valid_coercion = actual->get_kind () == TyTy::TypeKind::SLICE
168 : 0 : || actual->get_kind () == TyTy::TypeKind::ARRAY;
169 : 0 : if (!valid_coercion)
170 : 0 : return error_mark_node;
171 : :
172 : : // nothing to do here
173 : 0 : if (actual->get_kind () == TyTy::TypeKind::SLICE)
174 : : return rvalue;
175 : :
176 : : // return an unsized coercion
177 : 0 : Resolver::Adjustment unsize_adj (
178 : 0 : Resolver::Adjustment::AdjustmentType::UNSIZE, actual, expected);
179 : 0 : return resolve_unsized_adjustment (unsize_adj, rvalue, rvalue_locus);
180 : : }
181 : :
182 : : return rvalue;
183 : : }
184 : :
185 : : tree
186 : 124 : HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
187 : : const TyTy::DynamicObjectType *ty,
188 : : location_t locus)
189 : : {
190 : : // DST's get wrapped in a pseudo reference that doesnt exist...
191 : 124 : const TyTy::ReferenceType r (ctx->get_mappings ().get_next_hir_id (),
192 : 124 : TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
193 : :
194 : 124 : tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
195 : 124 : tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
196 : 124 : tree vtable_field = DECL_CHAIN (dynamic_object_fields);
197 : 124 : rust_assert (TREE_CODE (TREE_TYPE (vtable_field)) == ARRAY_TYPE);
198 : :
199 : : //' this assumes ordering and current the structure is
200 : : // __trait_object_ptr
201 : : // [list of function ptrs]
202 : :
203 : 124 : auto probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
204 : 124 : tree address_of_compiled_ref = null_pointer_node;
205 : 124 : if (!actual->is_unit ())
206 : 109 : address_of_compiled_ref = address_expression (compiled_ref, locus);
207 : :
208 : 124 : std::vector<tree> vtable_ctor_elems;
209 : 124 : std::vector<unsigned long> vtable_ctor_idx;
210 : 124 : unsigned long i = 0;
211 : 315 : for (auto &bound : ty->get_object_items ())
212 : : {
213 : 191 : const Resolver::TraitItemReference *item = bound.first;
214 : 191 : const TyTy::TypeBoundPredicate *predicate = bound.second;
215 : :
216 : 191 : auto address = compute_address_for_trait_item (item, predicate,
217 : : probed_bounds_for_receiver,
218 : 191 : actual, actual, locus);
219 : 191 : vtable_ctor_elems.push_back (address);
220 : 191 : vtable_ctor_idx.push_back (i++);
221 : 124 : }
222 : :
223 : 124 : tree vtable_ctor
224 : 124 : = Backend::array_constructor_expression (TREE_TYPE (vtable_field),
225 : : vtable_ctor_idx, vtable_ctor_elems,
226 : : locus);
227 : :
228 : 124 : std::vector<tree> dyn_ctor = {address_of_compiled_ref, vtable_ctor};
229 : 124 : return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
230 : 124 : locus);
231 : 124 : }
232 : :
233 : : tree
234 : 191 : HIRCompileBase::compute_address_for_trait_item (
235 : : const Resolver::TraitItemReference *ref,
236 : : const TyTy::TypeBoundPredicate *predicate,
237 : : std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
238 : : &receiver_bounds,
239 : : const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
240 : : {
241 : 191 : tl::optional<TyTy::TypeBoundPredicateItem> predicate_item
242 : 191 : = predicate->lookup_associated_item (ref->get_identifier ());
243 : 191 : rust_assert (predicate_item.has_value ());
244 : :
245 : : // This is the expected end type
246 : 191 : TyTy::BaseType *trait_item_type
247 : 191 : = predicate_item->get_tyty_for_receiver (root);
248 : 191 : rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
249 : 191 : TyTy::FnType *trait_item_fntype
250 : : = static_cast<TyTy::FnType *> (trait_item_type);
251 : :
252 : : // Loop through the list of trait references and impls that we satisfy.
253 : : // We are looking for one that has an implementation for "ref", a trait
254 : : // item.
255 : 277 : for (auto &item : receiver_bounds)
256 : : {
257 : 263 : HIR::ImplBlock *impl_block = item.second;
258 : 263 : rust_assert (impl_block != nullptr);
259 : :
260 : : // Checks for empty impl blocks, triggered by Sized trait.
261 : 263 : if (!impl_block->has_type ())
262 : 86 : continue;
263 : :
264 : : // Lookup type for potentially associated impl.
265 : 256 : HIR::Type &self_type_path = impl_block->get_type ();
266 : :
267 : : // Convert HIR::Type to TyTy::BaseType
268 : 256 : TyTy::BaseType *self = nullptr;
269 : 256 : bool ok = ctx->get_tyctx ()->lookup_type (
270 : 256 : self_type_path.get_mappings ().get_hirid (), &self);
271 : :
272 : 256 : rust_assert (ok);
273 : :
274 : : // Look through the relevant bounds on our type, and find which one our
275 : : // impl block satisfies
276 : 256 : TyTy::TypeBoundPredicate *self_bound = nullptr;
277 : 256 : for (auto &bound : self->get_specified_bounds ())
278 : : {
279 : 256 : const Resolver::TraitReference *bound_ref = bound.get ();
280 : 256 : const Resolver::TraitReference *specified_ref = predicate->get ();
281 : : // If this impl is for one of our types or supertypes
282 : 256 : if (specified_ref->satisfies_bound (*bound_ref))
283 : : {
284 : : self_bound = &bound;
285 : : break;
286 : : }
287 : : }
288 : :
289 : : // This impl block doesn't help us
290 : 256 : if (self_bound == nullptr)
291 : 0 : continue;
292 : :
293 : : // Find the specific function in the impl block that matches "ref".
294 : : // This is the one we want to compute the address for.
295 : 256 : HIR::Function *associated_function = nullptr;
296 : 512 : for (auto &impl_item : impl_block->get_impl_items ())
297 : : {
298 : 256 : bool is_function = impl_item->get_impl_item_type ()
299 : 256 : == HIR::ImplItem::ImplItemType::FUNCTION;
300 : 256 : if (!is_function)
301 : 0 : continue;
302 : :
303 : 256 : HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
304 : 256 : bool found_associated_item
305 : 256 : = fn->get_function_name ().as_string ().compare (
306 : 512 : ref->get_identifier ())
307 : 256 : == 0;
308 : 256 : if (found_associated_item)
309 : 256 : associated_function = fn;
310 : : }
311 : :
312 : : // This impl block satisfies the bound, but doesn't contain the relevant
313 : : // function. This could happen because of supertraits.
314 : 256 : if (associated_function == nullptr)
315 : 79 : continue;
316 : :
317 : : // lookup the associated type for this item
318 : 177 : TyTy::BaseType *lookup = nullptr;
319 : 177 : ok = ctx->get_tyctx ()->lookup_type (
320 : 177 : associated_function->get_mappings ().get_hirid (), &lookup);
321 : 177 : rust_assert (ok);
322 : 177 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
323 : 177 : TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
324 : :
325 : 177 : if (lookup_fntype->needs_substitution ())
326 : : {
327 : 7 : TyTy::BaseType *infer
328 : 7 : = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
329 : 7 : infer
330 : 7 : = Resolver::unify_site (infer->get_ref (),
331 : 7 : TyTy::TyWithLocation (trait_item_fntype),
332 : 7 : TyTy::TyWithLocation (infer),
333 : : UNDEF_LOCATION);
334 : 7 : rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
335 : : lookup_fntype = static_cast<TyTy::FnType *> (infer);
336 : : }
337 : :
338 : 177 : return CompileInherentImplItem::Compile (associated_function, ctx,
339 : 177 : lookup_fntype, locus);
340 : : }
341 : :
342 : : // we can only compile trait-items with a body
343 : 14 : bool trait_item_has_definition = ref->is_optional ();
344 : 14 : rust_assert (trait_item_has_definition);
345 : :
346 : 14 : HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
347 : 14 : return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
348 : 14 : locus);
349 : 191 : }
350 : :
351 : : bool
352 : 846 : HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
353 : : location_t lvalue_locus,
354 : : location_t rvalue_locus)
355 : : {
356 : 846 : rust_assert (ltype != NULL_TREE);
357 : 846 : rust_assert (rtype != NULL_TREE);
358 : :
359 : : // lets just return ok as other errors have already occurred
360 : 846 : if (ltype == error_mark_node || rtype == error_mark_node)
361 : : return true;
362 : :
363 : 846 : tree ltype_domain = TYPE_DOMAIN (ltype);
364 : 846 : if (!ltype_domain)
365 : : return false;
366 : :
367 : 846 : if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
368 : : return false;
369 : :
370 : 846 : unsigned HOST_WIDE_INT ltype_length
371 : 1692 : = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
372 : 1692 : - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
373 : 846 : TYPE_PRECISION (TREE_TYPE (ltype_domain)),
374 : 846 : TYPE_SIGN (TREE_TYPE (ltype_domain)))
375 : 846 : .to_uhwi ();
376 : :
377 : 846 : tree rtype_domain = TYPE_DOMAIN (rtype);
378 : 846 : if (!rtype_domain)
379 : : return false;
380 : :
381 : 846 : if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
382 : : return false;
383 : :
384 : 846 : unsigned HOST_WIDE_INT rtype_length
385 : 1692 : = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
386 : 1692 : - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
387 : 846 : TYPE_PRECISION (TREE_TYPE (rtype_domain)),
388 : 846 : TYPE_SIGN (TREE_TYPE (rtype_domain)))
389 : 846 : .to_uhwi ();
390 : :
391 : 846 : if (ltype_length != rtype_length)
392 : : {
393 : 0 : rust_error_at (rvalue_locus, ErrorCode::E0308,
394 : : "mismatched types, expected an array with a fixed size "
395 : : "of " HOST_WIDE_INT_PRINT_UNSIGNED
396 : : " elements, found one with " HOST_WIDE_INT_PRINT_UNSIGNED
397 : : " elements",
398 : : ltype_length, rtype_length);
399 : 0 : return false;
400 : : }
401 : :
402 : : return true;
403 : : }
404 : :
405 : : } // namespace Compile
406 : : } // namespace Rust
|