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 "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 4072 : CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
32 4072 : : crate (crate), ctx (ctx)
33 4072 : {}
34 :
35 4072 : CompileCrate::~CompileCrate () {}
36 :
37 : void
38 4072 : CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
39 : {
40 4072 : CompileCrate c (crate, ctx);
41 4072 : c.go ();
42 4072 : }
43 :
44 : void
45 4072 : CompileCrate::go ()
46 : {
47 20967 : for (auto &item : crate.get_items ())
48 16895 : CompileItem::compile (item.get (), ctx);
49 4072 : auto crate_type
50 4072 : = Rust::Session::get_instance ().options.target_data.get_crate_type ();
51 4072 : if (crate_type == TargetOptions::CrateType::PROC_MACRO)
52 0 : add_proc_macro_symbols ();
53 4072 : }
54 :
55 : // Shared methods in compilation
56 :
57 : tree
58 42767 : 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 42767 : std::vector<Resolver::Adjustment> *adjustments = nullptr;
63 42767 : bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
64 42767 : if (ok)
65 : {
66 29767 : rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
67 : }
68 :
69 42767 : return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
70 : }
71 :
72 : tree
73 48719 : HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
74 : TyTy::BaseType *lval, location_t lvalue_locus,
75 : location_t rvalue_locus)
76 : {
77 48719 : if (rvalue == error_mark_node)
78 : return error_mark_node;
79 :
80 48613 : TyTy::BaseType *actual = rval->destructure ();
81 48613 : TyTy::BaseType *expected = lval->destructure ();
82 :
83 48613 : if (expected->get_kind () == TyTy::TypeKind::REF)
84 : {
85 : // this is a dyn object
86 4263 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
87 : {
88 : return rvalue;
89 : }
90 :
91 : // bad coercion... of something to a reference
92 1914 : if (actual->get_kind () != TyTy::TypeKind::REF)
93 0 : return error_mark_node;
94 :
95 1914 : const TyTy::ReferenceType *exp
96 : = static_cast<const TyTy::ReferenceType *> (expected);
97 1914 : const TyTy::ReferenceType *act
98 : = static_cast<const TyTy::ReferenceType *> (actual);
99 :
100 1914 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
101 1914 : tree coerced
102 1914 : = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
103 : lvalue_locus, rvalue_locus);
104 1914 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
105 : return coerced;
106 :
107 1914 : return address_expression (coerced, rvalue_locus);
108 : }
109 44350 : else if (expected->get_kind () == TyTy::TypeKind::POINTER)
110 : {
111 : // this is a dyn object
112 5161 : if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
113 : {
114 : return rvalue;
115 : }
116 :
117 : // bad coercion... of something to a reference
118 4038 : bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
119 4038 : || actual->get_kind () == TyTy::TypeKind::POINTER;
120 4038 : if (!valid_coercion)
121 0 : return error_mark_node;
122 :
123 4038 : const TyTy::PointerType *exp
124 : = static_cast<const TyTy::PointerType *> (expected);
125 :
126 4038 : TyTy::BaseType *actual_base = nullptr;
127 4038 : 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 3770 : else if (actual->get_kind () == TyTy::TypeKind::POINTER)
135 : {
136 3770 : const TyTy::PointerType *act
137 : = static_cast<const TyTy::PointerType *> (actual);
138 :
139 3770 : actual_base = act->get_base ();
140 : }
141 4038 : rust_assert (actual_base != nullptr);
142 :
143 4038 : tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
144 4038 : tree coerced
145 4038 : = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
146 : lvalue_locus, rvalue_locus);
147 :
148 4038 : if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
149 : return coerced;
150 :
151 4038 : return address_expression (coerced, rvalue_locus);
152 : }
153 39189 : 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 38343 : 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
|