]>
Commit | Line | Data |
---|---|---|
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 | |
22 | namespace Rust { | |
23 | namespace Resolver { | |
24 | ||
d991a3f1 | 25 | TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from, |
06688fe4 PH |
26 | TyTy::TyWithLocation to) |
27 | : locus (locus), from (from), to (to) | |
28 | {} | |
29 | ||
30 | TypeCoercionRules::CoercionResult | |
d991a3f1 | 31 | TypeCastRules::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 | ||
38 | TypeCoercionRules::CoercionResult | |
04b29afc | 39 | TypeCastRules::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 | ||
66 | TypeCoercionRules::CoercionResult | |
67 | TypeCastRules::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 | ||
315 | TypeCoercionRules::CoercionResult | |
316 | TypeCastRules::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 | ||
370 | void | |
04b29afc PH |
371 | TypeCastRules::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 |