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