]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/typecheck/rust-casts.cc
90bdef1fd3c14b9c606ecc7f8b4ee2c4b762858b
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
19 #include "rust-casts.h"
24 TypeCastRules::TypeCastRules (location_t locus
, TyTy::TyWithLocation from
,
25 TyTy::TyWithLocation to
)
26 : locus (locus
), from (from
), to (to
)
29 TypeCoercionRules::CoercionResult
30 TypeCastRules::resolve (location_t locus
, TyTy::TyWithLocation from
,
31 TyTy::TyWithLocation to
)
33 TypeCastRules
cast_rules (locus
, from
, to
);
34 return cast_rules
.check ();
37 TypeCoercionRules::CoercionResult
38 TypeCastRules::check ()
40 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
41 auto possible_coercion
42 = TypeCoercionRules::TryCoerce (from
.get_ty (), to
.get_ty (), locus
,
43 true /*allow-autoderef*/,
44 true /*is_cast_site*/);
45 if (!possible_coercion
.is_error ())
47 // given the attempt was ok we need to ensure we perform it so that any
48 // inference variables are unified correctly
49 return TypeCoercionRules::Coerce (from
.get_ty (), to
.get_ty (), locus
,
50 true /*allow-autoderef*/,
51 true /*is_cast_site*/);
54 // try the simple cast rules
55 auto simple_cast
= cast_rules ();
56 if (!simple_cast
.is_error ())
61 return TypeCoercionRules::CoercionResult::get_error ();
64 TypeCoercionRules::CoercionResult
65 TypeCastRules::cast_rules ()
67 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L596
68 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L654
70 TyTy::BaseType
*from_type
= from
.get_ty ()->destructure ();
72 rust_debug ("cast_rules from={%s} to={%s}", from_type
->debug_str ().c_str (),
73 to
.get_ty ()->debug_str ().c_str ());
74 switch (from_type
->get_kind ())
76 case TyTy::TypeKind::INFER
: {
77 TyTy::InferType
*from_infer
78 = static_cast<TyTy::InferType
*> (from_type
);
79 switch (from_infer
->get_infer_kind ())
81 case TyTy::InferType::InferTypeKind::GENERAL
:
82 return TypeCoercionRules::CoercionResult
{{},
83 to
.get_ty ()->clone ()};
85 case TyTy::InferType::InferTypeKind::INTEGRAL
:
86 switch (to
.get_ty ()->get_kind ())
88 case TyTy::TypeKind::CHAR
: {
91 = from
.get_ty ()->get_kind () == TyTy::TypeKind::UINT
;
94 && (static_cast<TyTy::UintType
*> (from
.get_ty ())
96 == TyTy::UintType::UintKind::U8
);
98 return TypeCoercionRules::CoercionResult
{
99 {}, to
.get_ty ()->clone ()};
103 case TyTy::TypeKind::USIZE
:
104 case TyTy::TypeKind::ISIZE
:
105 case TyTy::TypeKind::UINT
:
106 case TyTy::TypeKind::INT
:
107 case TyTy::TypeKind::POINTER
:
108 return TypeCoercionRules::CoercionResult
{
109 {}, to
.get_ty ()->clone ()};
111 case TyTy::TypeKind::INFER
: {
112 TyTy::InferType
*to_infer
113 = static_cast<TyTy::InferType
*> (to
.get_ty ());
115 switch (to_infer
->get_infer_kind ())
117 case TyTy::InferType::InferTypeKind::GENERAL
:
118 case TyTy::InferType::InferTypeKind::INTEGRAL
:
119 return TypeCoercionRules::CoercionResult
{
120 {}, to
.get_ty ()->clone ()};
123 return TypeCoercionRules::CoercionResult::get_error ();
129 return TypeCoercionRules::CoercionResult::get_error ();
133 case TyTy::InferType::InferTypeKind::FLOAT
:
134 switch (to
.get_ty ()->get_kind ())
136 case TyTy::TypeKind::USIZE
:
137 case TyTy::TypeKind::ISIZE
:
138 case TyTy::TypeKind::UINT
:
139 case TyTy::TypeKind::INT
:
140 return TypeCoercionRules::CoercionResult
{
141 {}, to
.get_ty ()->clone ()};
143 case TyTy::TypeKind::INFER
: {
144 TyTy::InferType
*to_infer
145 = static_cast<TyTy::InferType
*> (to
.get_ty ());
147 switch (to_infer
->get_infer_kind ())
149 case TyTy::InferType::InferTypeKind::GENERAL
:
150 case TyTy::InferType::InferTypeKind::FLOAT
:
151 return TypeCoercionRules::CoercionResult
{
152 {}, to
.get_ty ()->clone ()};
155 return TypeCoercionRules::CoercionResult::get_error ();
161 return TypeCoercionRules::CoercionResult::get_error ();
168 case TyTy::TypeKind::BOOL
:
169 switch (to
.get_ty ()->get_kind ())
171 case TyTy::TypeKind::INFER
:
172 case TyTy::TypeKind::USIZE
:
173 case TyTy::TypeKind::ISIZE
:
174 case TyTy::TypeKind::UINT
:
175 case TyTy::TypeKind::INT
:
176 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
179 return TypeCoercionRules::CoercionResult::get_error ();
183 case TyTy::TypeKind::CHAR
:
184 case TyTy::TypeKind::USIZE
:
185 case TyTy::TypeKind::ISIZE
:
186 case TyTy::TypeKind::UINT
:
187 case TyTy::TypeKind::INT
:
188 switch (to
.get_ty ()->get_kind ())
190 case TyTy::TypeKind::CHAR
: {
192 bool was_uint
= from
.get_ty ()->get_kind () == TyTy::TypeKind::UINT
;
193 bool was_u8
= was_uint
194 && (static_cast<TyTy::UintType
*> (from
.get_ty ())
196 == TyTy::UintType::UintKind::U8
);
198 return TypeCoercionRules::CoercionResult
{{},
199 to
.get_ty ()->clone ()};
203 case TyTy::TypeKind::FLOAT
: {
204 // can only do this for number types not char
206 = from
.get_ty ()->get_kind () == TyTy::TypeKind::CHAR
;
208 return TypeCoercionRules::CoercionResult
{{},
209 to
.get_ty ()->clone ()};
213 case TyTy::TypeKind::POINTER
: {
214 // char can't be casted as a ptr
216 = from
.get_ty ()->get_kind () == TyTy::TypeKind::CHAR
;
218 return TypeCoercionRules::CoercionResult
{{},
219 to
.get_ty ()->clone ()};
223 case TyTy::TypeKind::INFER
:
224 case TyTy::TypeKind::USIZE
:
225 case TyTy::TypeKind::ISIZE
:
226 case TyTy::TypeKind::UINT
:
227 case TyTy::TypeKind::INT
:
228 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
231 return TypeCoercionRules::CoercionResult::get_error ();
235 case TyTy::TypeKind::FLOAT
:
236 switch (to
.get_ty ()->get_kind ())
238 case TyTy::TypeKind::USIZE
:
239 case TyTy::TypeKind::ISIZE
:
240 case TyTy::TypeKind::UINT
:
241 case TyTy::TypeKind::INT
:
242 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
244 case TyTy::TypeKind::FLOAT
:
245 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
247 case TyTy::TypeKind::INFER
: {
248 TyTy::InferType
*to_infer
249 = static_cast<TyTy::InferType
*> (to
.get_ty ());
251 switch (to_infer
->get_infer_kind ())
253 case TyTy::InferType::InferTypeKind::GENERAL
:
254 case TyTy::InferType::InferTypeKind::FLOAT
:
255 return TypeCoercionRules::CoercionResult
{
256 {}, to
.get_ty ()->clone ()};
259 return TypeCoercionRules::CoercionResult::get_error ();
265 return TypeCoercionRules::CoercionResult::get_error ();
269 case TyTy::TypeKind::REF
:
270 case TyTy::TypeKind::POINTER
:
271 switch (to
.get_ty ()->get_kind ())
273 case TyTy::TypeKind::USIZE
:
274 case TyTy::TypeKind::ISIZE
:
275 case TyTy::TypeKind::UINT
:
276 case TyTy::TypeKind::INT
: {
277 // refs should not cast to numeric type
279 = from
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
282 return TypeCoercionRules::CoercionResult
{
283 {}, to
.get_ty ()->clone ()};
288 case TyTy::TypeKind::REF
:
289 case TyTy::TypeKind::POINTER
:
290 return check_ptr_ptr_cast ();
293 return TypeCoercionRules::CoercionResult::get_error ();
298 return TypeCoercionRules::CoercionResult::get_error ();
301 return TypeCoercionRules::CoercionResult::get_error ();
304 TypeCoercionRules::CoercionResult
305 TypeCastRules::check_ptr_ptr_cast ()
307 rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
308 from
.get_ty ()->debug_str ().c_str (),
309 to
.get_ty ()->debug_str ().c_str ());
311 bool from_is_ref
= from
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
312 bool to_is_ref
= to
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
313 bool from_is_ptr
= from
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
314 bool to_is_ptr
= to
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
316 if (from_is_ptr
&& to_is_ptr
)
318 // mutability is ignored here as all pointer usage requires unsafe
319 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
321 else if (from_is_ref
&& to_is_ref
)
323 // mutability must be coercedable
324 TyTy::ReferenceType
&f
325 = static_cast<TyTy::ReferenceType
&> (*from
.get_ty ());
326 TyTy::ReferenceType
&t
327 = static_cast<TyTy::ReferenceType
&> (*to
.get_ty ());
329 if (TypeCoercionRules::coerceable_mutability (f
.mutability (),
332 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
336 return TypeCoercionRules::CoercionResult::get_error ();
340 TypeCastRules::emit_cast_error () const
342 rich_location
r (line_table
, locus
);
343 r
.add_range (from
.get_locus ());
344 r
.add_range (to
.get_locus ());
345 ErrorCode error_code
;
346 std::string error_msg
;
347 switch (to
.get_ty ()->get_kind ())
349 case TyTy::TypeKind::BOOL
:
350 error_msg
= "cannot cast %qs as %qs";
351 error_code
= ErrorCode::E0054
;
353 case TyTy::TypeKind::CHAR
:
355 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
356 error_code
= ErrorCode::E0604
;
358 case TyTy::TypeKind::SLICE
:
359 error_msg
= "cast to unsized type: %qs as %qs";
360 error_code
= ErrorCode::E0620
;
364 error_msg
= "casting %qs as %qs is invalid";
365 error_code
= ErrorCode::E0606
;
368 rust_error_at (r
, error_code
, error_msg
.c_str (),
369 from
.get_ty ()->get_name ().c_str (),
370 to
.get_ty ()->get_name ().c_str ());
373 } // namespace Resolver