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 : 3324 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
32 : 3324 : : crate (crate), ctx (ctx)
33 : 3324 : {}
34 : :
35 : 3324 : CompileCrate::~CompileCrate () {}
36 : :
37 : : void
38 : 3324 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
39 : : {
40 : 3324 : CompileCrate c (crate, ctx);
41 : 3324 : c.go ();
42 : 3324 : }
43 : :
44 : : void
45 : 3324 : CompileCrate::go ()
46 : : {
47 : 16127 : for (auto &item : crate.get_items ())
48 : 12803 : CompileItem::compile (item.get (), ctx);
49 : 3324 : auto crate_type
50 : 3324 : = Rust::Session::get_instance ().options.target_data.get_crate_type ();
51 : 3324 : if (crate_type == TargetOptions::CrateType::PROC_MACRO)
52 : 0 : add_proc_macro_symbols ();
53 : 3324 : }
54 : :
55 : : // Shared methods in compilation
56 : :
57 : : tree
58 : 23917 : 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 : 23917 : std::vector<Resolver::Adjustment> *adjustments = nullptr;
63 : 23917 : bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
64 : 23917 : if (ok)
65 : : {
66 : 16690 : rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
67 : : }
68 : :
69 : 23917 : return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
70 : : }
71 : :
72 : : tree
73 : 27581 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
74 : : TyTy::BaseType *lval, location_t lvalue_locus,
75 : : location_t rvalue_locus)
76 : : {
77 : 27581 : if (rvalue == error_mark_node)
78 : : return error_mark_node;
79 : :
80 : 27576 : TyTy::BaseType *actual = rval->destructure ();
81 : 27576 : TyTy::BaseType *expected = lval->destructure ();
82 : :
83 : 27576 : if (expected->get_kind () == TyTy::TypeKind::REF)
84 : : {
85 : : // this is a dyn object
86 : 2140 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
87 : : {
88 : : return rvalue;
89 : : }
90 : :
91 : : // bad coercion... of something to a reference
92 : 753 : if (actual->get_kind () != TyTy::TypeKind::REF)
93 : 0 : return error_mark_node;
94 : :
95 : 753 : const TyTy::ReferenceType *exp
96 : : = static_cast<const TyTy::ReferenceType *> (expected);
97 : 753 : const TyTy::ReferenceType *act
98 : : = static_cast<const TyTy::ReferenceType *> (actual);
99 : :
100 : 753 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
101 : 753 : tree coerced
102 : 753 : = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
103 : : lvalue_locus, rvalue_locus);
104 : 753 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
105 : : return coerced;
106 : :
107 : 753 : return address_expression (coerced, rvalue_locus);
108 : : }
109 : 25436 : else if (expected->get_kind () == TyTy::TypeKind::POINTER)
110 : : {
111 : : // this is a dyn object
112 : 3912 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
113 : : {
114 : : return rvalue;
115 : : }
116 : :
117 : : // bad coercion... of something to a reference
118 : 2911 : bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
119 : 2911 : || actual->get_kind () == TyTy::TypeKind::POINTER;
120 : 2911 : if (!valid_coercion)
121 : 0 : return error_mark_node;
122 : :
123 : 2911 : const TyTy::PointerType *exp
124 : : = static_cast<const TyTy::PointerType *> (expected);
125 : :
126 : 2911 : TyTy::BaseType *actual_base = nullptr;
127 : 2911 : if (actual->get_kind () == TyTy::TypeKind::REF)
128 : : {
129 : 202 : const TyTy::ReferenceType *act
130 : : = static_cast<const TyTy::ReferenceType *> (actual);
131 : :
132 : 202 : actual_base = act->get_base ();
133 : : }
134 : 2709 : else if (actual->get_kind () == TyTy::TypeKind::POINTER)
135 : : {
136 : 2709 : const TyTy::PointerType *act
137 : : = static_cast<const TyTy::PointerType *> (actual);
138 : :
139 : 2709 : actual_base = act->get_base ();
140 : : }
141 : 2911 : rust_assert (actual_base != nullptr);
142 : :
143 : 2911 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
144 : 2911 : tree coerced
145 : 2911 : = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
146 : : lvalue_locus, rvalue_locus);
147 : :
148 : 2911 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
149 : : return coerced;
150 : :
151 : 2911 : return address_expression (coerced, rvalue_locus);
152 : : }
153 : 21524 : else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
154 : : {
155 : 472 : if (actual->get_kind () != TyTy::TypeKind::ARRAY)
156 : 0 : return error_mark_node;
157 : :
158 : 472 : tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
159 : 472 : tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
160 : 472 : if (!verify_array_capacities (tree_lval_type, tree_rval_type,
161 : : lvalue_locus, rvalue_locus))
162 : 1 : return error_mark_node;
163 : : }
164 : 21052 : 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 : 70 : 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 : 70 : const TyTy::ReferenceType r (ctx->get_mappings ()->get_next_hir_id (),
193 : 70 : TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
194 : :
195 : 70 : tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
196 : 70 : tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
197 : 70 : tree vtable_field = DECL_CHAIN (dynamic_object_fields);
198 : 70 : 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 : 70 : std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
205 : 70 : probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
206 : :
207 : 70 : tree address_of_compiled_ref = null_pointer_node;
208 : 70 : if (!actual->is_unit ())
209 : 56 : address_of_compiled_ref = address_expression (compiled_ref, locus);
210 : :
211 : 70 : std::vector<tree> vtable_ctor_elems;
212 : 70 : std::vector<unsigned long> vtable_ctor_idx;
213 : 70 : unsigned long i = 0;
214 : 147 : for (auto &bound : ty->get_object_items ())
215 : : {
216 : 77 : const Resolver::TraitItemReference *item = bound.first;
217 : 77 : const TyTy::TypeBoundPredicate *predicate = bound.second;
218 : :
219 : 77 : auto address = compute_address_for_trait_item (item, predicate,
220 : : probed_bounds_for_receiver,
221 : 77 : actual, actual, locus);
222 : 77 : vtable_ctor_elems.push_back (address);
223 : 77 : vtable_ctor_idx.push_back (i++);
224 : 70 : }
225 : :
226 : 70 : tree vtable_ctor
227 : 70 : = Backend::array_constructor_expression (TREE_TYPE (vtable_field),
228 : : vtable_ctor_idx, vtable_ctor_elems,
229 : : locus);
230 : :
231 : 70 : std::vector<tree> dyn_ctor = {address_of_compiled_ref, vtable_ctor};
232 : 70 : return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
233 : 70 : locus);
234 : 70 : }
235 : :
236 : : tree
237 : 77 : 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 : : // There are two cases here one where its an item which has an implementation
245 : : // within a trait-impl-block. Then there is the case where there is a default
246 : : // implementation for this within the trait.
247 : : //
248 : : // The awkward part here is that this might be a generic trait and we need to
249 : : // figure out the correct monomorphized type for this so we can resolve the
250 : : // address of the function , this is stored as part of the
251 : : // type-bound-predicate
252 : : //
253 : : // Algo:
254 : : // check if there is an impl-item for this trait-item-ref first
255 : : // else assert that the trait-item-ref has an implementation
256 : : //
257 : : // FIXME this does not support super traits
258 : :
259 : 77 : TyTy::TypeBoundPredicateItem predicate_item
260 : 77 : = predicate->lookup_associated_item (ref->get_identifier ());
261 : 77 : rust_assert (!predicate_item.is_error ());
262 : :
263 : : // this is the expected end type
264 : 77 : TyTy::BaseType *trait_item_type = predicate_item.get_tyty_for_receiver (root);
265 : 77 : rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
266 : 77 : TyTy::FnType *trait_item_fntype
267 : : = static_cast<TyTy::FnType *> (trait_item_type);
268 : :
269 : : // find impl-block for this trait-item-ref
270 : 77 : HIR::ImplBlock *associated_impl_block = nullptr;
271 : 77 : const Resolver::TraitReference *predicate_trait_ref = predicate->get ();
272 : 77 : for (auto &item : receiver_bounds)
273 : : {
274 : 77 : Resolver::TraitReference *trait_ref = item.first;
275 : 77 : HIR::ImplBlock *impl_block = item.second;
276 : 77 : if (predicate_trait_ref->is_equal (*trait_ref))
277 : : {
278 : : associated_impl_block = impl_block;
279 : : break;
280 : : }
281 : : }
282 : :
283 : : // FIXME this probably should just return error_mark_node but this helps
284 : : // debug for now since we are wrongly returning early on type-resolution
285 : : // failures, until we take advantage of more error types and error_mark_node
286 : 77 : rust_assert (associated_impl_block != nullptr);
287 : :
288 : : // lookup self for the associated impl
289 : 77 : std::unique_ptr<HIR::Type> &self_type_path
290 : 77 : = associated_impl_block->get_type ();
291 : 77 : TyTy::BaseType *self = nullptr;
292 : 77 : bool ok = ctx->get_tyctx ()->lookup_type (
293 : 77 : self_type_path->get_mappings ().get_hirid (), &self);
294 : 77 : rust_assert (ok);
295 : :
296 : : // lookup the predicate item from the self
297 : 77 : TyTy::TypeBoundPredicate *self_bound = nullptr;
298 : 77 : for (auto &bound : self->get_specified_bounds ())
299 : : {
300 : 77 : const Resolver::TraitReference *bound_ref = bound.get ();
301 : 77 : const Resolver::TraitReference *specified_ref = predicate->get ();
302 : 77 : if (bound_ref->is_equal (*specified_ref))
303 : : {
304 : : self_bound = &bound;
305 : : break;
306 : : }
307 : : }
308 : 77 : rust_assert (self_bound != nullptr);
309 : :
310 : : // lookup the associated item from the associated impl block
311 : 77 : TyTy::TypeBoundPredicateItem associated_self_item
312 : 77 : = self_bound->lookup_associated_item (ref->get_identifier ());
313 : 77 : rust_assert (!associated_self_item.is_error ());
314 : :
315 : : // Lookup the impl-block for the associated impl_item if it exists
316 : 77 : HIR::Function *associated_function = nullptr;
317 : 154 : for (auto &impl_item : associated_impl_block->get_impl_items ())
318 : : {
319 : 77 : bool is_function = impl_item->get_impl_item_type ()
320 : 77 : == HIR::ImplItem::ImplItemType::FUNCTION;
321 : 77 : if (!is_function)
322 : 0 : continue;
323 : :
324 : 77 : HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
325 : 77 : bool found_associated_item
326 : 154 : = fn->get_function_name ().as_string ().compare (ref->get_identifier ())
327 : 77 : == 0;
328 : 77 : if (found_associated_item)
329 : 77 : associated_function = fn;
330 : : }
331 : :
332 : : // we found an impl_item for this
333 : 77 : if (associated_function != nullptr)
334 : : {
335 : : // lookup the associated type for this item
336 : 70 : TyTy::BaseType *lookup = nullptr;
337 : 70 : bool ok = ctx->get_tyctx ()->lookup_type (
338 : 70 : associated_function->get_mappings ().get_hirid (), &lookup);
339 : 70 : rust_assert (ok);
340 : 70 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
341 : 70 : TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
342 : :
343 : 70 : if (lookup_fntype->needs_substitution ())
344 : : {
345 : 7 : TyTy::BaseType *infer
346 : 7 : = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
347 : 7 : infer
348 : 7 : = Resolver::unify_site (infer->get_ref (),
349 : 7 : TyTy::TyWithLocation (trait_item_fntype),
350 : 7 : TyTy::TyWithLocation (infer),
351 : : UNDEF_LOCATION);
352 : 7 : rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
353 : : lookup_fntype = static_cast<TyTy::FnType *> (infer);
354 : : }
355 : :
356 : 70 : return CompileInherentImplItem::Compile (associated_function, ctx,
357 : : lookup_fntype, true, locus);
358 : : }
359 : :
360 : : // we can only compile trait-items with a body
361 : 7 : bool trait_item_has_definition = ref->is_optional ();
362 : 7 : rust_assert (trait_item_has_definition);
363 : :
364 : 7 : HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
365 : 7 : return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
366 : 7 : locus);
367 : : }
368 : :
369 : : bool
370 : 472 : HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
371 : : location_t lvalue_locus,
372 : : location_t rvalue_locus)
373 : : {
374 : 472 : rust_assert (ltype != NULL_TREE);
375 : 472 : rust_assert (rtype != NULL_TREE);
376 : :
377 : : // lets just return ok as other errors have already occurred
378 : 472 : if (ltype == error_mark_node || rtype == error_mark_node)
379 : : return true;
380 : :
381 : 472 : tree ltype_domain = TYPE_DOMAIN (ltype);
382 : 472 : if (!ltype_domain)
383 : : return false;
384 : :
385 : 472 : if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
386 : : return false;
387 : :
388 : 472 : unsigned HOST_WIDE_INT ltype_length
389 : 944 : = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
390 : 944 : - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
391 : 472 : TYPE_PRECISION (TREE_TYPE (ltype_domain)),
392 : 472 : TYPE_SIGN (TREE_TYPE (ltype_domain)))
393 : 472 : .to_uhwi ();
394 : :
395 : 472 : tree rtype_domain = TYPE_DOMAIN (rtype);
396 : 472 : if (!rtype_domain)
397 : : return false;
398 : :
399 : 472 : if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
400 : : return false;
401 : :
402 : 472 : unsigned HOST_WIDE_INT rtype_length
403 : 944 : = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
404 : 944 : - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
405 : 472 : TYPE_PRECISION (TREE_TYPE (rtype_domain)),
406 : 472 : TYPE_SIGN (TREE_TYPE (rtype_domain)))
407 : 472 : .to_uhwi ();
408 : :
409 : 472 : if (ltype_length != rtype_length)
410 : : {
411 : 1 : rust_error_at (rvalue_locus, ErrorCode::E0308,
412 : : "mismatched types, expected an array with a fixed size "
413 : : "of " HOST_WIDE_INT_PRINT_UNSIGNED
414 : : " elements, found one with " HOST_WIDE_INT_PRINT_UNSIGNED
415 : : " elements",
416 : : ltype_length, rtype_length);
417 : 1 : return false;
418 : : }
419 : :
420 : : return true;
421 : : }
422 : :
423 : : } // namespace Compile
424 : : } // namespace Rust
|