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