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