]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-casts.cc
tree-optimization/122577 - missed vectorization of conversion from bool
[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:
94b82f54 280 case TyTy::TypeKind::FNPTR:
06688fe4
PH
281 case TyTy::TypeKind::POINTER:
282 switch (to.get_ty ()->get_kind ())
283 {
3396da35
N
284 case TyTy::TypeKind::USIZE:
285 case TyTy::TypeKind::ISIZE:
286 case TyTy::TypeKind::UINT:
dd65cf1d
MP
287 case TyTy::TypeKind::INT:
288 {
3396da35 289 // refs should not cast to numeric type
94b82f54
PEP
290 auto kind = from.get_ty ()->get_kind ();
291 bool from_ptr = kind == TyTy::TypeKind::POINTER
292 || kind == TyTy::TypeKind::FNPTR;
3396da35
N
293 if (from_ptr)
294 {
295 return TypeCoercionRules::CoercionResult{
296 {}, to.get_ty ()->clone ()};
297 }
298 }
299 break;
300
06688fe4
PH
301 case TyTy::TypeKind::REF:
302 case TyTy::TypeKind::POINTER:
303 return check_ptr_ptr_cast ();
304
06688fe4
PH
305 default:
306 return TypeCoercionRules::CoercionResult::get_error ();
307 }
308 break;
309
310 default:
311 return TypeCoercionRules::CoercionResult::get_error ();
312 }
313
314 return TypeCoercionRules::CoercionResult::get_error ();
315}
316
317TypeCoercionRules::CoercionResult
318TypeCastRules::check_ptr_ptr_cast ()
319{
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 ());
323
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;
328
329 if (from_is_ptr && to_is_ptr)
330 {
331 // mutability is ignored here as all pointer usage requires unsafe
332 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
333 }
334 else if (from_is_ref && to_is_ref)
335 {
04b29afc
PH
336 const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
337 const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
338
339 if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
340 {
341 // this needs to be handled by coercion logic
342 return TypeCoercionRules::CoercionResult::get_error ();
343 }
344
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);
350 if (res.is_error ())
351 {
352 // this needs to be handled by coercion logic
353 return TypeCoercionRules::CoercionResult::get_error ();
354 }
355
356 // mutability must be coerceable
06688fe4
PH
357 TyTy::ReferenceType &f
358 = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
359 TyTy::ReferenceType &t
360 = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
361
362 if (TypeCoercionRules::coerceable_mutability (f.mutability (),
363 t.mutability ()))
364 {
365 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
366 }
367 }
368
369 return TypeCoercionRules::CoercionResult::get_error ();
370}
371
372void
04b29afc
PH
373TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
374 TyTy::TyWithLocation to)
06688fe4 375{
ffadba42 376 rich_location r (line_table, locus);
06688fe4
PH
377 r.add_range (from.get_locus ());
378 r.add_range (to.get_locus ());
2952785b
MM
379 ErrorCode error_code;
380 std::string error_msg;
381 switch (to.get_ty ()->get_kind ())
382 {
383 case TyTy::TypeKind::BOOL:
384 error_msg = "cannot cast %qs as %qs";
385 error_code = ErrorCode::E0054;
386 break;
387 case TyTy::TypeKind::CHAR:
388 error_msg
389 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
390 error_code = ErrorCode::E0604;
391 break;
392 case TyTy::TypeKind::SLICE:
393 error_msg = "cast to unsized type: %qs as %qs";
394 error_code = ErrorCode::E0620;
395 break;
396
397 default:
398 error_msg = "casting %qs as %qs is invalid";
399 error_code = ErrorCode::E0606;
400 break;
401 }
402 rust_error_at (r, error_code, error_msg.c_str (),
06688fe4
PH
403 from.get_ty ()->get_name ().c_str (),
404 to.get_ty ()->get_name ().c_str ());
405}
406
407} // namespace Resolver
1b34e40e 408} // namespace Rust