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
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
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"
31 CompileCrate::CompileCrate (HIR::Crate
&crate
, Context
*ctx
)
32 : crate (crate
), ctx (ctx
)
35 CompileCrate::~CompileCrate () {}
38 CompileCrate::Compile (HIR::Crate
&crate
, Context
*ctx
)
40 CompileCrate
c (crate
, ctx
);
47 for (auto &item
: crate
.get_items ())
48 CompileItem::compile (item
.get (), ctx
);
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
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
);
66 rvalue
= resolve_adjustements (*adjustments
, rvalue
, rvalue_locus
);
69 return coercion_site1 (rvalue
, rval
, lval
, lvalue_locus
, rvalue_locus
);
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
)))
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
);
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
)))
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
)))
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
;
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
);
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
)))
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
)
167 bool valid_coercion
= actual
->get_kind () == TyTy::TypeKind::SLICE
168 || actual
->get_kind () == TyTy::TypeKind::ARRAY
;
170 return error_mark_node
;
172 // nothing to do here
173 if (actual
->get_kind () == TyTy::TypeKind::SLICE
)
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
);
186 HIRCompileBase::coerce_to_dyn_object (tree compiled_ref
,
187 const TyTy::BaseType
*actual
,
188 const TyTy::DynamicObjectType
*ty
,
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
;
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
++);
227 = Backend::array_constructor_expression (TREE_TYPE (vtable_field
),
228 vtable_ctor_idx
, vtable_ctor_elems
,
231 std::vector
<tree
> dyn_ctor
= {address_of_compiled_ref
, vtable_ctor
};
232 return Backend::constructor_expression (dynamic_object
, false, dyn_ctor
, -1,
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
*>>
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
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
;
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
);
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
))
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
;
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 ())
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
);
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
);
348 = Resolver::unify_site (infer
->get_ref (),
349 TyTy::TyWithLocation (trait_item_fntype
),
350 TyTy::TyWithLocation (infer
),
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,
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
)
381 tree ltype_domain
= TYPE_DOMAIN (ltype
);
385 if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain
)))
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
)))
395 tree rtype_domain
= TYPE_DOMAIN (rtype
);
399 if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain
)))
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
)))
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
416 ltype_length
, rtype_length
);
423 } // namespace Compile