LCOV - code coverage report
Current view: top level - gcc/rust/typecheck - rust-casts.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 77.4 % 239 185
Test Date: 2026-10-03 16:17:38 Functions: 100.0 % 6 6
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-casts.h"
      20              : #include "rust-tyty-util.h"
      21              : #include "rust-tyty.h"
      22              : 
      23              : namespace Rust {
      24              : namespace Resolver {
      25              : 
      26         5764 : TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
      27              :                               TyTy::TyWithLocation to)
      28         5764 :   : locus (locus), from (from), to (to)
      29         5764 : {}
      30              : 
      31              : TypeCoercionRules::CoercionResult
      32         5764 : TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
      33              :                         TyTy::TyWithLocation to, bool emit_error)
      34              : {
      35         5764 :   TypeCastRules cast_rules (locus, from, to);
      36         5764 :   return cast_rules.check (emit_error);
      37              : }
      38              : 
      39              : TypeCoercionRules::CoercionResult
      40         5764 : TypeCastRules::check (bool emit_error)
      41              : {
      42              :   // try the simple cast rules
      43         5764 :   auto simple_cast = cast_rules ();
      44         5764 :   if (!simple_cast.is_error ())
      45         3780 :     return simple_cast;
      46              : 
      47              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
      48         1984 :   auto possible_coercion
      49              :     = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
      50              :                                     true /*allow-autoderef*/,
      51         1984 :                                     true /*is_cast_site*/);
      52         1984 :   if (!possible_coercion.is_error ())
      53              :     {
      54              :       // given the attempt was ok we need to ensure we perform it so that any
      55              :       // inference variables are unified correctly
      56         1961 :       return TypeCoercionRules::Coerce (from.get_ty (), to.get_ty (), locus,
      57              :                                         true /*allow-autoderef*/,
      58         1961 :                                         true /*is_cast_site*/);
      59              :     }
      60              : 
      61           23 :   if (emit_error)
      62           16 :     TypeCastRules::emit_cast_error (locus, from, to);
      63              : 
      64           23 :   return TypeCoercionRules::CoercionResult::get_error ();
      65         1984 : }
      66              : 
      67              : TypeCoercionRules::CoercionResult
      68         5764 : TypeCastRules::cast_rules ()
      69              : {
      70              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L596
      71              :   // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L654
      72              : 
      73         5764 :   TyTy::BaseType *from_type = from.get_ty ()->destructure ();
      74         5764 :   if (auto c = from_type->try_as<TyTy::ConstParamType> ())
      75            0 :     from_type = c->get_specified_type ();
      76              : 
      77         5764 :   rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
      78              :               to.get_ty ()->debug_str ().c_str ());
      79         5764 :   switch (from_type->get_kind ())
      80              :     {
      81           79 :     case TyTy::TypeKind::INFER:
      82           79 :       {
      83           79 :         TyTy::InferType *from_infer
      84              :           = static_cast<TyTy::InferType *> (from_type);
      85           79 :         switch (from_infer->get_infer_kind ())
      86              :           {
      87            0 :           case TyTy::InferType::InferTypeKind::GENERAL:
      88            0 :             return TypeCoercionRules::CoercionResult{{},
      89            0 :                                                      to.get_ty ()->clone ()};
      90              : 
      91           79 :           case TyTy::InferType::InferTypeKind::INTEGRAL:
      92           79 :             switch (to.get_ty ()->get_kind ())
      93              :               {
      94            2 :               case TyTy::TypeKind::CHAR:
      95            2 :                 {
      96              :                   // only u8 and char
      97            2 :                   bool was_uint
      98            2 :                     = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
      99            2 :                   bool was_u8
     100              :                     = was_uint
     101            2 :                       && (static_cast<TyTy::UintType *> (from.get_ty ())
     102            0 :                             ->get_uint_kind ()
     103            8 :                           == TyTy::UintType::UintKind::U8);
     104            0 :                   if (was_u8)
     105            0 :                     return TypeCoercionRules::CoercionResult{
     106            0 :                       {}, to.get_ty ()->clone ()};
     107              :                 }
     108              :                 break;
     109              : 
     110           60 :               case TyTy::TypeKind::USIZE:
     111           60 :               case TyTy::TypeKind::ISIZE:
     112           60 :               case TyTy::TypeKind::UINT:
     113           60 :               case TyTy::TypeKind::INT:
     114           60 :               case TyTy::TypeKind::POINTER:
     115           60 :                 return TypeCoercionRules::CoercionResult{
     116           60 :                   {}, to.get_ty ()->clone ()};
     117              : 
     118           16 :               case TyTy::TypeKind::INFER:
     119           16 :                 {
     120           16 :                   TyTy::InferType *to_infer
     121           16 :                     = static_cast<TyTy::InferType *> (to.get_ty ());
     122              : 
     123           16 :                   switch (to_infer->get_infer_kind ())
     124              :                     {
     125           16 :                     case TyTy::InferType::InferTypeKind::GENERAL:
     126           16 :                     case TyTy::InferType::InferTypeKind::INTEGRAL:
     127           16 :                       return TypeCoercionRules::CoercionResult{
     128           16 :                         {}, to.get_ty ()->clone ()};
     129              : 
     130            0 :                     default:
     131            0 :                       return TypeCoercionRules::CoercionResult::get_error ();
     132              :                     }
     133              :                 }
     134            1 :                 break;
     135              : 
     136            1 :               default:
     137            1 :                 return TypeCoercionRules::CoercionResult::get_error ();
     138              :               }
     139              :             break;
     140              : 
     141            0 :           case TyTy::InferType::InferTypeKind::FLOAT:
     142            0 :             switch (to.get_ty ()->get_kind ())
     143              :               {
     144            0 :               case TyTy::TypeKind::USIZE:
     145            0 :               case TyTy::TypeKind::ISIZE:
     146            0 :               case TyTy::TypeKind::UINT:
     147            0 :               case TyTy::TypeKind::INT:
     148            0 :                 return TypeCoercionRules::CoercionResult{
     149            0 :                   {}, to.get_ty ()->clone ()};
     150              : 
     151            0 :               case TyTy::TypeKind::INFER:
     152            0 :                 {
     153            0 :                   TyTy::InferType *to_infer
     154            0 :                     = static_cast<TyTy::InferType *> (to.get_ty ());
     155              : 
     156            0 :                   switch (to_infer->get_infer_kind ())
     157              :                     {
     158            0 :                     case TyTy::InferType::InferTypeKind::GENERAL:
     159            0 :                     case TyTy::InferType::InferTypeKind::FLOAT:
     160            0 :                       return TypeCoercionRules::CoercionResult{
     161            0 :                         {}, to.get_ty ()->clone ()};
     162              : 
     163            0 :                     default:
     164            0 :                       return TypeCoercionRules::CoercionResult::get_error ();
     165              :                     }
     166              :                 }
     167            0 :                 break;
     168              : 
     169            0 :               default:
     170            0 :                 return TypeCoercionRules::CoercionResult::get_error ();
     171              :               }
     172              :             break;
     173              :           }
     174              :       }
     175              :       break;
     176              : 
     177           52 :     case TyTy::TypeKind::BOOL:
     178           52 :       switch (to.get_ty ()->get_kind ())
     179              :         {
     180           49 :         case TyTy::TypeKind::INFER:
     181           49 :         case TyTy::TypeKind::USIZE:
     182           49 :         case TyTy::TypeKind::ISIZE:
     183           49 :         case TyTy::TypeKind::UINT:
     184           49 :         case TyTy::TypeKind::INT:
     185           49 :           return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     186              : 
     187            3 :         default:
     188            3 :           return TypeCoercionRules::CoercionResult::get_error ();
     189              :         }
     190         1528 :       break;
     191              : 
     192         1528 :     case TyTy::TypeKind::CHAR:
     193         1528 :     case TyTy::TypeKind::USIZE:
     194         1528 :     case TyTy::TypeKind::ISIZE:
     195         1528 :     case TyTy::TypeKind::UINT:
     196         1528 :     case TyTy::TypeKind::INT:
     197         1528 :       switch (to.get_ty ()->get_kind ())
     198              :         {
     199           20 :         case TyTy::TypeKind::CHAR:
     200           20 :           {
     201              :             // only u8 and char
     202           20 :             bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
     203           20 :             bool was_u8 = was_uint
     204           20 :                           && (static_cast<TyTy::UintType *> (from.get_ty ())
     205           18 :                                 ->get_uint_kind ()
     206           24 :                               == TyTy::UintType::UintKind::U8);
     207           16 :             if (was_u8)
     208           16 :               return TypeCoercionRules::CoercionResult{{},
     209           16 :                                                        to.get_ty ()->clone ()};
     210              :           }
     211              :           break;
     212              : 
     213           10 :         case TyTy::TypeKind::FLOAT:
     214           10 :           {
     215              :             // can only do this for number types not char
     216           10 :             bool from_char
     217           10 :               = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
     218           10 :             if (!from_char)
     219            9 :               return TypeCoercionRules::CoercionResult{{},
     220            9 :                                                        to.get_ty ()->clone ()};
     221              :           }
     222              :           break;
     223              : 
     224            7 :         case TyTy::TypeKind::POINTER:
     225            7 :           {
     226              :             // char can't be casted as a ptr
     227            7 :             bool from_char
     228            7 :               = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
     229            7 :             if (!from_char)
     230            7 :               return TypeCoercionRules::CoercionResult{{},
     231            7 :                                                        to.get_ty ()->clone ()};
     232              :           }
     233              :           break;
     234              : 
     235         1488 :         case TyTy::TypeKind::INFER:
     236         1488 :         case TyTy::TypeKind::USIZE:
     237         1488 :         case TyTy::TypeKind::ISIZE:
     238         1488 :         case TyTy::TypeKind::UINT:
     239         1488 :         case TyTy::TypeKind::INT:
     240         1488 :           return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     241              : 
     242            3 :         default:
     243            3 :           return TypeCoercionRules::CoercionResult::get_error ();
     244              :         }
     245              :       break;
     246              : 
     247            6 :     case TyTy::TypeKind::FLOAT:
     248            6 :       switch (to.get_ty ()->get_kind ())
     249              :         {
     250            6 :         case TyTy::TypeKind::USIZE:
     251            6 :         case TyTy::TypeKind::ISIZE:
     252            6 :         case TyTy::TypeKind::UINT:
     253            6 :         case TyTy::TypeKind::INT:
     254            6 :           return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     255              : 
     256            0 :         case TyTy::TypeKind::FLOAT:
     257            0 :           return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     258              : 
     259            0 :         case TyTy::TypeKind::INFER:
     260            0 :           {
     261            0 :             TyTy::InferType *to_infer
     262            0 :               = static_cast<TyTy::InferType *> (to.get_ty ());
     263              : 
     264            0 :             switch (to_infer->get_infer_kind ())
     265              :               {
     266            0 :               case TyTy::InferType::InferTypeKind::GENERAL:
     267            0 :               case TyTy::InferType::InferTypeKind::FLOAT:
     268            0 :                 return TypeCoercionRules::CoercionResult{
     269            0 :                   {}, to.get_ty ()->clone ()};
     270              : 
     271            0 :               default:
     272            0 :                 return TypeCoercionRules::CoercionResult::get_error ();
     273              :               }
     274              :           }
     275            0 :           break;
     276              : 
     277            0 :         default:
     278            0 :           return TypeCoercionRules::CoercionResult::get_error ();
     279              :         }
     280         4092 :       break;
     281              : 
     282         4092 :     case TyTy::TypeKind::REF:
     283         4092 :     case TyTy::TypeKind::FNPTR:
     284         4092 :     case TyTy::TypeKind::POINTER:
     285         4092 :       switch (to.get_ty ()->get_kind ())
     286              :         {
     287           20 :         case TyTy::TypeKind::USIZE:
     288           20 :         case TyTy::TypeKind::ISIZE:
     289           20 :         case TyTy::TypeKind::UINT:
     290           20 :         case TyTy::TypeKind::INT:
     291           20 :           {
     292              :             // refs should not cast to numeric type
     293           20 :             auto kind = from.get_ty ()->get_kind ();
     294           20 :             bool from_ptr = kind == TyTy::TypeKind::POINTER
     295           20 :                             || kind == TyTy::TypeKind::FNPTR;
     296           20 :             if (from_ptr)
     297              :               {
     298           19 :                 return TypeCoercionRules::CoercionResult{
     299           19 :                   {}, to.get_ty ()->clone ()};
     300              :               }
     301              :           }
     302              :           break;
     303              : 
     304         4071 :         case TyTy::TypeKind::REF:
     305         4071 :         case TyTy::TypeKind::POINTER:
     306         4071 :           return check_ptr_ptr_cast ();
     307              : 
     308            1 :         default:
     309            1 :           return TypeCoercionRules::CoercionResult::get_error ();
     310              :         }
     311              :       break;
     312              : 
     313            7 :     default:
     314            7 :       return TypeCoercionRules::CoercionResult::get_error ();
     315              :     }
     316              : 
     317            8 :   return TypeCoercionRules::CoercionResult::get_error ();
     318              : }
     319              : 
     320              : TypeCoercionRules::CoercionResult
     321         4071 : TypeCastRules::check_ptr_ptr_cast ()
     322              : {
     323         4071 :   rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
     324              :               from.get_ty ()->debug_str ().c_str (),
     325              :               to.get_ty ()->debug_str ().c_str ());
     326              : 
     327         4071 :   bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
     328         4071 :   bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
     329         4071 :   bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
     330         4071 :   bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
     331              : 
     332         4071 :   if (from_is_ptr && to_is_ptr)
     333              :     {
     334              :       // mutability is ignored here as all pointer usage requires unsafe
     335         2110 :       return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     336              :     }
     337         1961 :   else if (from_is_ref && to_is_ref)
     338              :     {
     339           26 :       const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
     340           26 :       const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
     341              : 
     342           26 :       if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
     343              :         {
     344              :           // this needs to be handled by coercion logic
     345           26 :           return TypeCoercionRules::CoercionResult::get_error ();
     346              :         }
     347              : 
     348              :       // are the underlying types safely simple castable?
     349            7 :       const auto to_underly = to_ref.get_base ();
     350            7 :       const auto from_underly = from_ref.get_base ();
     351            7 :       auto res = resolve (locus, TyTy::TyWithLocation (from_underly),
     352           14 :                           TyTy::TyWithLocation (to_underly), false);
     353            7 :       if (res.is_error ())
     354              :         {
     355              :           // this needs to be handled by coercion logic
     356            7 :           return TypeCoercionRules::CoercionResult::get_error ();
     357              :         }
     358              : 
     359              :       // mutability must be coerceable
     360            0 :       TyTy::ReferenceType &f
     361            0 :         = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
     362            0 :       TyTy::ReferenceType &t
     363            0 :         = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
     364              : 
     365            0 :       if (TypeCoercionRules::coerceable_mutability (f.mutability (),
     366              :                                                     t.mutability ()))
     367              :         {
     368            0 :           return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
     369              :         }
     370            7 :     }
     371              : 
     372         1935 :   return TypeCoercionRules::CoercionResult::get_error ();
     373              : }
     374              : 
     375              : void
     376           16 : TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
     377              :                                 TyTy::TyWithLocation to)
     378              : {
     379           16 :   rich_location r (line_table, locus);
     380           16 :   r.add_range (from.get_locus ());
     381           16 :   r.add_range (to.get_locus ());
     382           16 :   ErrorCode error_code;
     383           16 :   std::string error_msg;
     384           16 :   switch (to.get_ty ()->get_kind ())
     385              :     {
     386            4 :     case TyTy::TypeKind::BOOL:
     387            4 :       error_msg = "cannot cast %qs as %qs";
     388            4 :       error_code = ErrorCode::E0054;
     389            4 :       break;
     390            7 :     case TyTy::TypeKind::CHAR:
     391            7 :       error_msg
     392            7 :         += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
     393            7 :       error_code = ErrorCode::E0604;
     394            7 :       break;
     395            1 :     case TyTy::TypeKind::SLICE:
     396            1 :       error_msg = "cast to unsized type: %qs as %qs";
     397            1 :       error_code = ErrorCode::E0620;
     398            1 :       break;
     399              : 
     400            4 :     default:
     401            4 :       error_msg = "casting %qs as %qs is invalid";
     402            4 :       error_code = ErrorCode::E0606;
     403            4 :       break;
     404              :     }
     405           16 :   rust_error_at (r, error_code, error_msg.c_str (),
     406           32 :                  from.get_ty ()->get_name ().c_str (),
     407           32 :                  to.get_ty ()->get_name ().c_str ());
     408           16 : }
     409              : 
     410              : } // namespace Resolver
     411              : } // 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.