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 319879 : TyTyResolveCompile::TyTyResolveCompile (Context *ctx, bool trait_object_mode)
35 319879 : : ctx (ctx), trait_object_mode (trait_object_mode),
36 319879 : translated (error_mark_node)
37 319879 : {}
38 :
39 : tree
40 319879 : TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty,
41 : bool trait_object_mode)
42 : {
43 319879 : TyTyResolveCompile compiler (ctx, trait_object_mode);
44 319879 : const TyTy::BaseType *destructured = ty->destructure ();
45 319879 : destructured->accept_vis (compiler);
46 :
47 319879 : if (compiler.translated != error_mark_node
48 319879 : && TYPE_NAME (compiler.translated) != NULL)
49 : {
50 : // canonicalize the type
51 277625 : compiler.translated = ctx->insert_compiled_type (compiler.translated);
52 : }
53 :
54 319879 : 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 6408 : 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 6408 : return compile (ctx, repr);
83 : }
84 :
85 : tree
86 32289 : TyTyResolveCompile::get_unit_type (Context *ctx)
87 : {
88 32289 : static tree unit_type;
89 32289 : if (unit_type == nullptr)
90 : {
91 4606 : auto cn = ctx->get_mappings ().get_current_crate ();
92 4606 : auto &c = ctx->get_mappings ().get_ast_crate (cn);
93 4606 : location_t locus = BUILTINS_LOCATION;
94 4606 : if (c.items.size () > 0)
95 : {
96 4603 : auto &item = c.items[0];
97 4603 : locus = item->get_locus ();
98 : }
99 :
100 4606 : auto unit_type_node = Backend::struct_type ({});
101 4606 : unit_type = Backend::named_type ("()", unit_type_node, locus);
102 : }
103 32289 : 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 571 : TyTyResolveCompile::visit (const TyTy::InferType &type)
114 : {
115 571 : const TyTy::BaseType *orig = &type;
116 571 : TyTy::BaseType *lookup = nullptr;
117 571 : bool ok = ctx->get_tyctx ()->lookup_type (type.get_ref (), &lookup);
118 571 : if (!ok)
119 : {
120 0 : translated = error_mark_node;
121 7 : return;
122 : }
123 :
124 571 : 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 564 : translated = TyTyResolveCompile::compile (ctx, lookup);
138 : }
139 :
140 : void
141 0 : TyTyResolveCompile::visit (const TyTy::ParamType &type)
142 : {
143 0 : translated = error_mark_node;
144 0 : }
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 327 : TyTyResolveCompile::visit (const TyTy::ProjectionType &type)
172 : {
173 : // workaround to get around const here
174 327 : TyTy::ProjectionType *projection
175 327 : = static_cast<TyTy::ProjectionType *> (type.clone ());
176 327 : auto normalized
177 327 : = Resolver::normalize_projection (projection, BUILTINS_LOCATION, false,
178 : false);
179 327 : if (normalized == projection)
180 : {
181 0 : translated = error_mark_node;
182 0 : return;
183 : }
184 :
185 327 : 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 17522 : TyTyResolveCompile::visit (const TyTy::FnType &type)
236 : {
237 17522 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
238 17522 : std::vector<Backend::typed_identifier> parameters;
239 17522 : 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 17522 : auto hir_type = type.get_return_type ()->destructure ();
244 17522 : bool return_is_unit = hir_type->is_unit ();
245 17522 : bool is_c_abi = type.get_abi () == ABI::C;
246 17522 : bool should_be_void = is_c_abi && return_is_unit;
247 17522 : if (!should_be_void)
248 : {
249 16441 : auto ret = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode);
250 16441 : location_t return_type_locus
251 16441 : = ctx->get_mappings ().lookup_location (hir_type->get_ref ());
252 16441 : results.emplace_back ("_", ret, return_type_locus);
253 : }
254 :
255 34737 : for (auto ¶m_pair : type.get_params ())
256 : {
257 17215 : auto param_tyty = param_pair.get_type ();
258 17215 : auto compiled_param_type
259 17215 : = TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode);
260 :
261 17215 : parameters.emplace_back (param_pair.get_pattern ().to_string (),
262 : compiled_param_type,
263 34430 : ctx->get_mappings ().lookup_location (
264 : param_tyty->get_ref ()));
265 : }
266 :
267 17522 : if (!type.is_variadic ())
268 33302 : translated = Backend::function_type (receiver, parameters, results, NULL,
269 16651 : type.get_ident ().locus);
270 : else
271 871 : translated
272 871 : = Backend::function_type_variadic (receiver, parameters, results, NULL,
273 871 : type.get_ident ().locus);
274 17522 : }
275 :
276 : void
277 94 : TyTyResolveCompile::visit (const TyTy::FnPtr &type)
278 : {
279 94 : tree result_type = TyTyResolveCompile::compile (ctx, type.get_return_type ());
280 :
281 94 : std::vector<tree> parameters;
282 :
283 94 : auto ¶ms = type.get_params ();
284 168 : for (auto &p : params)
285 : {
286 74 : tree pty = TyTyResolveCompile::compile (ctx, p.get_tyty ());
287 74 : parameters.push_back (pty);
288 : }
289 :
290 94 : translated = Backend::function_ptr_type (result_type, parameters,
291 94 : type.get_ident ().locus);
292 94 : }
293 :
294 : void
295 21112 : TyTyResolveCompile::visit (const TyTy::ADTType &type)
296 : {
297 21112 : tree type_record = error_mark_node;
298 :
299 21112 : TyTy::ADTType::ReprOptions repr = type.get_repr_options ();
300 21112 : if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
301 : {
302 34 : rust_assert (type.number_of_variants () == 1);
303 34 : TyTy::VariantDef &variant = *type.get_variants ().at (0);
304 :
305 34 : 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 34 : else if (variant.num_fields () == 1)
316 : {
317 : // single field transparent repr
318 34 : const TyTy::StructFieldType *field = variant.get_field_at_index (0);
319 34 : type_record
320 34 : = 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 :
338 : // compilation of non-transparent ADTs below
339 21078 : else if (!type.is_enum ())
340 : {
341 14670 : rust_assert (type.number_of_variants () == 1);
342 :
343 14670 : TyTy::VariantDef &variant = *type.get_variants ().at (0);
344 14670 : std::vector<Backend::typed_identifier> fields;
345 41051 : for (size_t i = 0; i < variant.num_fields (); i++)
346 : {
347 26381 : const TyTy::StructFieldType *field = variant.get_field_at_index (i);
348 26381 : tree compiled_field_ty
349 26381 : = TyTyResolveCompile::compile (ctx, field->get_field_type ());
350 :
351 26381 : fields.emplace_back (field->get_name (), compiled_field_ty,
352 52762 : ctx->get_mappings ().lookup_location (
353 : type.get_ty_ref ()));
354 : }
355 :
356 14670 : type_record = type.is_union () ? Backend::union_type (fields, false)
357 14450 : : Backend::struct_type (fields, false);
358 14670 : }
359 : else
360 : {
361 : // see:
362 : // https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241
363 : //
364 : // enums are actually a big union so for example the rust enum:
365 : //
366 : // enum AnEnum {
367 : // A,
368 : // B,
369 : // C (char),
370 : // D { x: i64, y: i64 },
371 : // }
372 : //
373 : // we actually turn this into
374 : //
375 : // union {
376 : // struct A { int RUST$ENUM$DISR; }; <- this is a data-less variant
377 : // struct B { int RUST$ENUM$DISR; }; <- this is a data-less variant
378 : // struct C { int RUST$ENUM$DISR; char __0; };
379 : // struct D { int RUST$ENUM$DISR; i64 x; i64 y; };
380 : // }
381 : //
382 : // Ada, qual_union_types might still work for this but I am not 100% sure.
383 : // I ran into some issues lets reuse our normal union and ask Ada people
384 : // about it.
385 : //
386 : // I think the above is actually wrong and it should actually be this
387 : //
388 : // struct {
389 : // int RUST$ENUM$DISR; // take into account the repr for this TODO
390 : // union {
391 : // // Variant A
392 : // struct {
393 : // // No additional fields
394 : // } A;
395 :
396 : // // Variant B
397 : // struct {
398 : // // No additional fields
399 : // } B;
400 :
401 : // // Variant C
402 : // struct {
403 : // char c;
404 : // } C;
405 :
406 : // // Variant D
407 : // struct {
408 : // int64_t x;
409 : // int64_t y;
410 : // } D;
411 : // } payload; // The union of all variant data
412 : // };
413 :
414 6408 : std::vector<tree> variant_records;
415 22573 : for (auto &variant : type.get_variants ())
416 : {
417 16165 : std::vector<Backend::typed_identifier> fields;
418 22197 : for (size_t i = 0; i < variant->num_fields (); i++)
419 : {
420 6032 : const TyTy::StructFieldType *field
421 6032 : = variant->get_field_at_index (i);
422 6032 : tree compiled_field_ty
423 6032 : = TyTyResolveCompile::compile (ctx, field->get_field_type ());
424 :
425 6032 : std::string field_name = field->get_name ();
426 6032 : if (variant->get_variant_type ()
427 : == TyTy::VariantDef::VariantType::TUPLE)
428 4527 : field_name = "__" + field->get_name ();
429 :
430 12064 : fields.emplace_back (field_name, compiled_field_ty,
431 6032 : ctx->get_mappings ().lookup_location (
432 : type.get_ty_ref ()));
433 6032 : }
434 :
435 16165 : tree variant_record = Backend::struct_type (fields);
436 16165 : tree named_variant_record
437 16165 : = Backend::named_type (variant->get_ident ().path.get (),
438 32330 : variant_record, variant->get_ident ().locus);
439 :
440 : // add them to the list
441 16165 : variant_records.push_back (named_variant_record);
442 16165 : }
443 :
444 : // now we need to make the actual union, but first we need to make
445 : // named_type TYPE_DECL's out of the variants
446 :
447 6408 : size_t i = 0;
448 6408 : std::vector<Backend::typed_identifier> enum_fields;
449 22573 : for (auto &variant_record : variant_records)
450 : {
451 16165 : TyTy::VariantDef *variant = type.get_variants ().at (i++);
452 16165 : std::string implicit_variant_name = variant->get_identifier ();
453 :
454 32330 : enum_fields.emplace_back (implicit_variant_name, variant_record,
455 16165 : ctx->get_mappings ().lookup_location (
456 : type.get_ty_ref ()));
457 16165 : }
458 :
459 : //
460 6408 : location_t locus = ctx->get_mappings ().lookup_location (type.get_ref ());
461 :
462 : // finally make the union or the enum
463 6408 : tree variants_union = Backend::union_type (enum_fields, false);
464 6408 : layout_type (variants_union);
465 6408 : tree named_union_record
466 6408 : = Backend::named_type ("payload", variants_union, locus);
467 :
468 : // create the overall struct
469 6408 : tree enumeral_type = TyTyResolveCompile::get_implicit_enumeral_node_type (
470 6408 : type.get_repr_options ().repr);
471 6408 : Backend::typed_identifier discrim (RUST_ENUM_DISR_FIELD_NAME,
472 6408 : enumeral_type, locus);
473 6408 : Backend::typed_identifier variants_union_field ("payload",
474 : named_union_record,
475 6408 : locus);
476 :
477 6408 : std::vector<Backend::typed_identifier> fields
478 6408 : = {discrim, variants_union_field};
479 6408 : type_record = Backend::struct_type (fields, false);
480 6408 : }
481 :
482 : // Handle repr options
483 : // TODO: "packed" should only narrow type alignment and "align" should only
484 : // widen it. Do we need to check and enforce this here, or is it taken care of
485 : // later on in the gcc middle-end?
486 21112 : if (repr.repr_kind != TyTy::ADTType::ReprKind::TRANSPARENT)
487 : {
488 21078 : if (repr.pack)
489 : {
490 10 : TYPE_PACKED (type_record) = 1;
491 10 : if (repr.pack > 1)
492 : {
493 5 : SET_TYPE_ALIGN (type_record, repr.pack * 8);
494 5 : TYPE_USER_ALIGN (type_record) = 1;
495 : }
496 : }
497 21068 : else if (repr.align)
498 : {
499 10 : SET_TYPE_ALIGN (type_record, repr.align * 8);
500 10 : TYPE_USER_ALIGN (type_record) = 1;
501 : }
502 21078 : layout_type (type_record);
503 : }
504 :
505 21112 : std::string named_struct_str
506 21112 : = type.get_ident ().path.get () + type.subst_as_string ();
507 21112 : translated = Backend::named_type (named_struct_str, type_record,
508 21112 : type.get_ident ().locus);
509 21112 : }
510 :
511 : void
512 17838 : TyTyResolveCompile::visit (const TyTy::TupleType &type)
513 : {
514 17838 : if (type.num_fields () == 0)
515 : {
516 15955 : translated = get_unit_type (ctx);
517 15955 : return;
518 : }
519 :
520 : // create implicit struct
521 1883 : std::vector<Backend::typed_identifier> fields;
522 5834 : for (size_t i = 0; i < type.num_fields (); i++)
523 : {
524 3951 : TyTy::BaseType *field = type.get_field (i);
525 3951 : tree compiled_field_ty = TyTyResolveCompile::compile (ctx, field);
526 :
527 : // rustc uses the convention __N, where N is an integer, to
528 : // name the fields of a tuple. We follow this as well,
529 : // because this is used by GDB. One further reason to prefer
530 : // this, rather than simply emitting the integer, is that this
531 : // approach makes it simpler to use a C-only debugger, or
532 : // GDB's C mode, when debugging Rust.
533 3951 : fields.emplace_back ("__" + std::to_string (i), compiled_field_ty,
534 7902 : ctx->get_mappings ().lookup_location (
535 : type.get_ty_ref ()));
536 : }
537 :
538 1883 : tree struct_type_record = Backend::struct_type (fields);
539 1883 : translated = Backend::named_type (type.get_name (), struct_type_record,
540 1883 : type.get_ident ().locus);
541 1883 : }
542 :
543 : void
544 4138 : TyTyResolveCompile::visit (const TyTy::ArrayType &type)
545 : {
546 4138 : tree element_type
547 4138 : = TyTyResolveCompile::compile (ctx, type.get_element_type ());
548 4138 : auto const_capacity = type.get_capacity ();
549 :
550 : // Check if capacity is a const type
551 4138 : if (const_capacity->get_kind () != TyTy::TypeKind::CONST)
552 : {
553 0 : rust_error_at (type.get_locus (), "array capacity is not a const type");
554 0 : translated = error_mark_node;
555 0 : return;
556 : }
557 :
558 4138 : auto *capacity_const = const_capacity->as_const_type ();
559 :
560 4138 : rust_assert (capacity_const->const_kind ()
561 : == TyTy::BaseConstType::ConstKind::Value);
562 4138 : auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
563 4138 : auto folded_capacity_expr = capacity_value.get_value ();
564 :
565 : // build_index_type takes the maximum index, which is one less than
566 : // the length.
567 4138 : tree index_type_tree = build_index_type (
568 : fold_build2 (MINUS_EXPR, sizetype, folded_capacity_expr, size_one_node));
569 :
570 4138 : translated = build_array_type (element_type, index_type_tree, false);
571 : }
572 :
573 : void
574 135 : TyTyResolveCompile::visit (const TyTy::SliceType &type)
575 : {
576 135 : tree type_record = create_slice_type_record (type);
577 :
578 135 : std::string named_struct_str
579 270 : = std::string ("[") + type.get_element_type ()->get_name () + "]";
580 135 : translated = Backend::named_type (named_struct_str, type_record,
581 135 : type.get_ident ().locus);
582 135 : }
583 :
584 : void
585 10434 : TyTyResolveCompile::visit (const TyTy::BoolType &)
586 : {
587 10434 : translated
588 10434 : = Backend::named_type ("bool", boolean_type_node, BUILTINS_LOCATION);
589 10434 : }
590 :
591 : void
592 77814 : TyTyResolveCompile::visit (const TyTy::IntType &type)
593 : {
594 77814 : switch (type.get_int_kind ())
595 : {
596 9955 : case TyTy::IntType::I8:
597 9955 : translated = Backend::named_type ("i8", Backend::integer_type (false, 8),
598 : BUILTINS_LOCATION);
599 9955 : return;
600 :
601 5663 : case TyTy::IntType::I16:
602 5663 : translated
603 5663 : = Backend::named_type ("i16", Backend::integer_type (false, 16),
604 : BUILTINS_LOCATION);
605 5663 : return;
606 :
607 51024 : case TyTy::IntType::I32:
608 51024 : translated
609 51024 : = Backend::named_type ("i32", Backend::integer_type (false, 32),
610 : BUILTINS_LOCATION);
611 51024 : return;
612 :
613 5837 : case TyTy::IntType::I64:
614 5837 : translated
615 5837 : = Backend::named_type ("i64", Backend::integer_type (false, 64),
616 : BUILTINS_LOCATION);
617 5837 : return;
618 :
619 5335 : case TyTy::IntType::I128:
620 5335 : translated
621 5335 : = Backend::named_type ("i128", Backend::integer_type (false, 128),
622 : BUILTINS_LOCATION);
623 5335 : return;
624 : }
625 : }
626 :
627 : void
628 56367 : TyTyResolveCompile::visit (const TyTy::UintType &type)
629 : {
630 56367 : switch (type.get_uint_kind ())
631 : {
632 14820 : case TyTy::UintType::U8:
633 14820 : translated = Backend::named_type ("u8", Backend::integer_type (true, 8),
634 : BUILTINS_LOCATION);
635 14820 : return;
636 :
637 8983 : case TyTy::UintType::U16:
638 8983 : translated = Backend::named_type ("u16", Backend::integer_type (true, 16),
639 : BUILTINS_LOCATION);
640 8983 : return;
641 :
642 13706 : case TyTy::UintType::U32:
643 13706 : translated = Backend::named_type ("u32", Backend::integer_type (true, 32),
644 : BUILTINS_LOCATION);
645 13706 : return;
646 :
647 13781 : case TyTy::UintType::U64:
648 13781 : translated = Backend::named_type ("u64", Backend::integer_type (true, 64),
649 : BUILTINS_LOCATION);
650 13781 : return;
651 :
652 5077 : case TyTy::UintType::U128:
653 5077 : translated
654 5077 : = Backend::named_type ("u128", Backend::integer_type (true, 128),
655 : BUILTINS_LOCATION);
656 5077 : return;
657 : }
658 : }
659 :
660 : void
661 15127 : TyTyResolveCompile::visit (const TyTy::FloatType &type)
662 : {
663 15127 : switch (type.get_float_kind ())
664 : {
665 7351 : case TyTy::FloatType::F32:
666 7351 : translated = Backend::named_type ("f32", Backend::float_type (32),
667 : BUILTINS_LOCATION);
668 7351 : return;
669 :
670 7776 : case TyTy::FloatType::F64:
671 7776 : translated = Backend::named_type ("f64", Backend::float_type (64),
672 : BUILTINS_LOCATION);
673 7776 : return;
674 : }
675 : }
676 :
677 : void
678 35155 : TyTyResolveCompile::visit (const TyTy::USizeType &)
679 : {
680 35155 : translated
681 35155 : = Backend::named_type ("usize",
682 : Backend::integer_type (true,
683 : Backend::get_pointer_size ()),
684 : BUILTINS_LOCATION);
685 35155 : }
686 :
687 : void
688 18724 : TyTyResolveCompile::visit (const TyTy::ISizeType &)
689 : {
690 18724 : translated
691 18724 : = Backend::named_type ("isize",
692 : Backend::integer_type (false,
693 : Backend::get_pointer_size ()),
694 : BUILTINS_LOCATION);
695 18724 : }
696 :
697 : void
698 5557 : TyTyResolveCompile::visit (const TyTy::CharType &)
699 : {
700 5557 : translated
701 5557 : = Backend::named_type ("char", Backend::wchar_type (), BUILTINS_LOCATION);
702 5557 : }
703 :
704 : void
705 18588 : TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
706 : {
707 18588 : const TyTy::SliceType *slice = nullptr;
708 18588 : const TyTy::StrType *str = nullptr;
709 18588 : const TyTy::DynamicObjectType *dyn = nullptr;
710 18588 : const TyTy::ADTType *adt = nullptr;
711 18588 : if (type.is_dyn_slice_type (&slice))
712 : {
713 612 : tree type_record = create_slice_type_record (*slice);
714 612 : std::string dyn_slice_type_str
715 1836 : = std::string (type.is_mutable () ? "&mut " : "&") + "["
716 1836 : + slice->get_element_type ()->get_name () + "]";
717 :
718 612 : translated = Backend::named_type (dyn_slice_type_str, type_record,
719 : slice->get_locus ());
720 :
721 612 : return;
722 612 : }
723 17976 : else if (type.is_dyn_str_type (&str))
724 : {
725 4128 : tree type_record = create_str_type_record (*str);
726 4128 : std::string dyn_str_type_str
727 12384 : = std::string (type.is_mutable () ? "&mut " : "&") + "str";
728 :
729 4128 : translated = Backend::named_type (dyn_str_type_str, type_record,
730 : str->get_locus ());
731 :
732 4128 : return;
733 4128 : }
734 13848 : else if (type.is_dyn_obj_type (&dyn))
735 : {
736 685 : tree type_record = create_dyn_obj_record (*dyn);
737 685 : std::string dyn_str_type_str
738 1370 : = std::string (type.is_mutable () ? "&mut " : "& ") + dyn->get_name ();
739 :
740 685 : translated = Backend::named_type (dyn_str_type_str, type_record,
741 : dyn->get_locus ());
742 :
743 685 : return;
744 685 : }
745 : // Check for CStr, create a specific record for it
746 13163 : else if (type.is_dyn_cstr_type (&adt))
747 : {
748 : // CStr in core crate is defined as the following:
749 : //
750 : // #[repr(transparent)]
751 : // pub struct CStr {
752 : // inner: [u8]
753 : // }
754 : //
755 : // Reuse the c_char (u8) slice fat-pointer layout
756 56 : TyTy::BaseType *u8 = nullptr;
757 56 : ctx->get_tyctx ()->lookup_builtin ("u8", &u8);
758 : // Create a synthetic SliceType over u8 and use that record layout
759 56 : TyTy::SliceType synthetic_slice (adt->get_ref (), adt->get_ident ().locus,
760 112 : TyTy::TyVar (u8->get_ref ()));
761 56 : tree type_record = create_slice_type_record (synthetic_slice);
762 56 : translated
763 56 : = Backend::named_type ("&CStr", type_record, adt->get_ident ().locus);
764 :
765 56 : return;
766 56 : }
767 :
768 13107 : tree base_compiled_type
769 13107 : = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
770 13107 : if (type.is_mutable ())
771 : {
772 1151 : translated = Backend::reference_type (base_compiled_type);
773 : }
774 : else
775 : {
776 : // https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html
777 : // If you have a reference &T, then normally in Rust the compiler performs
778 : // optimizations based on the knowledge that &T points to immutable data.
779 : // Mutating that data, for example through an alias or by transmuting a &T
780 : // into a &mut T, is considered undefined behavior. UnsafeCell<T> opts-out
781 : // of the immutability guarantee for &T: a shared reference &UnsafeCell<T>
782 : // may point to data that is being mutated. This is called “interior
783 : // mutability”.
784 11956 : auto base = type.get_base ()->contains_unsafe_cell ()
785 11956 : ? base_compiled_type
786 11954 : : Backend::immutable_type (base_compiled_type);
787 11956 : translated = Backend::reference_type (base);
788 : }
789 : }
790 :
791 : void
792 10606 : TyTyResolveCompile::visit (const TyTy::PointerType &type)
793 : {
794 10606 : const TyTy::SliceType *slice = nullptr;
795 10606 : const TyTy::StrType *str = nullptr;
796 10606 : const TyTy::DynamicObjectType *dyn = nullptr;
797 10606 : if (type.is_dyn_slice_type (&slice))
798 : {
799 564 : tree type_record = create_slice_type_record (*slice);
800 564 : std::string dyn_slice_type_str
801 1636 : = std::string (type.is_mutable () ? "*mut " : "*const ") + "["
802 1692 : + slice->get_element_type ()->get_name () + "]";
803 :
804 564 : translated = Backend::named_type (dyn_slice_type_str, type_record,
805 : slice->get_locus ());
806 :
807 564 : return;
808 564 : }
809 10042 : else if (type.is_dyn_str_type (&str))
810 : {
811 2637 : tree type_record = create_str_type_record (*str);
812 2637 : std::string dyn_str_type_str
813 7911 : = std::string (type.is_mutable () ? "*mut " : "*const ") + "str";
814 :
815 2637 : translated = Backend::named_type (dyn_str_type_str, type_record,
816 : str->get_locus ());
817 :
818 2637 : return;
819 2637 : }
820 7405 : else if (type.is_dyn_obj_type (&dyn))
821 : {
822 12 : tree type_record = create_dyn_obj_record (*dyn);
823 12 : std::string dyn_str_type_str
824 36 : = std::string (type.is_mutable () ? "*mut " : "*const ")
825 24 : + dyn->get_name ();
826 :
827 12 : translated = Backend::named_type (dyn_str_type_str, type_record,
828 : dyn->get_locus ());
829 :
830 12 : return;
831 12 : }
832 :
833 7393 : tree base_compiled_type
834 7393 : = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
835 7393 : if (type.is_mutable ())
836 : {
837 1697 : translated = Backend::pointer_type (base_compiled_type);
838 : }
839 : else
840 : {
841 5696 : auto base = Backend::immutable_type (base_compiled_type);
842 5696 : translated = Backend::pointer_type (base);
843 : }
844 : }
845 :
846 : void
847 4632 : TyTyResolveCompile::visit (const TyTy::StrType &type)
848 : {
849 4632 : tree raw_str = create_str_type_record (type);
850 4632 : translated = Backend::named_type ("str", raw_str, BUILTINS_LOCATION);
851 4632 : }
852 :
853 : void
854 4891 : TyTyResolveCompile::visit (const TyTy::NeverType &)
855 : {
856 4891 : translated = get_unit_type (ctx);
857 4891 : }
858 :
859 : void
860 4 : TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type)
861 : {
862 4 : if (trait_object_mode)
863 : {
864 0 : translated = Backend::integer_type (true, Backend::get_pointer_size ());
865 0 : return;
866 : }
867 :
868 4 : tree type_record = create_dyn_obj_record (type);
869 4 : translated = Backend::named_type (type.get_name (), type_record,
870 4 : type.get_ident ().locus);
871 : }
872 :
873 : void
874 0 : TyTyResolveCompile::visit (const TyTy::OpaqueType &type)
875 : {
876 0 : rust_assert (type.can_resolve ());
877 0 : auto underlying = type.resolve ();
878 0 : translated = TyTyResolveCompile::compile (ctx, underlying, trait_object_mode);
879 0 : }
880 :
881 : tree
882 701 : TyTyResolveCompile::create_dyn_obj_record (const TyTy::DynamicObjectType &type)
883 : {
884 701 : location_t locus = ctx->get_mappings ().lookup_location (type.get_ty_ref ());
885 : // create implicit struct
886 701 : std::vector<Backend::typed_identifier> fields;
887 :
888 701 : tree voidptr_ty = build_pointer_type (void_type_node);
889 :
890 701 : fields.emplace_back ("data", voidptr_ty, locus);
891 :
892 701 : std::vector<Backend::typed_identifier> vtable_fields;
893 :
894 : // drop_in_place is not implemented yet!
895 701 : vtable_fields.emplace_back ("__drop_in_place", voidptr_ty, locus);
896 701 : vtable_fields.emplace_back ("__size", size_type_node, locus);
897 701 : vtable_fields.emplace_back ("__align", size_type_node, locus);
898 :
899 701 : size_t items_size = type.get_object_items ().size ();
900 1663 : for (size_t method_idx = 0; method_idx < items_size; method_idx++)
901 962 : vtable_fields.emplace_back ("__method_" + std::to_string (method_idx),
902 : voidptr_ty, locus);
903 :
904 701 : tree vtable_record = Backend::struct_type (vtable_fields);
905 701 : tree vtable_ptr_ty = build_pointer_type (vtable_record);
906 :
907 701 : fields.emplace_back ("vtable", vtable_ptr_ty, locus);
908 :
909 701 : tree record = Backend::struct_type (fields);
910 701 : RS_DST_FLAG (record) = 1;
911 701 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
912 :
913 701 : return record;
914 701 : }
915 :
916 : tree
917 1367 : TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type)
918 : {
919 : // lookup usize
920 1367 : TyTy::BaseType *usize = nullptr;
921 1367 : bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
922 1367 : rust_assert (ok);
923 :
924 1367 : tree element_type
925 1367 : = TyTyResolveCompile::compile (ctx, type.get_element_type ());
926 1367 : tree data_field_ty = build_pointer_type (element_type);
927 1367 : Backend::typed_identifier data_field ("data", data_field_ty,
928 1367 : type.get_locus ());
929 :
930 1367 : tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
931 1367 : Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
932 :
933 1367 : tree record = Backend::struct_type ({data_field, len_field});
934 1367 : RS_DST_FLAG (record) = 1;
935 1367 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
936 :
937 1367 : return record;
938 : }
939 :
940 : tree
941 11397 : TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type)
942 : {
943 : // lookup usize
944 11397 : TyTy::BaseType *usize = nullptr;
945 11397 : bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
946 11397 : rust_assert (ok);
947 :
948 11397 : tree char_ptr = build_pointer_type (char_type_node);
949 11397 : tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
950 :
951 11397 : tree element_type = const_char_type;
952 11397 : tree data_field_ty = build_pointer_type (element_type);
953 11397 : Backend::typed_identifier data_field ("data", data_field_ty,
954 11397 : type.get_locus ());
955 :
956 11397 : tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
957 11397 : Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ());
958 :
959 11397 : tree record = Backend::struct_type ({data_field, len_field});
960 11397 : RS_DST_FLAG (record) = 1;
961 11397 : TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record);
962 :
963 11397 : return record;
964 : }
965 :
966 : } // namespace Compile
967 : } // namespace Rust
|