libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / backend / rust-compile.cc
blob5b07d79a17a60d6e8c9a079aad16f203d2de504b
1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
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"
28 namespace Rust {
29 namespace Compile {
31 CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
32 : crate (crate), ctx (ctx)
35 CompileCrate::~CompileCrate () {}
37 void
38 CompileCrate::Compile (HIR::Crate &crate, Context *ctx)
40 CompileCrate c (crate, ctx);
41 c.go ();
44 void
45 CompileCrate::go ()
47 for (auto &item : crate.get_items ())
48 CompileItem::compile (item.get (), ctx);
49 auto crate_type
50 = Rust::Session::get_instance ().options.target_data.get_crate_type ();
51 if (crate_type == TargetOptions::CrateType::PROC_MACRO)
52 add_proc_macro_symbols ();
55 // Shared methods in compilation
57 tree
58 HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval,
59 TyTy::BaseType *lval, location_t lvalue_locus,
60 location_t rvalue_locus)
62 std::vector<Resolver::Adjustment> *adjustments = nullptr;
63 bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
64 if (ok)
66 rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
69 return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
72 tree
73 HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
74 TyTy::BaseType *lval, location_t lvalue_locus,
75 location_t rvalue_locus)
77 if (rvalue == error_mark_node)
78 return error_mark_node;
80 TyTy::BaseType *actual = rval->destructure ();
81 TyTy::BaseType *expected = lval->destructure ();
83 if (expected->get_kind () == TyTy::TypeKind::REF)
85 // this is a dyn object
86 if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
88 return rvalue;
91 // bad coercion... of something to a reference
92 if (actual->get_kind () != TyTy::TypeKind::REF)
93 return error_mark_node;
95 const TyTy::ReferenceType *exp
96 = static_cast<const TyTy::ReferenceType *> (expected);
97 const TyTy::ReferenceType *act
98 = static_cast<const TyTy::ReferenceType *> (actual);
100 tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
101 tree coerced
102 = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
103 lvalue_locus, rvalue_locus);
104 if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
105 return coerced;
107 return address_expression (coerced, rvalue_locus);
109 else if (expected->get_kind () == TyTy::TypeKind::POINTER)
111 // this is a dyn object
112 if (RS_DST_FLAG_P (TREE_TYPE (rvalue)))
114 return rvalue;
117 // bad coercion... of something to a reference
118 bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF
119 || actual->get_kind () == TyTy::TypeKind::POINTER;
120 if (!valid_coercion)
121 return error_mark_node;
123 const TyTy::PointerType *exp
124 = static_cast<const TyTy::PointerType *> (expected);
126 TyTy::BaseType *actual_base = nullptr;
127 if (actual->get_kind () == TyTy::TypeKind::REF)
129 const TyTy::ReferenceType *act
130 = static_cast<const TyTy::ReferenceType *> (actual);
132 actual_base = act->get_base ();
134 else if (actual->get_kind () == TyTy::TypeKind::POINTER)
136 const TyTy::PointerType *act
137 = static_cast<const TyTy::PointerType *> (actual);
139 actual_base = act->get_base ();
141 rust_assert (actual_base != nullptr);
143 tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
144 tree coerced
145 = coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
146 lvalue_locus, rvalue_locus);
148 if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced)))
149 return coerced;
151 return address_expression (coerced, rvalue_locus);
153 else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
155 if (actual->get_kind () != TyTy::TypeKind::ARRAY)
156 return error_mark_node;
158 tree tree_rval_type = TyTyResolveCompile::compile (ctx, actual);
159 tree tree_lval_type = TyTyResolveCompile::compile (ctx, expected);
160 if (!verify_array_capacities (tree_lval_type, tree_rval_type,
161 lvalue_locus, rvalue_locus))
162 return error_mark_node;
164 else if (expected->get_kind () == TyTy::TypeKind::SLICE)
166 // bad coercion
167 bool valid_coercion = actual->get_kind () == TyTy::TypeKind::SLICE
168 || actual->get_kind () == TyTy::TypeKind::ARRAY;
169 if (!valid_coercion)
170 return error_mark_node;
172 // nothing to do here
173 if (actual->get_kind () == TyTy::TypeKind::SLICE)
174 return rvalue;
176 // return an unsized coercion
177 Resolver::Adjustment unsize_adj (
178 Resolver::Adjustment::AdjustmentType::UNSIZE, actual, expected);
179 return resolve_unsized_adjustment (unsize_adj, rvalue, rvalue_locus);
182 return rvalue;
185 tree
186 HIRCompileBase::coerce_to_dyn_object (tree compiled_ref,
187 const TyTy::BaseType *actual,
188 const TyTy::DynamicObjectType *ty,
189 location_t locus)
191 // DST's get wrapped in a pseudo reference that doesnt exist...
192 const TyTy::ReferenceType r (ctx->get_mappings ()->get_next_hir_id (),
193 TyTy::TyVar (ty->get_ref ()), Mutability::Imm);
195 tree dynamic_object = TyTyResolveCompile::compile (ctx, &r);
196 tree dynamic_object_fields = TYPE_FIELDS (dynamic_object);
197 tree vtable_field = DECL_CHAIN (dynamic_object_fields);
198 rust_assert (TREE_CODE (TREE_TYPE (vtable_field)) == ARRAY_TYPE);
200 //' this assumes ordering and current the structure is
201 // __trait_object_ptr
202 // [list of function ptrs]
204 std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
205 probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
207 tree address_of_compiled_ref = null_pointer_node;
208 if (!actual->is_unit ())
209 address_of_compiled_ref = address_expression (compiled_ref, locus);
211 std::vector<tree> vtable_ctor_elems;
212 std::vector<unsigned long> vtable_ctor_idx;
213 unsigned long i = 0;
214 for (auto &bound : ty->get_object_items ())
216 const Resolver::TraitItemReference *item = bound.first;
217 const TyTy::TypeBoundPredicate *predicate = bound.second;
219 auto address = compute_address_for_trait_item (item, predicate,
220 probed_bounds_for_receiver,
221 actual, actual, locus);
222 vtable_ctor_elems.push_back (address);
223 vtable_ctor_idx.push_back (i++);
226 tree vtable_ctor
227 = Backend::array_constructor_expression (TREE_TYPE (vtable_field),
228 vtable_ctor_idx, vtable_ctor_elems,
229 locus);
231 std::vector<tree> dyn_ctor = {address_of_compiled_ref, vtable_ctor};
232 return Backend::constructor_expression (dynamic_object, false, dyn_ctor, -1,
233 locus);
236 tree
237 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)
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.
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
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
257 // FIXME this does not support super traits
259 TyTy::TypeBoundPredicateItem predicate_item
260 = predicate->lookup_associated_item (ref->get_identifier ());
261 rust_assert (!predicate_item.is_error ());
263 // this is the expected end type
264 TyTy::BaseType *trait_item_type = predicate_item.get_tyty_for_receiver (root);
265 rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
266 TyTy::FnType *trait_item_fntype
267 = static_cast<TyTy::FnType *> (trait_item_type);
269 // find impl-block for this trait-item-ref
270 HIR::ImplBlock *associated_impl_block = nullptr;
271 const Resolver::TraitReference *predicate_trait_ref = predicate->get ();
272 for (auto &item : receiver_bounds)
274 Resolver::TraitReference *trait_ref = item.first;
275 HIR::ImplBlock *impl_block = item.second;
276 if (predicate_trait_ref->is_equal (*trait_ref))
278 associated_impl_block = impl_block;
279 break;
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 rust_assert (associated_impl_block != nullptr);
288 // lookup self for the associated impl
289 std::unique_ptr<HIR::Type> &self_type_path
290 = associated_impl_block->get_type ();
291 TyTy::BaseType *self = nullptr;
292 bool ok = ctx->get_tyctx ()->lookup_type (
293 self_type_path->get_mappings ().get_hirid (), &self);
294 rust_assert (ok);
296 // lookup the predicate item from the self
297 TyTy::TypeBoundPredicate *self_bound = nullptr;
298 for (auto &bound : self->get_specified_bounds ())
300 const Resolver::TraitReference *bound_ref = bound.get ();
301 const Resolver::TraitReference *specified_ref = predicate->get ();
302 if (bound_ref->is_equal (*specified_ref))
304 self_bound = &bound;
305 break;
308 rust_assert (self_bound != nullptr);
310 // lookup the associated item from the associated impl block
311 TyTy::TypeBoundPredicateItem associated_self_item
312 = self_bound->lookup_associated_item (ref->get_identifier ());
313 rust_assert (!associated_self_item.is_error ());
315 // Lookup the impl-block for the associated impl_item if it exists
316 HIR::Function *associated_function = nullptr;
317 for (auto &impl_item : associated_impl_block->get_impl_items ())
319 bool is_function = impl_item->get_impl_item_type ()
320 == HIR::ImplItem::ImplItemType::FUNCTION;
321 if (!is_function)
322 continue;
324 HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
325 bool found_associated_item
326 = fn->get_function_name ().as_string ().compare (ref->get_identifier ())
327 == 0;
328 if (found_associated_item)
329 associated_function = fn;
332 // we found an impl_item for this
333 if (associated_function != nullptr)
335 // lookup the associated type for this item
336 TyTy::BaseType *lookup = nullptr;
337 bool ok = ctx->get_tyctx ()->lookup_type (
338 associated_function->get_mappings ().get_hirid (), &lookup);
339 rust_assert (ok);
340 rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
341 TyTy::FnType *lookup_fntype = static_cast<TyTy::FnType *> (lookup);
343 if (lookup_fntype->needs_substitution ())
345 TyTy::BaseType *infer
346 = Resolver::SubstMapper::InferSubst (lookup_fntype, UNDEF_LOCATION);
347 infer
348 = Resolver::unify_site (infer->get_ref (),
349 TyTy::TyWithLocation (trait_item_fntype),
350 TyTy::TyWithLocation (infer),
351 UNDEF_LOCATION);
352 rust_assert (infer->get_kind () == TyTy::TypeKind::FNDEF);
353 lookup_fntype = static_cast<TyTy::FnType *> (infer);
356 return CompileInherentImplItem::Compile (associated_function, ctx,
357 lookup_fntype, true, locus);
360 // we can only compile trait-items with a body
361 bool trait_item_has_definition = ref->is_optional ();
362 rust_assert (trait_item_has_definition);
364 HIR::TraitItem *trait_item = ref->get_hir_trait_item ();
365 return CompileTraitItem::Compile (trait_item, ctx, trait_item_fntype, true,
366 locus);
369 bool
370 HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
371 location_t lvalue_locus,
372 location_t rvalue_locus)
374 rust_assert (ltype != NULL_TREE);
375 rust_assert (rtype != NULL_TREE);
377 // lets just return ok as other errors have already occurred
378 if (ltype == error_mark_node || rtype == error_mark_node)
379 return true;
381 tree ltype_domain = TYPE_DOMAIN (ltype);
382 if (!ltype_domain)
383 return false;
385 if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
386 return false;
388 unsigned HOST_WIDE_INT ltype_length
389 = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
390 - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
391 TYPE_PRECISION (TREE_TYPE (ltype_domain)),
392 TYPE_SIGN (TREE_TYPE (ltype_domain)))
393 .to_uhwi ();
395 tree rtype_domain = TYPE_DOMAIN (rtype);
396 if (!rtype_domain)
397 return false;
399 if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
400 return false;
402 unsigned HOST_WIDE_INT rtype_length
403 = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
404 - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
405 TYPE_PRECISION (TREE_TYPE (rtype_domain)),
406 TYPE_SIGN (TREE_TYPE (rtype_domain)))
407 .to_uhwi ();
409 if (ltype_length != rtype_length)
411 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 return false;
420 return true;
423 } // namespace Compile
424 } // namespace Rust