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