LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-type.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 91.2 % 464 423
Test Date: 2026-08-22 16:33:35 Functions: 77.8 % 36 28
Legend: Lines:     hit not hit

            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 &param_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 &params = 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
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.