]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/typecheck/rust-casts.cc
7d086013e9f6fa08d7ca96480708e22b03ef3449
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"
20 #include "rust-tyty-util.h"
25 TypeCastRules::TypeCastRules (location_t locus
, TyTy::TyWithLocation from
,
26 TyTy::TyWithLocation to
)
27 : locus (locus
), from (from
), to (to
)
30 TypeCoercionRules::CoercionResult
31 TypeCastRules::resolve (location_t locus
, TyTy::TyWithLocation from
,
32 TyTy::TyWithLocation to
, bool emit_error
)
34 TypeCastRules
cast_rules (locus
, from
, to
);
35 return cast_rules
.check (emit_error
);
38 TypeCoercionRules::CoercionResult
39 TypeCastRules::check (bool emit_error
)
41 // try the simple cast rules
42 auto simple_cast
= cast_rules ();
43 if (!simple_cast
.is_error ())
46 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
47 auto possible_coercion
48 = TypeCoercionRules::TryCoerce (from
.get_ty (), to
.get_ty (), locus
,
49 true /*allow-autoderef*/,
50 true /*is_cast_site*/);
51 if (!possible_coercion
.is_error ())
53 // given the attempt was ok we need to ensure we perform it so that any
54 // inference variables are unified correctly
55 return TypeCoercionRules::Coerce (from
.get_ty (), to
.get_ty (), locus
,
56 true /*allow-autoderef*/,
57 true /*is_cast_site*/);
61 TypeCastRules::emit_cast_error (locus
, from
, to
);
63 return TypeCoercionRules::CoercionResult::get_error ();
66 TypeCoercionRules::CoercionResult
67 TypeCastRules::cast_rules ()
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
72 TyTy::BaseType
*from_type
= from
.get_ty ()->destructure ();
74 rust_debug ("cast_rules from={%s} to={%s}", from_type
->debug_str ().c_str (),
75 to
.get_ty ()->debug_str ().c_str ());
76 switch (from_type
->get_kind ())
78 case TyTy::TypeKind::INFER
:
80 TyTy::InferType
*from_infer
81 = static_cast<TyTy::InferType
*> (from_type
);
82 switch (from_infer
->get_infer_kind ())
84 case TyTy::InferType::InferTypeKind::GENERAL
:
85 return TypeCoercionRules::CoercionResult
{{},
86 to
.get_ty ()->clone ()};
88 case TyTy::InferType::InferTypeKind::INTEGRAL
:
89 switch (to
.get_ty ()->get_kind ())
91 case TyTy::TypeKind::CHAR
:
95 = from
.get_ty ()->get_kind () == TyTy::TypeKind::UINT
;
98 && (static_cast<TyTy::UintType
*> (from
.get_ty ())
100 == TyTy::UintType::UintKind::U8
);
102 return TypeCoercionRules::CoercionResult
{
103 {}, to
.get_ty ()->clone ()};
107 case TyTy::TypeKind::USIZE
:
108 case TyTy::TypeKind::ISIZE
:
109 case TyTy::TypeKind::UINT
:
110 case TyTy::TypeKind::INT
:
111 case TyTy::TypeKind::POINTER
:
112 return TypeCoercionRules::CoercionResult
{
113 {}, to
.get_ty ()->clone ()};
115 case TyTy::TypeKind::INFER
:
117 TyTy::InferType
*to_infer
118 = static_cast<TyTy::InferType
*> (to
.get_ty ());
120 switch (to_infer
->get_infer_kind ())
122 case TyTy::InferType::InferTypeKind::GENERAL
:
123 case TyTy::InferType::InferTypeKind::INTEGRAL
:
124 return TypeCoercionRules::CoercionResult
{
125 {}, to
.get_ty ()->clone ()};
128 return TypeCoercionRules::CoercionResult::get_error ();
134 return TypeCoercionRules::CoercionResult::get_error ();
138 case TyTy::InferType::InferTypeKind::FLOAT
:
139 switch (to
.get_ty ()->get_kind ())
141 case TyTy::TypeKind::USIZE
:
142 case TyTy::TypeKind::ISIZE
:
143 case TyTy::TypeKind::UINT
:
144 case TyTy::TypeKind::INT
:
145 return TypeCoercionRules::CoercionResult
{
146 {}, to
.get_ty ()->clone ()};
148 case TyTy::TypeKind::INFER
:
150 TyTy::InferType
*to_infer
151 = static_cast<TyTy::InferType
*> (to
.get_ty ());
153 switch (to_infer
->get_infer_kind ())
155 case TyTy::InferType::InferTypeKind::GENERAL
:
156 case TyTy::InferType::InferTypeKind::FLOAT
:
157 return TypeCoercionRules::CoercionResult
{
158 {}, to
.get_ty ()->clone ()};
161 return TypeCoercionRules::CoercionResult::get_error ();
167 return TypeCoercionRules::CoercionResult::get_error ();
174 case TyTy::TypeKind::BOOL
:
175 switch (to
.get_ty ()->get_kind ())
177 case TyTy::TypeKind::INFER
:
178 case TyTy::TypeKind::USIZE
:
179 case TyTy::TypeKind::ISIZE
:
180 case TyTy::TypeKind::UINT
:
181 case TyTy::TypeKind::INT
:
182 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
185 return TypeCoercionRules::CoercionResult::get_error ();
189 case TyTy::TypeKind::CHAR
:
190 case TyTy::TypeKind::USIZE
:
191 case TyTy::TypeKind::ISIZE
:
192 case TyTy::TypeKind::UINT
:
193 case TyTy::TypeKind::INT
:
194 switch (to
.get_ty ()->get_kind ())
196 case TyTy::TypeKind::CHAR
:
199 bool was_uint
= from
.get_ty ()->get_kind () == TyTy::TypeKind::UINT
;
200 bool was_u8
= was_uint
201 && (static_cast<TyTy::UintType
*> (from
.get_ty ())
203 == TyTy::UintType::UintKind::U8
);
205 return TypeCoercionRules::CoercionResult
{{},
206 to
.get_ty ()->clone ()};
210 case TyTy::TypeKind::FLOAT
:
212 // can only do this for number types not char
214 = from
.get_ty ()->get_kind () == TyTy::TypeKind::CHAR
;
216 return TypeCoercionRules::CoercionResult
{{},
217 to
.get_ty ()->clone ()};
221 case TyTy::TypeKind::POINTER
:
223 // char can't be casted as a ptr
225 = from
.get_ty ()->get_kind () == TyTy::TypeKind::CHAR
;
227 return TypeCoercionRules::CoercionResult
{{},
228 to
.get_ty ()->clone ()};
232 case TyTy::TypeKind::INFER
:
233 case TyTy::TypeKind::USIZE
:
234 case TyTy::TypeKind::ISIZE
:
235 case TyTy::TypeKind::UINT
:
236 case TyTy::TypeKind::INT
:
237 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
240 return TypeCoercionRules::CoercionResult::get_error ();
244 case TyTy::TypeKind::FLOAT
:
245 switch (to
.get_ty ()->get_kind ())
247 case TyTy::TypeKind::USIZE
:
248 case TyTy::TypeKind::ISIZE
:
249 case TyTy::TypeKind::UINT
:
250 case TyTy::TypeKind::INT
:
251 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
253 case TyTy::TypeKind::FLOAT
:
254 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
256 case TyTy::TypeKind::INFER
:
258 TyTy::InferType
*to_infer
259 = static_cast<TyTy::InferType
*> (to
.get_ty ());
261 switch (to_infer
->get_infer_kind ())
263 case TyTy::InferType::InferTypeKind::GENERAL
:
264 case TyTy::InferType::InferTypeKind::FLOAT
:
265 return TypeCoercionRules::CoercionResult
{
266 {}, to
.get_ty ()->clone ()};
269 return TypeCoercionRules::CoercionResult::get_error ();
275 return TypeCoercionRules::CoercionResult::get_error ();
279 case TyTy::TypeKind::REF
:
280 case TyTy::TypeKind::FNPTR
:
281 case TyTy::TypeKind::POINTER
:
282 switch (to
.get_ty ()->get_kind ())
284 case TyTy::TypeKind::USIZE
:
285 case TyTy::TypeKind::ISIZE
:
286 case TyTy::TypeKind::UINT
:
287 case TyTy::TypeKind::INT
:
289 // refs should not cast to numeric type
290 auto kind
= from
.get_ty ()->get_kind ();
291 bool from_ptr
= kind
== TyTy::TypeKind::POINTER
292 || kind
== TyTy::TypeKind::FNPTR
;
295 return TypeCoercionRules::CoercionResult
{
296 {}, to
.get_ty ()->clone ()};
301 case TyTy::TypeKind::REF
:
302 case TyTy::TypeKind::POINTER
:
303 return check_ptr_ptr_cast ();
306 return TypeCoercionRules::CoercionResult::get_error ();
311 return TypeCoercionRules::CoercionResult::get_error ();
314 return TypeCoercionRules::CoercionResult::get_error ();
317 TypeCoercionRules::CoercionResult
318 TypeCastRules::check_ptr_ptr_cast ()
320 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 ());
324 bool from_is_ref
= from
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
325 bool to_is_ref
= to
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
326 bool from_is_ptr
= from
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
327 bool to_is_ptr
= to
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
329 if (from_is_ptr
&& to_is_ptr
)
331 // mutability is ignored here as all pointer usage requires unsafe
332 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
334 else if (from_is_ref
&& to_is_ref
)
336 const auto &from_ref
= *from
.get_ty ()->as
<TyTy::ReferenceType
> ();
337 const auto &to_ref
= *to
.get_ty ()->as
<TyTy::ReferenceType
> ();
339 if (from_ref
.is_dyn_object () != to_ref
.is_dyn_object ())
341 // this needs to be handled by coercion logic
342 return TypeCoercionRules::CoercionResult::get_error ();
345 // are the underlying types safely simple castable?
346 const auto to_underly
= to_ref
.get_base ();
347 const auto from_underly
= from_ref
.get_base ();
348 auto res
= resolve (locus
, TyTy::TyWithLocation (from_underly
),
349 TyTy::TyWithLocation (to_underly
), false);
352 // this needs to be handled by coercion logic
353 return TypeCoercionRules::CoercionResult::get_error ();
356 // mutability must be coerceable
357 TyTy::ReferenceType
&f
358 = static_cast<TyTy::ReferenceType
&> (*from
.get_ty ());
359 TyTy::ReferenceType
&t
360 = static_cast<TyTy::ReferenceType
&> (*to
.get_ty ());
362 if (TypeCoercionRules::coerceable_mutability (f
.mutability (),
365 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
369 return TypeCoercionRules::CoercionResult::get_error ();
373 TypeCastRules::emit_cast_error (location_t locus
, TyTy::TyWithLocation from
,
374 TyTy::TyWithLocation to
)
376 rich_location
r (line_table
, locus
);
377 r
.add_range (from
.get_locus ());
378 r
.add_range (to
.get_locus ());
379 ErrorCode error_code
;
380 std::string error_msg
;
381 switch (to
.get_ty ()->get_kind ())
383 case TyTy::TypeKind::BOOL
:
384 error_msg
= "cannot cast %qs as %qs";
385 error_code
= ErrorCode::E0054
;
387 case TyTy::TypeKind::CHAR
:
389 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
390 error_code
= ErrorCode::E0604
;
392 case TyTy::TypeKind::SLICE
:
393 error_msg
= "cast to unsized type: %qs as %qs";
394 error_code
= ErrorCode::E0620
;
398 error_msg
= "casting %qs as %qs is invalid";
399 error_code
= ErrorCode::E0606
;
402 rust_error_at (r
, error_code
, error_msg
.c_str (),
403 from
.get_ty ()->get_name ().c_str (),
404 to
.get_ty ()->get_name ().c_str ());
407 } // namespace Resolver