]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-casts.cc
Daily bump.
[thirdparty/gcc.git] / gcc / rust / typecheck / rust-casts.cc
CommitLineData
6441eb6d 1// Copyright (C) 2020-2025 Free Software Foundation, Inc.
06688fe4
PH
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"
04b29afc 20#include "rust-tyty-util.h"
06688fe4
PH
21
22namespace Rust {
23namespace Resolver {
24
d991a3f1 25TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
06688fe4
PH
26 TyTy::TyWithLocation to)
27 : locus (locus), from (from), to (to)
28{}
29
30TypeCoercionRules::CoercionResult
d991a3f1 31TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
04b29afc 32 TyTy::TyWithLocation to, bool emit_error)
06688fe4
PH
33{
34 TypeCastRules cast_rules (locus, from, to);
04b29afc 35 return cast_rules.check (emit_error);
06688fe4
PH
36}
37
38TypeCoercionRules::CoercionResult
04b29afc 39TypeCastRules::check (bool emit_error)
06688fe4 40{
04b29afc
PH
41 // try the simple cast rules
42 auto simple_cast = cast_rules ();
43 if (!simple_cast.is_error ())
44 return simple_cast;
45
06688fe4
PH
46 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
47 auto possible_coercion
e6750011 48 = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
8ae7e93d
PH
49 true /*allow-autoderef*/,
50 true /*is_cast_site*/);
06688fe4 51 if (!possible_coercion.is_error ())
1b34e40e
PH
52 {
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,
8ae7e93d
PH
56 true /*allow-autoderef*/,
57 true /*is_cast_site*/);
1b34e40e 58 }
06688fe4 59
04b29afc
PH
60 if (emit_error)
61 TypeCastRules::emit_cast_error (locus, from, to);
06688fe4 62
06688fe4
PH
63 return TypeCoercionRules::CoercionResult::get_error ();
64}
65
66TypeCoercionRules::CoercionResult
67TypeCastRules::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
525110ae 72 TyTy::BaseType *from_type = from.get_ty ()->destructure ();
73
74 rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
06688fe4 75 to.get_ty ()->debug_str ().c_str ());
525110ae 76 switch (from_type->get_kind ())
06688fe4 77 {
dd65cf1d
MP
78 case TyTy::TypeKind::INFER:
79 {
06688fe4 80 TyTy::InferType *from_infer
525110ae 81 = static_cast<TyTy::InferType *> (from_type);
06688fe4
PH
82 switch (from_infer->get_infer_kind ())
83 {
84 case TyTy::InferType::InferTypeKind::GENERAL:
85 return TypeCoercionRules::CoercionResult{{},
86 to.get_ty ()->clone ()};
87
88 case TyTy::InferType::InferTypeKind::INTEGRAL:
89 switch (to.get_ty ()->get_kind ())
90 {
dd65cf1d
MP
91 case TyTy::TypeKind::CHAR:
92 {
bdb4e293
EM
93 // only u8 and char
94 bool was_uint
95 = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
96 bool was_u8
97 = was_uint
98 && (static_cast<TyTy::UintType *> (from.get_ty ())
99 ->get_uint_kind ()
100 == TyTy::UintType::UintKind::U8);
101 if (was_u8)
102 return TypeCoercionRules::CoercionResult{
103 {}, to.get_ty ()->clone ()};
104 }
105 break;
106
06688fe4
PH
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 ()};
114
dd65cf1d
MP
115 case TyTy::TypeKind::INFER:
116 {
06688fe4
PH
117 TyTy::InferType *to_infer
118 = static_cast<TyTy::InferType *> (to.get_ty ());
119
120 switch (to_infer->get_infer_kind ())
121 {
122 case TyTy::InferType::InferTypeKind::GENERAL:
123 case TyTy::InferType::InferTypeKind::INTEGRAL:
124 return TypeCoercionRules::CoercionResult{
125 {}, to.get_ty ()->clone ()};
126
127 default:
128 return TypeCoercionRules::CoercionResult::get_error ();
129 }
130 }
131 break;
132
133 default:
134 return TypeCoercionRules::CoercionResult::get_error ();
135 }
136 break;
137
138 case TyTy::InferType::InferTypeKind::FLOAT:
139 switch (to.get_ty ()->get_kind ())
140 {
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 ()};
147
dd65cf1d
MP
148 case TyTy::TypeKind::INFER:
149 {
06688fe4
PH
150 TyTy::InferType *to_infer
151 = static_cast<TyTy::InferType *> (to.get_ty ());
152
153 switch (to_infer->get_infer_kind ())
154 {
155 case TyTy::InferType::InferTypeKind::GENERAL:
156 case TyTy::InferType::InferTypeKind::FLOAT:
157 return TypeCoercionRules::CoercionResult{
158 {}, to.get_ty ()->clone ()};
159
160 default:
161 return TypeCoercionRules::CoercionResult::get_error ();
162 }
163 }
164 break;
165
166 default:
167 return TypeCoercionRules::CoercionResult::get_error ();
168 }
169 break;
170 }
171 }
172 break;
173
174 case TyTy::TypeKind::BOOL:
175 switch (to.get_ty ()->get_kind ())
176 {
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 ()};
183
184 default:
185 return TypeCoercionRules::CoercionResult::get_error ();
186 }
187 break;
188
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 ())
195 {
dd65cf1d
MP
196 case TyTy::TypeKind::CHAR:
197 {
06688fe4
PH
198 // only u8 and 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 ())
202 ->get_uint_kind ()
203 == TyTy::UintType::UintKind::U8);
204 if (was_u8)
205 return TypeCoercionRules::CoercionResult{{},
206 to.get_ty ()->clone ()};
207 }
208 break;
209
dd65cf1d
MP
210 case TyTy::TypeKind::FLOAT:
211 {
80bc600e
PH
212 // can only do this for number types not char
213 bool from_char
214 = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
215 if (!from_char)
216 return TypeCoercionRules::CoercionResult{{},
217 to.get_ty ()->clone ()};
218 }
219 break;
220
dd65cf1d
MP
221 case TyTy::TypeKind::POINTER:
222 {
3396da35
N
223 // char can't be casted as a ptr
224 bool from_char
225 = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
226 if (!from_char)
227 return TypeCoercionRules::CoercionResult{{},
228 to.get_ty ()->clone ()};
229 }
230 break;
231
06688fe4
PH
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 ()};
238
239 default:
240 return TypeCoercionRules::CoercionResult::get_error ();
241 }
242 break;
243
244 case TyTy::TypeKind::FLOAT:
245 switch (to.get_ty ()->get_kind ())
246 {
1cad5f2b
N
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 ()};
252
06688fe4
PH
253 case TyTy::TypeKind::FLOAT:
254 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
255
dd65cf1d
MP
256 case TyTy::TypeKind::INFER:
257 {
06688fe4
PH
258 TyTy::InferType *to_infer
259 = static_cast<TyTy::InferType *> (to.get_ty ());
260
261 switch (to_infer->get_infer_kind ())
262 {
263 case TyTy::InferType::InferTypeKind::GENERAL:
264 case TyTy::InferType::InferTypeKind::FLOAT:
265 return TypeCoercionRules::CoercionResult{
266 {}, to.get_ty ()->clone ()};
267
268 default:
269 return TypeCoercionRules::CoercionResult::get_error ();
270 }
271 }
272 break;
273
274 default:
275 return TypeCoercionRules::CoercionResult::get_error ();
276 }
277 break;
278
279 case TyTy::TypeKind::REF:
280 case TyTy::TypeKind::POINTER:
281 switch (to.get_ty ()->get_kind ())
282 {
3396da35
N
283 case TyTy::TypeKind::USIZE:
284 case TyTy::TypeKind::ISIZE:
285 case TyTy::TypeKind::UINT:
dd65cf1d
MP
286 case TyTy::TypeKind::INT:
287 {
3396da35
N
288 // refs should not cast to numeric type
289 bool from_ptr
290 = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
291 if (from_ptr)
292 {
293 return TypeCoercionRules::CoercionResult{
294 {}, to.get_ty ()->clone ()};
295 }
296 }
297 break;
298
06688fe4
PH
299 case TyTy::TypeKind::REF:
300 case TyTy::TypeKind::POINTER:
301 return check_ptr_ptr_cast ();
302
06688fe4
PH
303 default:
304 return TypeCoercionRules::CoercionResult::get_error ();
305 }
306 break;
307
308 default:
309 return TypeCoercionRules::CoercionResult::get_error ();
310 }
311
312 return TypeCoercionRules::CoercionResult::get_error ();
313}
314
315TypeCoercionRules::CoercionResult
316TypeCastRules::check_ptr_ptr_cast ()
317{
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 ());
321
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;
326
327 if (from_is_ptr && to_is_ptr)
328 {
329 // mutability is ignored here as all pointer usage requires unsafe
330 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
331 }
332 else if (from_is_ref && to_is_ref)
333 {
04b29afc
PH
334 const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
335 const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
336
337 if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
338 {
339 // this needs to be handled by coercion logic
340 return TypeCoercionRules::CoercionResult::get_error ();
341 }
342
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);
348 if (res.is_error ())
349 {
350 // this needs to be handled by coercion logic
351 return TypeCoercionRules::CoercionResult::get_error ();
352 }
353
354 // mutability must be coerceable
06688fe4
PH
355 TyTy::ReferenceType &f
356 = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
357 TyTy::ReferenceType &t
358 = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
359
360 if (TypeCoercionRules::coerceable_mutability (f.mutability (),
361 t.mutability ()))
362 {
363 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
364 }
365 }
366
367 return TypeCoercionRules::CoercionResult::get_error ();
368}
369
370void
04b29afc
PH
371TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
372 TyTy::TyWithLocation to)
06688fe4 373{
ffadba42 374 rich_location r (line_table, locus);
06688fe4
PH
375 r.add_range (from.get_locus ());
376 r.add_range (to.get_locus ());
2952785b
MM
377 ErrorCode error_code;
378 std::string error_msg;
379 switch (to.get_ty ()->get_kind ())
380 {
381 case TyTy::TypeKind::BOOL:
382 error_msg = "cannot cast %qs as %qs";
383 error_code = ErrorCode::E0054;
384 break;
385 case TyTy::TypeKind::CHAR:
386 error_msg
387 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
388 error_code = ErrorCode::E0604;
389 break;
390 case TyTy::TypeKind::SLICE:
391 error_msg = "cast to unsized type: %qs as %qs";
392 error_code = ErrorCode::E0620;
393 break;
394
395 default:
396 error_msg = "casting %qs as %qs is invalid";
397 error_code = ErrorCode::E0606;
398 break;
399 }
400 rust_error_at (r, error_code, error_msg.c_str (),
06688fe4
PH
401 from.get_ty ()->get_name ().c_str (),
402 to.get_ty ()->get_name ().c_str ());
403}
404
405} // namespace Resolver
1b34e40e 406} // namespace Rust