]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-casts.cc
openmp: Refactor handling of iterators
[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"
20
21namespace Rust {
22namespace Resolver {
23
d991a3f1 24TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
06688fe4
PH
25 TyTy::TyWithLocation to)
26 : locus (locus), from (from), to (to)
27{}
28
29TypeCoercionRules::CoercionResult
d991a3f1 30TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
06688fe4
PH
31 TyTy::TyWithLocation to)
32{
33 TypeCastRules cast_rules (locus, from, to);
34 return cast_rules.check ();
35}
36
37TypeCoercionRules::CoercionResult
38TypeCastRules::check ()
39{
40 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
41 auto possible_coercion
e6750011 42 = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
8ae7e93d
PH
43 true /*allow-autoderef*/,
44 true /*is_cast_site*/);
06688fe4 45 if (!possible_coercion.is_error ())
1b34e40e
PH
46 {
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,
8ae7e93d
PH
50 true /*allow-autoderef*/,
51 true /*is_cast_site*/);
1b34e40e 52 }
06688fe4
PH
53
54 // try the simple cast rules
55 auto simple_cast = cast_rules ();
56 if (!simple_cast.is_error ())
57 return simple_cast;
58
59 // failed to cast
60 emit_cast_error ();
61 return TypeCoercionRules::CoercionResult::get_error ();
62}
63
64TypeCoercionRules::CoercionResult
65TypeCastRules::cast_rules ()
66{
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
69
525110ae 70 TyTy::BaseType *from_type = from.get_ty ()->destructure ();
71
72 rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
06688fe4 73 to.get_ty ()->debug_str ().c_str ());
525110ae 74 switch (from_type->get_kind ())
06688fe4
PH
75 {
76 case TyTy::TypeKind::INFER: {
77 TyTy::InferType *from_infer
525110ae 78 = static_cast<TyTy::InferType *> (from_type);
06688fe4
PH
79 switch (from_infer->get_infer_kind ())
80 {
81 case TyTy::InferType::InferTypeKind::GENERAL:
82 return TypeCoercionRules::CoercionResult{{},
83 to.get_ty ()->clone ()};
84
85 case TyTy::InferType::InferTypeKind::INTEGRAL:
86 switch (to.get_ty ()->get_kind ())
87 {
bdb4e293
EM
88 case TyTy::TypeKind::CHAR: {
89 // only u8 and char
90 bool was_uint
91 = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
92 bool was_u8
93 = was_uint
94 && (static_cast<TyTy::UintType *> (from.get_ty ())
95 ->get_uint_kind ()
96 == TyTy::UintType::UintKind::U8);
97 if (was_u8)
98 return TypeCoercionRules::CoercionResult{
99 {}, to.get_ty ()->clone ()};
100 }
101 break;
102
06688fe4
PH
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 ()};
110
111 case TyTy::TypeKind::INFER: {
112 TyTy::InferType *to_infer
113 = static_cast<TyTy::InferType *> (to.get_ty ());
114
115 switch (to_infer->get_infer_kind ())
116 {
117 case TyTy::InferType::InferTypeKind::GENERAL:
118 case TyTy::InferType::InferTypeKind::INTEGRAL:
119 return TypeCoercionRules::CoercionResult{
120 {}, to.get_ty ()->clone ()};
121
122 default:
123 return TypeCoercionRules::CoercionResult::get_error ();
124 }
125 }
126 break;
127
128 default:
129 return TypeCoercionRules::CoercionResult::get_error ();
130 }
131 break;
132
133 case TyTy::InferType::InferTypeKind::FLOAT:
134 switch (to.get_ty ()->get_kind ())
135 {
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 ()};
142
143 case TyTy::TypeKind::INFER: {
144 TyTy::InferType *to_infer
145 = static_cast<TyTy::InferType *> (to.get_ty ());
146
147 switch (to_infer->get_infer_kind ())
148 {
149 case TyTy::InferType::InferTypeKind::GENERAL:
150 case TyTy::InferType::InferTypeKind::FLOAT:
151 return TypeCoercionRules::CoercionResult{
152 {}, to.get_ty ()->clone ()};
153
154 default:
155 return TypeCoercionRules::CoercionResult::get_error ();
156 }
157 }
158 break;
159
160 default:
161 return TypeCoercionRules::CoercionResult::get_error ();
162 }
163 break;
164 }
165 }
166 break;
167
168 case TyTy::TypeKind::BOOL:
169 switch (to.get_ty ()->get_kind ())
170 {
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 ()};
177
178 default:
179 return TypeCoercionRules::CoercionResult::get_error ();
180 }
181 break;
182
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 ())
189 {
190 case TyTy::TypeKind::CHAR: {
191 // only u8 and 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 ())
195 ->get_uint_kind ()
196 == TyTy::UintType::UintKind::U8);
197 if (was_u8)
198 return TypeCoercionRules::CoercionResult{{},
199 to.get_ty ()->clone ()};
200 }
201 break;
202
80bc600e
PH
203 case TyTy::TypeKind::FLOAT: {
204 // can only do this for number types not char
205 bool from_char
206 = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
207 if (!from_char)
208 return TypeCoercionRules::CoercionResult{{},
209 to.get_ty ()->clone ()};
210 }
211 break;
212
3396da35
N
213 case TyTy::TypeKind::POINTER: {
214 // char can't be casted as a ptr
215 bool from_char
216 = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
217 if (!from_char)
218 return TypeCoercionRules::CoercionResult{{},
219 to.get_ty ()->clone ()};
220 }
221 break;
222
06688fe4
PH
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 ()};
229
230 default:
231 return TypeCoercionRules::CoercionResult::get_error ();
232 }
233 break;
234
235 case TyTy::TypeKind::FLOAT:
236 switch (to.get_ty ()->get_kind ())
237 {
1cad5f2b
N
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 ()};
243
06688fe4
PH
244 case TyTy::TypeKind::FLOAT:
245 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
246
247 case TyTy::TypeKind::INFER: {
248 TyTy::InferType *to_infer
249 = static_cast<TyTy::InferType *> (to.get_ty ());
250
251 switch (to_infer->get_infer_kind ())
252 {
253 case TyTy::InferType::InferTypeKind::GENERAL:
254 case TyTy::InferType::InferTypeKind::FLOAT:
255 return TypeCoercionRules::CoercionResult{
256 {}, to.get_ty ()->clone ()};
257
258 default:
259 return TypeCoercionRules::CoercionResult::get_error ();
260 }
261 }
262 break;
263
264 default:
265 return TypeCoercionRules::CoercionResult::get_error ();
266 }
267 break;
268
269 case TyTy::TypeKind::REF:
270 case TyTy::TypeKind::POINTER:
271 switch (to.get_ty ()->get_kind ())
272 {
3396da35
N
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
278 bool from_ptr
279 = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
280 if (from_ptr)
281 {
282 return TypeCoercionRules::CoercionResult{
283 {}, to.get_ty ()->clone ()};
284 }
285 }
286 break;
287
06688fe4
PH
288 case TyTy::TypeKind::REF:
289 case TyTy::TypeKind::POINTER:
290 return check_ptr_ptr_cast ();
291
06688fe4
PH
292 default:
293 return TypeCoercionRules::CoercionResult::get_error ();
294 }
295 break;
296
297 default:
298 return TypeCoercionRules::CoercionResult::get_error ();
299 }
300
301 return TypeCoercionRules::CoercionResult::get_error ();
302}
303
304TypeCoercionRules::CoercionResult
305TypeCastRules::check_ptr_ptr_cast ()
306{
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 ());
310
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;
315
316 if (from_is_ptr && to_is_ptr)
317 {
318 // mutability is ignored here as all pointer usage requires unsafe
319 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
320 }
321 else if (from_is_ref && to_is_ref)
322 {
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 ());
328
329 if (TypeCoercionRules::coerceable_mutability (f.mutability (),
330 t.mutability ()))
331 {
332 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
333 }
334 }
335
336 return TypeCoercionRules::CoercionResult::get_error ();
337}
338
339void
340TypeCastRules::emit_cast_error () const
341{
ffadba42 342 rich_location r (line_table, locus);
06688fe4
PH
343 r.add_range (from.get_locus ());
344 r.add_range (to.get_locus ());
2952785b
MM
345 ErrorCode error_code;
346 std::string error_msg;
347 switch (to.get_ty ()->get_kind ())
348 {
349 case TyTy::TypeKind::BOOL:
350 error_msg = "cannot cast %qs as %qs";
351 error_code = ErrorCode::E0054;
352 break;
353 case TyTy::TypeKind::CHAR:
354 error_msg
355 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
356 error_code = ErrorCode::E0604;
357 break;
358 case TyTy::TypeKind::SLICE:
359 error_msg = "cast to unsized type: %qs as %qs";
360 error_code = ErrorCode::E0620;
361 break;
362
363 default:
364 error_msg = "casting %qs as %qs is invalid";
365 error_code = ErrorCode::E0606;
366 break;
367 }
368 rust_error_at (r, error_code, error_msg.c_str (),
06688fe4
PH
369 from.get_ty ()->get_name ().c_str (),
370 to.get_ty ()->get_name ().c_str ());
371}
372
373} // namespace Resolver
1b34e40e 374} // namespace Rust