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-type.h"
20 : #include "rust-constexpr.h"
21 : #include "rust-compile-base.h"
22 : #include "rust-type-util.h"
23 :
24 : #include "rust-tyty.h"
25 : #include "tree.h"
26 : #include "fold-const.h"
27 : #include "stor-layout.h"
28 :
29 : namespace Rust {
30 : namespace Compile {
31 :
32 : static const std::string RUST_ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR";
33 :
34 338717 : TyTyResolveCompile::TyTyResolveCompile (Context *ctx, bool trait_object_mode)
35 338717 : : ctx (ctx), trait_object_mode (trait_object_mode),
36 338717 : translated (error_mark_node)
37 338717 : {}
38 :
39 : tree
40 338717 : TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty,
41 : bool trait_object_mode)
42 : {
43 338717 : TyTyResolveCompile compiler (ctx, trait_object_mode);
44 338717 : const TyTy::BaseType *destructured = ty->destructure ();
45 338717 : destructured->accept_vis (compiler);
46 :
47 338717 : if (compiler.translated != error_mark_node
48 338717 : && TYPE_NAME (compiler.translated) != NULL)
49 : {
50 : // canonicalize the type
51 292866 : compiler.translated = ctx->insert_compiled_type (compiler.translated);
52 : }
53 :
54 338717 : return compiler.translated;
55 : }
56 :
57 : // see: gcc/c/c-decl.cc:8230-8241
58 : // https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fddfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241
59 : tree
60 6743 : TyTyResolveCompile::get_implicit_enumeral_node_type (TyTy::BaseType *repr)
61 : {
62 : // static tree enum_node = NULL_TREE;
63 : // if (enum_node == NULL_TREE)
64 : // {
65 : // enum_node = make_node (ENUMERAL_TYPE);
66 : // SET_TYPE_MODE (enum_node, TYPE_MODE (unsigned_type_node));
67 : // SET_TYPE_ALIGN (enum_node, TYPE_ALIGN (unsigned_type_node));
68 : // TYPE_USER_ALIGN (enum_node) = 0;
69 : // TYPE_UNSIGNED (enum_node) = 1;
70 : // TYPE_PRECISION (enum_node) = TYPE_PRECISION (unsigned_type_node);
71 : // TYPE_MIN_VALUE (enum_node) = TYPE_MIN_VALUE (unsigned_type_node);
72 : // TYPE_MAX_VALUE (enum_node) = TYPE_MAX_VALUE (unsigned_type_node);
73 :
74 : // // tree identifier = ctx->get_backend ()->get_identifier_node
75 : // // ("enumeral"); tree enum_decl
76 : // // = build_decl (BUILTINS_LOCATION, TYPE_DECL, identifier,
77 : // enum_node);
78 : // // TYPE_NAME (enum_node) = enum_decl;
79 : // }
80 : // return enum_node;
81 :
82 6743 : return compile (ctx, repr);
83 : }
84 :
85 : tree
86 33265 : TyTyResolveCompile::get_unit_type (Context *ctx)
87 : {
88 33265 : static tree unit_type;
89 33265 : if (unit_type == nullptr)
90 : {
91 4707 : auto cn = ctx->get_mappings ().get_current_crate ();
92 4707 : auto &c = ctx->get_mappings ().get_ast_crate (cn);
93 4707 : location_t locus = BUILTINS_LOCATION;
94 4707 : if (c.items.size () > 0)
95 : {
96 4701 : auto &item = c.items[0];
97 4701 : locus = item->get_locus ();
98 : }
99 :
100 4707 : auto unit_type_node = Backend::struct_type ({});
101 4707 : unit_type = Backend::named_type ("()", unit_type_node, locus);
102 : }
103 33265 : return unit_type;
104 : }
105 :
106 : void
107 0 : TyTyResolveCompile::visit (const TyTy::ErrorType &)
108 : {
109 0 : translated = error_mark_node;
110 0 : }
111 :
112 : void
113 629 : TyTyResolveCompile::visit (const TyTy::InferType &type)
114 : {
115 629 : const TyTy::BaseType *orig = &type;
116 629 : TyTy::BaseType *lookup = nullptr;
117 629 : bool ok = ctx->get_tyctx ()->lookup_type (type.get_ref (), &lookup);
118 629 : if (!ok)
119 : {
120 0 : translated = error_mark_node;
121 7 : return;
122 : }
123 :
124 629 : if (orig == lookup)
125 : {
126 7 : TyTy::BaseType *def = nullptr;
127 7 : if (type.default_type (&def))
128 : {
129 7 : translated = TyTyResolveCompile::compile (ctx, def);
130 7 : return;
131 : }
132 :
133 0 : translated = error_mark_node;
134 0 : return;
135 : }
136 :
137 622 : translated = TyTyResolveCompile::compile (ctx, lookup);
138 : }
139 :
140 : void
141 1 : TyTyResolveCompile::visit (const TyTy::ParamType &type)
142 : {
143 1 : translated = error_mark_node;
144 1 : }
145 :
146 : void
147 0 : TyTyResolveCompile::visit (const TyTy::ConstParamType &type)
148 : {
149 0 : translated = error_mark_node;
150 0 : }
151 :
152 : void
153 0 : TyTyResolveCompile::visit (const TyTy::ConstValueType &type)
154 : {
155 0 : translated = error_mark_node;
156 0 : }
157 :
158 : void
159 0 : TyTyResolveCompile::visit (const TyTy::ConstInferType &type)
160 : {
161 0 : translated = error_mark_node;
162 0 : }
163 :
164 : void
165 0 : TyTyResolveCompile::visit (const TyTy::ConstErrorType &type)
166 : {
167 0 : translated = error_mark_node;
168 0 : }
169 :
170 : void
171 378 : TyTyResolveCompile::visit (const TyTy::ProjectionType &type)
172 : {
173 : // workaround to get around const here
174 378 : TyTy::ProjectionType *projection
175 378 : = static_cast<TyTy::ProjectionType *> (type.clone ());
176 378 : auto normalized
177 378 : = Resolver::normalize_projection (projection, BUILTINS_LOCATION, false,
178 : false);
179 378 : if (normalized == projection)
180 : {
181 0 : translated = error_mark_node;
182 0 : return;
183 : }
184 :
185 378 : translated = TyTyResolveCompile::compile (ctx, normalized, false);
186 : }
187 :
188 : void
189 0 : TyTyResolveCompile::visit (const TyTy::PlaceholderType &type)
190 : {
191 0 : translated = error_mark_node;
192 0 : }
193 :
194 : void
195 243 : TyTyResolveCompile::visit (const TyTy::ClosureType &type)
196 : {
197 243 : auto &mappings = ctx->get_mappings ();
198 :
199 243 : std::vector<Backend::typed_identifier> fields;
200 :
201 243 : size_t i = 0;
202 334 : for (const auto &capture : type.get_captures ())
203 : {
204 : // lookup the HirId
205 91 : tl::optional<HirId> hid = mappings.lookup_node_to_hir (capture);
206 91 : rust_assert (hid.has_value ());
207 91 : auto ref = hid.value ();
208 :
209 : // lookup the var decl type
210 91 : TyTy::BaseType *lookup = nullptr;
211 91 : bool found = ctx->get_tyctx ()->lookup_type (ref, &lookup);
212 91 : rust_assert (found);
213 :
214 : // FIXME get the var pattern name
215 91 : std::string mappings_name = "capture_" + std::to_string (i);
216 :
217 : // FIXME
218 : // this should be based on the closure move-ability
219 91 : tree decl_type = TyTyResolveCompile::compile (ctx, lookup);
220 91 : tree capture_type = build_reference_type (decl_type);
221 91 : fields.emplace_back (mappings_name, capture_type,
222 91 : type.get_ident ().locus);
223 91 : }
224 :
225 243 : tree type_record = Backend::struct_type (fields);
226 243 : RS_CLOSURE_FLAG (type_record) = 1;
227 :
228 243 : std::string named_struct_str
229 486 : = type.get_ident ().path.get () + "::{{closure}}";
230 243 : translated = Backend::named_type (named_struct_str, type_record,
231 243 : type.get_ident ().locus);
232 243 : }
233 :
234 : void
235 19006 : TyTyResolveCompile::visit (const TyTy::FnType &type)
236 : {
237 19006 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
238 19006 : std::vector<Backend::typed_identifier> parameters;
239 19006 : std::vector<Backend::typed_identifier> results;
240 :
241 : // we can only return unit-type if its not the C ABI because it will expect
242 : // void
243 19006 : auto hir_type = type.get_return_type ()->destructure ();
244 19006 : bool return_is_unit = hir_type->is_unit ();
245 19006 : bool is_c_abi = type.get_abi () == ABI::C;
246 19006 : bool should_be_void = is_c_abi && return_is_unit;
247 19006 : if (!should_be_void)
248 : {
249 17906 : auto ret = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode);
250 17906 : location_t return_type_locus
251 17906 : = ctx->get_mappings ().lookup_location (hir_type->get_ref ());
252 17906 : results.emplace_back ("_", ret, return_type_locus);
253 : }
254 :
255 38359 : for (auto ¶m_pair : type.get_params ())
256 : {
257 19353 : auto param_tyty = param_pair.get_type ();
258 19353 : auto compiled_param_type
259 19353 : = TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode);
260 :
261 19353 : parameters.emplace_back (param_pair.get_pattern ().to_string (),
262 : compiled_param_type,
263 38706 : ctx->get_mappings ().lookup_location (
264 : param_tyty->get_ref ()));
265 : }
266 :
267 19006 : if (!type.is_variadic ())
268 36246 : translated = Backend::function_type (receiver, parameters, results, NULL,
269 18123 : type.get_ident ().locus);
270 : else
271 883 : translated
272 883 : = Backend::function_type_variadic (receiver, parameters, results, NULL,
273 883 : type.get_ident ().locus);
274 19006 : }
275 :
276 : void
277 110 : TyTyResolveCompile::visit (const TyTy::FnPtr &type)
278 : {
279 110 : tree result_type = TyTyResolveCompile::compile (ctx, type.get_return_type ());
280 :
281 110 : std::vector<tree> parameters;
282 :
283 110 : auto ¶ms = type.get_params ();
284 200 : for (auto &p : params)
285 : {
286 90 : tree pty = TyTyResolveCompile::compile (ctx, p.get_tyty ());
287 90 : parameters.push_back (pty);
288 : }
289 :
290 110 : translated = Backend::function_ptr_type (result_type, parameters,
291 110 : type.get_ident ().locus);
292 110 : }
293 :
294 : void
295 22216 : TyTyResolveCompile::visit (const TyTy::ADTType &type)
296 : {
297 22216 : tree type_record = error_mark_node;
298 :
299 22216 : TyTy::ADTType::ReprOptions repr = type.get_repr_options ();
300 22216 : if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
301 : {
302 90 : rust_assert (type.number_of_variants () == 1);
303 90 : TyTy::VariantDef &variant = *type.get_variants ().at (0);
304 :
305 90 : if (variant.num_fields () == 0)
306 : {
307 : // 0-field transparent repr
308 : // Rustonomicon states that transparent structs should have a single
309 : // non-zero-sized field, but rustc compiles one with 0 fields happily
310 : // without errors, so not sure what's the correct treatment.
311 : //
312 : // For now, treat it as a unit struct
313 0 : type_record = Backend::struct_type ({});
314 : }
315 90 : else if (variant.num_fields () == 1)
316 : {
317 : // single field transparent repr
318 90 : const TyTy::StructFieldType *field = variant.get_field_at_index (0);
319 90 : type_record
320 90 : = TyTyResolveCompile::compile (ctx, field->get_field_type ());
321 : }
322 : else
323 : {
324 : // more than one field - typechecking already ensures there's only one
325 : // non-zero-sized field, just compile accessor for that
326 : // non-zero-sized.
327 0 : for (size_t i = 0; i < variant.num_fields (); i++)
328 : {
329 0 : auto field_ty = variant.get_field_at_index (i)->get_field_type ();
330 0 : if (!field_ty->is_zero_sized ())
331 : {
332 0 : type_record = TyTyResolveCompile::compile (ctx, field_ty);
333 : }
334 : }
335 : }
336 : }
337 22126 : else if (repr.repr_kind == TyTy::ADTType::ReprKind::SIMD)
338 : {
339 16 : TyTy::VariantDef &variant = *type.get_variants ().at (0);
340 16 : auto element = variant.get_fields ().at (0)->get_field_type ();
341 16 : auto inner_type = compile (ctx, element);
342 :
343 16 : type_record = build_vector_type (inner_type, variant.num_fields ());
344 : }
345 22110 : else if (type.get_adt_kind () == TyTy::ADTType::ADTKind::EXTERN)
346 : {
347 : // Extern types are codegen'd as C's void type. They can only be used
348 : // through indirection, so they're effectively always codegen'd as
349 : // `void *` types.
350 6 : type_record = void_type_node;
351 : }
352 22104 : else if (!type.is_enum ())
353 : {
354 15361 : rust_assert (type.number_of_variants () == 1);
355 :
356 15361 : TyTy::VariantDef &variant = *type.get_variants ().at (0);
357 15361 : std::vector<Backend::typed_identifier> fields;
358 42893 : for (size_t i = 0; i < variant.num_fields (); i++)
359 : {
360 27532 : const TyTy::StructFieldType *field = variant.get_field_at_index (i);
361 27532 : tree compiled_field_ty
362 27532 : = TyTyResolveCompile::compile (ctx, field->get_field_type ());
363 :
364 27532 : fields.emplace_back (field->get_name (), compiled_field_ty,
365 55064 : ctx->get_mappings ().lookup_location (
366 : type.get_ty_ref ()));
367 : }
368 :
369 15361 : if (!type.is_union () && variant.num_fields () > 0)
370 : {
371 13214 : const TyTy::StructFieldType *tail_field
372 13214 : = variant.get_field_at_index (variant.num_fields () - 1);
373 13214 : TyTy::BaseType *tail_ty = tail_field->get_field_type ();
374 :
375 13214 : if (tail_ty->is_unsized ())
376 : {
377 57 : tree raw_dst_type = error_mark_node;
378 :
379 57 : if (tail_ty->get_kind () == TyTy::TypeKind::SLICE)
380 : {
381 40 : auto slice = static_cast<TyTy::SliceType *> (tail_ty);
382 40 : tree elem_type
383 40 : = TyTyResolveCompile::compile (ctx,
384 40 : slice->get_element_type ());
385 40 : raw_dst_type = build_array_type (elem_type, NULL_TREE);
386 : }
387 17 : else if (tail_ty->get_kind () == TyTy::TypeKind::DYNAMIC)
388 : {
389 10 : raw_dst_type = make_node (RECORD_TYPE);
390 10 : TYPE_SIZE (raw_dst_type) = bitsize_zero_node;
391 10 : TYPE_SIZE_UNIT (raw_dst_type) = size_zero_node;
392 10 : layout_type (raw_dst_type);
393 : }
394 : else
395 : {
396 7 : raw_dst_type = fields.back ().type;
397 : }
398 57 : fields.pop_back ();
399 57 : fields.emplace_back (tail_field->get_name (), raw_dst_type,
400 114 : type.get_locus ());
401 : }
402 : }
403 15361 : type_record = type.is_union () ? Backend::union_type (fields, false)
404 15141 : : Backend::struct_type (fields, false);
405 15361 : }
406 : else
407 : {
408 : // see:
409 : // https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241
410 : //
411 : // enums are actually a big union so for example the rust enum:
412 : //
413 : // enum AnEnum {
414 : // A,
415 : // B,
416 : // C (char),
417 : // D { x: i64, y: i64 },
418 : // }
419 : //
420 : // we actually turn this into
421 : //
422 : // union {
423 : // struct A { int RUST$ENUM$DISR; }; <- this is a data-less variant
424 : // struct B { int RUST$ENUM$DISR; }; <- this is a data-less variant
425 : // struct C { int RUST$ENUM$DISR; char __0; };
426 : // struct D { int RUST$ENUM$DISR; i64 x; i64 y; };
427 : // }
428 : //
429 : // Ada, qual_union_types might still work for this but I am not 100% sure.
430 : // I ran into some issues lets reuse our normal union and ask Ada people
431 : // about it.
432 : //
433 : // I think the above is actually wrong and it should actually be this
434 : //
435 : // struct {
436 : // int RUST$ENUM$DISR; // take into account the repr for this TODO
437 : // union {
438 : // // Variant A
439 : // struct {
440 : // // No additional fields
441 : // } A;
442 :
443 : // // Variant B
444 : // struct {
445 : // // No additional fields
446 : // } B;
447 :
448 : // // Variant C
449 : // struct {
450 : // char c;
451 : // } C;
452 :
453 : // // Variant D
454 : // struct {
455 : // int64_t x;
456 : // int64_t y;
457 : // } D;
458 : // } payload; // The union of all variant data
459 : // };
460 :
461 6743 : std::vector<tree> variant_records;
462 23603 : for (auto &variant : type.get_variants ())
463 : {
464 16860 : std::vector<Backend::typed_identifier> fields;
465 23228 : for (size_t i = 0; i < variant->num_fields (); i++)
466 : {
467 6368 : const TyTy::StructFieldType *field
468 6368 : = variant->get_field_at_index (i);
469 6368 : tree compiled_field_ty
470 6368 : = TyTyResolveCompile::compile (ctx, field->get_field_type ());
471 :
472 6368 : std::string field_name = field->get_name ();
473 6368 : if (variant->get_variant_type ()
474 : == TyTy::VariantDef::VariantType::TUPLE)
475 4863 : field_name = "__" + field->get_name ();
476 :
477 12736 : fields.emplace_back (field_name, compiled_field_ty,
478 6368 : ctx->get_mappings ().lookup_location (
479 : type.get_ty_ref ()));
480 6368 : }
481 :
482 16860 : tree variant_record = Backend::struct_type (fields);
483 16860 : tree named_variant_record
484 16860 : = Backend::named_type (variant->get_ident ().path.get (),
485 33720 : variant_record, variant->get_ident ().locus);
486 :
487 : // add them to the list
488 16860 : variant_records.push_back (named_variant_record);
489 16860 : }
490 :
491 : // now we need to make the actual union, but first we need to make
492 : // named_type TYPE_DECL's out of the variants
493 :
494 6743 : size_t i = 0;
495 6743 : std::vector<Backend::typed_identifier> enum_fields;
496 23603 : for (auto &variant_record : variant_records)
497 : {
498 16860 : TyTy::VariantDef *variant = type.get_variants ().at (i++);
499 16860 : std::string implicit_variant_name = variant->get_identifier ();
500 :
501 33720 : enum_fields.emplace_back (implicit_variant_name, variant_record,
502 16860 : ctx->get_mappings ().lookup_location (
503 : type.get_ty_ref ()));
504 16860 : }
505 :
506 : //
507 6743 : location_t locus = ctx->get_mappings ().lookup_location (type.get_ref ());
508 :
509 : // finally make the union or the enum
510 6743 : tree variants_union = Backend::union_type (enum_fields, false);
511 6743 : layout_type (variants_union);
512 6743 : tree named_union_record
513 6743 : = Backend::named_type ("payload", variants_union, locus);
514 :
515 : // create the overall struct
516 6743 : tree enumeral_type = TyTyResolveCompile::get_implicit_enumeral_node_type (
517 6743 : type.get_repr_options ().repr);
518 6743 : Backend::typed_identifier discrim (RUST_ENUM_DISR_FIELD_NAME,
519 6743 : enumeral_type, locus);
520 6743 : Backend::typed_identifier variants_union_field ("payload",
521 : named_union_record,
522 6743 : locus);
523 :
524 6743 : std::vector<Backend::typed_identifier> fields
525 6743 : = {discrim, variants_union_field};
526 6743 : type_record = Backend::struct_type (fields, false);
527 6743 : }
528 :
529 : // Handle repr options
530 : // TODO: "packed" should only narrow type alignment and "align" should only
531 : // widen it. Do we need to check and enforce this here, or is it taken care of
532 : // later on in the gcc middle-end?
533 22216 : if (repr.repr_kind != TyTy::ADTType::ReprKind::TRANSPARENT)
534 : {
535 22126 : if (repr.pack)
536 : {
537 10 : TYPE_PACKED (type_record) = 1;
538 10 : if (repr.pack > 1)
539 : {
540 5 : SET_TYPE_ALIGN (type_record, repr.pack * 8);
541 5 : TYPE_USER_ALIGN (type_record) = 1;
542 : }
543 : }
544 22116 : else if (repr.align)
545 : {
546 10 : SET_TYPE_ALIGN (type_record, repr.align * 8);
547 10 : TYPE_USER_ALIGN (type_record) = 1;
548 : }
549 22126 : layout_type (type_record);
550 : }
551 :
552 22216 : std::string named_struct_str
553 22216 : = type.get_ident ().path.get () + type.subst_as_string ();
554 22216 : translated = Backend::named_type (named_struct_str, type_record,
555 22216 : type.get_ident ().locus);
556 22216 : }
557 :
558 : void
559 18651 : TyTyResolveCompile::visit (const TyTy::TupleType &type)
560 : {
561 18651 : if (type.num_fields () == 0)
562 : {
563 16486 : translated = get_unit_type (ctx);
564 16486 : return;
565 : }
566 :
567 : // create implicit struct
568 2165 : std::vector<Backend::typed_identifier> fields;
569 6669 : for (size_t i = 0; i < type.num_fields (); i++)
570 : {
571 4504 : TyTy::BaseType *field = type.get_field (i);
572 4504 : tree compiled_field_ty = TyTyResolveCompile::compile (ctx, field);
573 :
574 : // rustc uses the convention __N, where N is an integer, to
575 : // name the fields of a tuple. We follow this as well,
576 : // because this is used by GDB. One further reason to prefer
577 : // this, rather than simply emitting the integer, is that this
578 : // approach makes it simpler to use a C-only debugger, or
579 : // GDB's C mode, when debugging Rust.
580 4504 : fields.emplace_back ("__" + std::to_string (i), compiled_field_ty,
581 9008 : ctx->get_mappings ().lookup_location (
582 : type.get_ty_ref ()));
583 : }
584 :
585 2165 : tree struct_type_record = Backend::struct_type (fields);
586 2165 : translated = Backend::named_type (type.get_name (), struct_type_record,
587 2165 : type.get_ident ().locus);
588 2165 : }
589 :
590 : void
591 4593 : TyTyResolveCompile::visit (const TyTy::ArrayType &type)
592 : {
593 4593 : tree element_type
594 4593 : = TyTyResolveCompile::compile (ctx, type.get_element_type ());
595 4593 : auto const_capacity = type.get_capacity ();
596 :
597 : // Check if capacity is a const type
598 4593 : if (const_capacity->get_kind () != TyTy::TypeKind::CONST)
599 : {
600 0 : rust_error_at (type.get_locus (), "array capacity is not a const type");
601 0 : translated = error_mark_node;
602 0 : return;
603 : }
604 :
605 4593 : auto *capacity_const = const_capacity->as_const_type ();
606 :
607 4593 : rust_assert (capacity_const->const_kind ()
608 : == TyTy::BaseConstType::ConstKind::Value);
609 4593 : auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
610 4593 : auto folded_capacity_expr = capacity_value.get_value ();
611 :
612 : // build_index_type takes the maximum index, which is one less than
613 : // the length.
614 4593 : tree index_type_tree = build_index_type (
615 : fold_build2 (MINUS_EXPR, sizetype, folded_capacity_expr, size_one_node));
616 :
617 4593 : translated = build_array_type (element_type, index_type_tree, false);
618 : }
619 :
620 : void
621 251 : TyTyResolveCompile::visit (const TyTy::SliceType &type)
622 : {
623 251 : tree type_record = create_slice_type_record (type);
624 :
625 251 : std::string named_struct_str
626 502 : = std::string ("[") + type.get_element_type ()->get_name () + "]";
627 251 : translated = Backend::named_type (named_struct_str, type_record,
628 251 : type.get_ident ().locus);
629 251 : }
630 :
631 : void
632 11016 : TyTyResolveCompile::visit (const TyTy::BoolType &)
633 : {
634 11016 : translated
635 11016 : = Backend::named_type ("bool", boolean_type_node, BUILTINS_LOCATION);
636 11016 : }
637 :
638 : void
639 80095 : TyTyResolveCompile::visit (const TyTy::IntType &type)
640 : {
641 80095 : switch (type.get_int_kind ())
642 : {
643 10499 : case TyTy::IntType::I8:
644 10499 : translated = Backend::named_type ("i8", Backend::integer_type (false, 8),
645 : BUILTINS_LOCATION);
646 10499 : return;
647 :
648 5894 : case TyTy::IntType::I16:
649 5894 : translated
650 5894 : = Backend::named_type ("i16", Backend::integer_type (false, 16),
651 : BUILTINS_LOCATION);
652 5894 : return;
653 :
654 52203 : case TyTy::IntType::I32:
655 52203 : translated
656 52203 : = Backend::named_type ("i32", Backend::integer_type (false, 32),
657 : BUILTINS_LOCATION);
658 52203 : return;
659 :
660 6063 : case TyTy::IntType::I64:
661 6063 : translated
662 6063 : = Backend::named_type ("i64", Backend::integer_type (false, 64),
663 : BUILTINS_LOCATION);
664 6063 : return;
665 :
666 5436 : case TyTy::IntType::I128:
667 5436 : translated
668 5436 : = Backend::named_type ("i128", Backend::integer_type (false, 128),
669 : BUILTINS_LOCATION);
670 5436 : return;
671 : }
672 : }
673 :
674 : void
675 61779 : TyTyResolveCompile::visit (const TyTy::UintType &type)
676 : {
677 61779 : switch (type.get_uint_kind ())
678 : {
679 16485 : case TyTy::UintType::U8:
680 16485 : translated = Backend::named_type ("u8", Backend::integer_type (true, 8),
681 : BUILTINS_LOCATION);
682 16485 : return;
683 :
684 9932 : case TyTy::UintType::U16:
685 9932 : translated = Backend::named_type ("u16", Backend::integer_type (true, 16),
686 : BUILTINS_LOCATION);
687 9932 : return;
688 :
689 14867 : case TyTy::UintType::U32:
690 14867 : translated = Backend::named_type ("u32", Backend::integer_type (true, 32),
691 : BUILTINS_LOCATION);
692 14867 : return;
693 :
694 15233 : case TyTy::UintType::U64:
695 15233 : translated = Backend::named_type ("u64", Backend::integer_type (true, 64),
696 : BUILTINS_LOCATION);
697 15233 : return;
698 :
699 5262 : case TyTy::UintType::U128:
700 5262 : translated
701 5262 : = Backend::named_type ("u128", Backend::integer_type (true, 128),
702 : BUILTINS_LOCATION);
703 5262 : return;
704 : }
705 : }
706 :
707 : void
708 15575 : TyTyResolveCompile::visit (const TyTy::FloatType &type)
709 : {
710 15575 : switch (type.get_float_kind ())
711 : {
712 7579 : case TyTy::FloatType::F32:
713 7579 : translated = Backend::named_type ("f32", Backend::float_type (32),
714 : BUILTINS_LOCATION);
715 7579 : return;
716 :
717 7996 : case TyTy::FloatType::F64:
718 7996 : translated = Backend::named_type ("f64", Backend::float_type (64),
719 : BUILTINS_LOCATION);
720 7996 : return;
721 : }
722 : }
723 :
724 : void
725 38228 : TyTyResolveCompile::visit (const TyTy::USizeType &)
726 : {
727 38228 : translated
728 38228 : = Backend::named_type ("usize",
729 : Backend::integer_type (true,
730 : Backend::get_pointer_size ()),
731 : BUILTINS_LOCATION);
732 38228 : }
733 :
734 : void
735 19516 : TyTyResolveCompile::visit (const TyTy::ISizeType &)
736 : {
737 19516 : translated
738 19516 : = Backend::named_type ("isize",
739 : Backend::integer_type (false,
740 : Backend::get_pointer_size ()),
741 : BUILTINS_LOCATION);
742 19516 : }
743 :
744 : void
745 5693 : TyTyResolveCompile::visit (const TyTy::CharType &)
746 : {
747 5693 : translated
748 5693 : = Backend::named_type ("char", Backend::wchar_type (), BUILTINS_LOCATION);
749 5693 : }
750 :
751 : void
752 19467 : TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
753 : {
754 19467 : const TyTy::SliceType *slice = nullptr;
755 19467 : const TyTy::StrType *str = nullptr;
756 19467 : const TyTy::DynamicObjectType *dyn = nullptr;
757 19467 : const TyTy::ADTType *adt = nullptr;
758 19467 : if (type.is_dyn_slice_type (&slice))
759 : {
760 623 : tree type_record = create_slice_type_record (*slice);
761 623 : std::string dyn_slice_type_str
762 1868 : = std::string (type.is_mutable () ? "&mut " : "&") + "["
763 1869 : + slice->get_element_type ()->get_name () + "]";
764 :
765 623 : translated = Backend::named_type (dyn_slice_type_str, type_record,
766 : slice->get_locus ());
767 :
768 623 : return;
769 623 : }
770 18844 : else if (type.is_dyn_str_type (&str))
771 : {
772 4162 : tree type_record = create_str_type_record (*str);
773 4162 : std::string dyn_str_type_str
774 12486 : = std::string (type.is_mutable () ? "&mut " : "&") + "str";
775 :
776 4162 : translated = Backend::named_type (dyn_str_type_str, type_record,
777 : str->get_locus ());
778 :
779 4162 : return;
780 4162 : }
781 14682 : else if (type.is_dyn_obj_type (&dyn))
782 : {
783 526 : tree type_record = create_dyn_obj_record (*dyn);
784 526 : std::string dyn_str_type_str
785 1052 : = std::string (type.is_mutable () ? "&mut " : "& ") + dyn->get_name ();
786 :
787 526 : translated = Backend::named_type (dyn_str_type_str, type_record,
788 : dyn->get_locus ());
789 :
790 526 : return;
791 526 : }
792 14156 : else if (type.is_dyn_adt_type (&adt))
793 : {
794 76 : tree type_record = create_dyn_adt_record (*adt);
795 76 : std::string dyn_str_type_str
796 152 : = std::string (type.is_mutable () ? "&mut" : "& ") + adt->get_name ();
797 :
798 76 : translated = Backend::named_type (dyn_str_type_str, type_record,
799 : adt->get_locus ());
800 76 : return;
801 76 : }
802 : // Check for CStr, create a specific record for it
803 14080 : else if (type.is_dyn_cstr_type (&adt))
804 : {
805 : // CStr in core crate is defined as the following:
806 : //
807 : // #[repr(transparent)]
808 : // pub struct CStr {
809 : // inner: [u8]
810 : // }
811 : //
812 : // Reuse the c_char (u8) slice fat-pointer layout
813 0 : TyTy::BaseType *u8 = nullptr;
814 0 : ctx->get_tyctx ()->lookup_builtin ("u8", &u8);
815 : // Create a synthetic SliceType over u8 and use that record layout
816 0 : TyTy::SliceType synthetic_slice (adt->get_ref (), adt->get_ident ().locus,
817 0 : TyTy::TyVar (u8->get_ref ()));
818 0 : tree type_record = create_slice_type_record (synthetic_slice);
819 0 : translated
820 0 : = Backend::named_type ("&CStr", type_record, adt->get_ident ().locus);
821 :
822 0 : return;
823 0 : }
824 :
825 14080 : tree base_compiled_type
826 14080 : = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
827 14080 : if (type.is_mutable ())
828 : {
829 1346 : translated = Backend::reference_type (base_compiled_type);
830 : }
831 : else
832 : {
833 : // https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html
834 : // If you have a reference &T, then normally in Rust the compiler performs
835 : // optimizations based on the knowledge that &T points to immutable data.
836 : // Mutating that data, for example through an alias or by transmuting a &T
837 : // into a &mut T, is considered undefined behavior. UnsafeCell<T> opts-out
838 : // of the immutability guarantee for &T: a shared reference &UnsafeCell<T>
839 : // may point to data that is being mutated. This is called “interior
840 : // mutability”.
841 12734 : auto base = type.get_base ()->contains_unsafe_cell ()
842 12734 : ? base_compiled_type
843 12732 : : Backend::immutable_type (base_compiled_type);
844 12734 : translated = Backend::reference_type (base);
845 : }
846 : }
847 :
848 : void
849 11333 : TyTyResolveCompile::visit (const TyTy::PointerType &type)
850 : {
851 11333 : const TyTy::SliceType *slice = nullptr;
852 11333 : const TyTy::StrType *str = nullptr;
853 11333 : const TyTy::DynamicObjectType *dyn = nullptr;
854 11333 : const TyTy::ADTType *adt = nullptr;
855 11333 : if (type.is_dyn_slice_type (&slice))
856 : {
857 576 : tree type_record = create_slice_type_record (*slice);
858 576 : std::string dyn_slice_type_str
859 1668 : = std::string (type.is_mutable () ? "*mut " : "*const ") + "["
860 1728 : + slice->get_element_type ()->get_name () + "]";
861 :
862 576 : translated = Backend::named_type (dyn_slice_type_str, type_record,
863 : slice->get_locus ());
864 :
865 576 : return;
866 576 : }
867 10757 : else if (type.is_dyn_str_type (&str))
868 : {
869 2671 : tree type_record = create_str_type_record (*str);
870 2671 : std::string dyn_str_type_str
871 8013 : = std::string (type.is_mutable () ? "*mut " : "*const ") + "str";
872 :
873 2671 : translated = Backend::named_type (dyn_str_type_str, type_record,
874 : str->get_locus ());
875 :
876 2671 : return;
877 2671 : }
878 8086 : else if (type.is_dyn_obj_type (&dyn))
879 : {
880 19 : tree type_record = create_dyn_obj_record (*dyn);
881 19 : std::string dyn_str_type_str
882 55 : = std::string (type.is_mutable () ? "*mut " : "*const ")
883 38 : + dyn->get_name ();
884 :
885 19 : translated = Backend::named_type (dyn_str_type_str, type_record,
886 : dyn->get_locus ());
887 :
888 19 : return;
889 19 : }
890 8067 : else if (type.is_dyn_adt_type (&adt))
891 : {
892 21 : tree type_record = create_dyn_adt_record (*adt);
893 21 : std::string dyn_str_type_str
894 63 : = std::string (type.is_mutable () ? "*mut" : "*const ")
895 42 : + adt->get_name ();
896 :
897 21 : translated = Backend::named_type (dyn_str_type_str, type_record,
898 : adt->get_locus ());
899 21 : return;
900 21 : }
901 :
902 8046 : tree base_compiled_type
903 8046 : = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
904 8046 : if (type.is_mutable ())
905 : {
906 2086 : translated = Backend::pointer_type (base_compiled_type);
907 : }
908 : else
909 : {
910 5960 : auto base = Backend::immutable_type (base_compiled_type);
911 5960 : translated = Backend::pointer_type (base);
912 : }
913 : }
914 :
915 : void
916 4733 : TyTyResolveCompile::visit (const TyTy::StrType &type)
917 : {
918 4733 : tree raw_str = create_str_type_record (type);
919 4733 : translated = Backend::named_type ("str", raw_str, BUILTINS_LOCATION);
920 4733 : }
921 :
922 : void
923 5016 : TyTyResolveCompile::visit (const TyTy::NeverType &)
924 : {
925 5016 : translated = get_unit_type (ctx);
926 5016 : }
927 :
928 : void
929 188 : TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type)
930 : {
931 188 : if (trait_object_mode)
932 : {
933 0 : translated = Backend::integer_type (true, Backend::get_pointer_size ());
934 0 : return;
935 : }
936 :
937 188 : tree type_record = create_dyn_obj_record (type);
938 188 : translated = Backend::named_type (type.get_name (), type_record,
939 188 : type.get_ident ().locus);
940 : }
941 :
942 : void
943 0 : TyTyResolveCompile::visit (const TyTy::OpaqueType &type)
944 : {
945 0 : rust_assert (type.can_resolve ());
946 0 : auto underlying = type.resolve ();
947 0 : translated = TyTyResolveCompile::compile (ctx, underlying, trait_object_mode);
948 0 : }
949 :
950 : tree
951 742 : TyTyResolveCompile::create_dyn_obj_record (const TyTy::DynamicObjectType &type)
952 : {
953 742 : location_t locus = ctx->get_mappings ().lookup_location (type.get_ty_ref ());
954 : // create implicit struct
955 742 : std::vector<Backend::typed_identifier> fields;
956 :
957 742 : tree voidptr_ty = build_pointer_type (void_type_node);
958 :
959 742 : fields.emplace_back ("data", voidptr_ty, locus);
960 :
961 742 : std::vector<Backend::typed_identifier> vtable_fields;
962 :
963 : // drop_in_place is not implemented yet!
964 742 : vtable_fields.emplace_back ("__drop_in_place", voidptr_ty, locus);
965 742 : vtable_fields.emplace_back ("__size", size_type_node, locus);
966 742 : vtable_fields.emplace_back ("__align", size_type_node, locus);
967 :
968 742 : size_t items_size = type.get_object_items ().size ();
969 1745 : for (size_t method_idx = 0; method_idx < items_size; method_idx++)
970 1003 : vtable_fields.emplace_back ("__method_" + std::to_string (method_idx),
971 : voidptr_ty, locus);
972 :
973 742 : tree vtable_record = Backend::struct_type (vtable_fields);
974 742 : tree vtable_ptr_ty = build_pointer_type (vtable_record);
975 :
976 742 : fields.emplace_back ("vtable", vtable_ptr_ty, locus);
977 :
978 742 : tree record = Backend::struct_type (fields);
979 742 : RS_DST_FLAG (record) = 1;
980 742 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
981 :
982 742 : return record;
983 742 : }
984 :
985 : tree
986 1450 : TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type)
987 : {
988 : // lookup usize
989 1450 : TyTy::BaseType *usize = nullptr;
990 1450 : bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
991 1450 : rust_assert (ok);
992 :
993 1450 : tree element_type
994 1450 : = TyTyResolveCompile::compile (ctx, type.get_element_type ());
995 1450 : tree data_field_ty = build_pointer_type (element_type);
996 1450 : Backend::typed_identifier data_field ("data", data_field_ty,
997 1450 : type.get_locus ());
998 :
999 1450 : tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
1000 1450 : Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
1001 :
1002 1450 : tree record = Backend::struct_type ({data_field, len_field});
1003 1450 : RS_DST_FLAG (record) = 1;
1004 1450 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
1005 :
1006 1450 : return record;
1007 : }
1008 :
1009 : tree
1010 11566 : TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type)
1011 : {
1012 : // lookup usize
1013 11566 : TyTy::BaseType *usize = nullptr;
1014 11566 : bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
1015 11566 : rust_assert (ok);
1016 :
1017 11566 : tree char_ptr = build_pointer_type (char_type_node);
1018 11566 : tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
1019 :
1020 11566 : tree element_type = const_char_type;
1021 11566 : tree data_field_ty = build_pointer_type (element_type);
1022 11566 : Backend::typed_identifier data_field ("data", data_field_ty,
1023 11566 : type.get_locus ());
1024 :
1025 11566 : tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
1026 11566 : Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
1027 :
1028 11566 : tree record = Backend::struct_type ({data_field, len_field});
1029 11566 : RS_DST_FLAG (record) = 1;
1030 11566 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
1031 :
1032 11566 : return record;
1033 : }
1034 :
1035 : tree
1036 103 : TyTyResolveCompile::create_dyn_adt_record (const TyTy::ADTType &type)
1037 : {
1038 103 : location_t locus = type.get_locus ();
1039 :
1040 103 : tree adt_record = TyTyResolveCompile::compile (ctx, &type);
1041 103 : tree data_field_ty = build_pointer_type (adt_record);
1042 103 : Backend::typed_identifier data_field ("data", data_field_ty, locus);
1043 :
1044 103 : rust_assert (type.number_of_variants () > 0);
1045 103 : TyTy::VariantDef &variant = *type.get_variants ().front ();
1046 103 : rust_assert (variant.num_fields () > 0);
1047 :
1048 103 : const TyTy::BaseType *tail_field
1049 103 : = variant.get_field_at_index (variant.num_fields () - 1)->get_field_type ();
1050 :
1051 103 : tree meta_field_ty = error_mark_node;
1052 103 : std::string meta = "meta";
1053 :
1054 103 : if (tail_field->get_kind () == TyTy::TypeKind::SLICE
1055 103 : || tail_field->get_kind () == TyTy::TypeKind::STR)
1056 : {
1057 88 : TyTy::BaseType *usize = nullptr;
1058 88 : bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
1059 88 : rust_assert (ok);
1060 88 : meta_field_ty = TyTyResolveCompile::compile (ctx, usize);
1061 88 : meta = "len";
1062 : }
1063 15 : else if (tail_field->get_kind () == TyTy::TypeKind::DYNAMIC)
1064 : {
1065 9 : const TyTy::DynamicObjectType *dyn
1066 : = static_cast<const TyTy::DynamicObjectType *> (tail_field);
1067 9 : tree dyn_record = create_dyn_obj_record (*dyn);
1068 9 : tree vtable_field = DECL_CHAIN (TYPE_FIELDS (dyn_record));
1069 9 : meta_field_ty = TREE_TYPE (vtable_field);
1070 9 : meta = "vtable";
1071 : }
1072 6 : else if (tail_field->get_kind () == TyTy::TypeKind::ADT)
1073 : {
1074 6 : const TyTy::ADTType *inner_adt
1075 : = static_cast<const TyTy::ADTType *> (tail_field);
1076 6 : tree inner_fat_ptr = create_dyn_adt_record (*inner_adt);
1077 6 : tree inner_meta_field = DECL_CHAIN (TYPE_FIELDS (inner_fat_ptr));
1078 6 : meta_field_ty = TREE_TYPE (inner_meta_field);
1079 6 : tree name_ident = DECL_NAME (inner_meta_field);
1080 6 : if (name_ident != NULL_TREE)
1081 6 : meta = IDENTIFIER_POINTER (name_ident);
1082 : }
1083 : else
1084 0 : rust_unreachable ();
1085 :
1086 103 : Backend::typed_identifier meta_field (meta, meta_field_ty, locus);
1087 103 : tree record = Backend::struct_type ({data_field, meta_field});
1088 103 : RS_DST_FLAG (record) = 1;
1089 103 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
1090 :
1091 103 : return record;
1092 103 : }
1093 :
1094 : } // namespace Compile
1095 : } // namespace Rust
|