]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/typecheck/rust-casts.cc
f06d9ed24e8e7d876bfee6c902894b944b3a31c0
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::POINTER
:
281 switch (to
.get_ty ()->get_kind ())
283 case TyTy::TypeKind::USIZE
:
284 case TyTy::TypeKind::ISIZE
:
285 case TyTy::TypeKind::UINT
:
286 case TyTy::TypeKind::INT
:
288 // refs should not cast to numeric type
290 = from
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
293 return TypeCoercionRules::CoercionResult
{
294 {}, to
.get_ty ()->clone ()};
299 case TyTy::TypeKind::REF
:
300 case TyTy::TypeKind::POINTER
:
301 return check_ptr_ptr_cast ();
304 return TypeCoercionRules::CoercionResult::get_error ();
309 return TypeCoercionRules::CoercionResult::get_error ();
312 return TypeCoercionRules::CoercionResult::get_error ();
315 TypeCoercionRules::CoercionResult
316 TypeCastRules::check_ptr_ptr_cast ()
318 rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
319 from
.get_ty ()->debug_str ().c_str (),
320 to
.get_ty ()->debug_str ().c_str ());
322 bool from_is_ref
= from
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
323 bool to_is_ref
= to
.get_ty ()->get_kind () == TyTy::TypeKind::REF
;
324 bool from_is_ptr
= from
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
325 bool to_is_ptr
= to
.get_ty ()->get_kind () == TyTy::TypeKind::POINTER
;
327 if (from_is_ptr
&& to_is_ptr
)
329 // mutability is ignored here as all pointer usage requires unsafe
330 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
332 else if (from_is_ref
&& to_is_ref
)
334 const auto &from_ref
= *from
.get_ty ()->as
<TyTy::ReferenceType
> ();
335 const auto &to_ref
= *to
.get_ty ()->as
<TyTy::ReferenceType
> ();
337 if (from_ref
.is_dyn_object () != to_ref
.is_dyn_object ())
339 // this needs to be handled by coercion logic
340 return TypeCoercionRules::CoercionResult::get_error ();
343 // are the underlying types safely simple castable?
344 const auto to_underly
= to_ref
.get_base ();
345 const auto from_underly
= from_ref
.get_base ();
346 auto res
= resolve (locus
, TyTy::TyWithLocation (from_underly
),
347 TyTy::TyWithLocation (to_underly
), false);
350 // this needs to be handled by coercion logic
351 return TypeCoercionRules::CoercionResult::get_error ();
354 // mutability must be coerceable
355 TyTy::ReferenceType
&f
356 = static_cast<TyTy::ReferenceType
&> (*from
.get_ty ());
357 TyTy::ReferenceType
&t
358 = static_cast<TyTy::ReferenceType
&> (*to
.get_ty ());
360 if (TypeCoercionRules::coerceable_mutability (f
.mutability (),
363 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
367 return TypeCoercionRules::CoercionResult::get_error ();
371 TypeCastRules::emit_cast_error (location_t locus
, TyTy::TyWithLocation from
,
372 TyTy::TyWithLocation to
)
374 rich_location
r (line_table
, locus
);
375 r
.add_range (from
.get_locus ());
376 r
.add_range (to
.get_locus ());
377 ErrorCode error_code
;
378 std::string error_msg
;
379 switch (to
.get_ty ()->get_kind ())
381 case TyTy::TypeKind::BOOL
:
382 error_msg
= "cannot cast %qs as %qs";
383 error_code
= ErrorCode::E0054
;
385 case TyTy::TypeKind::CHAR
:
387 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
388 error_code
= ErrorCode::E0604
;
390 case TyTy::TypeKind::SLICE
:
391 error_msg
= "cast to unsized type: %qs as %qs";
392 error_code
= ErrorCode::E0620
;
396 error_msg
= "casting %qs as %qs is invalid";
397 error_code
= ErrorCode::E0606
;
400 rust_error_at (r
, error_code
, error_msg
.c_str (),
401 from
.get_ty ()->get_name ().c_str (),
402 to
.get_ty ()->get_name ().c_str ());
405 } // namespace Resolver