Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
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 : : #include "rust-tyty-util.h"
21 : :
22 : : namespace Rust {
23 : : namespace Resolver {
24 : :
25 : 4949 : TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
26 : 4949 : TyTy::TyWithLocation to)
27 : 4949 : : locus (locus), from (from), to (to)
28 : 4949 : {}
29 : :
30 : : TypeCoercionRules::CoercionResult
31 : 4949 : TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
32 : : TyTy::TyWithLocation to, bool emit_error)
33 : : {
34 : 4949 : TypeCastRules cast_rules (locus, from, to);
35 : 4949 : return cast_rules.check (emit_error);
36 : : }
37 : :
38 : : TypeCoercionRules::CoercionResult
39 : 4949 : TypeCastRules::check (bool emit_error)
40 : : {
41 : : // try the simple cast rules
42 : 4949 : auto simple_cast = cast_rules ();
43 : 4949 : if (!simple_cast.is_error ())
44 : 3208 : return simple_cast;
45 : :
46 : : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
47 : 1741 : auto possible_coercion
48 : : = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
49 : : true /*allow-autoderef*/,
50 : 1741 : true /*is_cast_site*/);
51 : 1741 : if (!possible_coercion.is_error ())
52 : : {
53 : : // given the attempt was ok we need to ensure we perform it so that any
54 : : // inference variables are unified correctly
55 : 1718 : return TypeCoercionRules::Coerce (from.get_ty (), to.get_ty (), locus,
56 : : true /*allow-autoderef*/,
57 : 1718 : true /*is_cast_site*/);
58 : : }
59 : :
60 : 23 : if (emit_error)
61 : 16 : TypeCastRules::emit_cast_error (locus, from, to);
62 : :
63 : 23 : return TypeCoercionRules::CoercionResult::get_error ();
64 : 1741 : }
65 : :
66 : : TypeCoercionRules::CoercionResult
67 : 4949 : 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 : :
72 : 4949 : TyTy::BaseType *from_type = from.get_ty ()->destructure ();
73 : :
74 : 4949 : rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
75 : : to.get_ty ()->debug_str ().c_str ());
76 : 4949 : switch (from_type->get_kind ())
77 : : {
78 : 71 : case TyTy::TypeKind::INFER:
79 : 71 : {
80 : 71 : TyTy::InferType *from_infer
81 : : = static_cast<TyTy::InferType *> (from_type);
82 : 71 : switch (from_infer->get_infer_kind ())
83 : : {
84 : 0 : case TyTy::InferType::InferTypeKind::GENERAL:
85 : 0 : return TypeCoercionRules::CoercionResult{{},
86 : 0 : to.get_ty ()->clone ()};
87 : :
88 : 71 : case TyTy::InferType::InferTypeKind::INTEGRAL:
89 : 71 : switch (to.get_ty ()->get_kind ())
90 : : {
91 : 2 : case TyTy::TypeKind::CHAR:
92 : 2 : {
93 : : // only u8 and char
94 : 2 : bool was_uint
95 : 2 : = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
96 : 2 : bool was_u8
97 : : = was_uint
98 : 2 : && (static_cast<TyTy::UintType *> (from.get_ty ())
99 : 0 : ->get_uint_kind ()
100 : 8 : == TyTy::UintType::UintKind::U8);
101 : 0 : if (was_u8)
102 : 0 : return TypeCoercionRules::CoercionResult{
103 : 0 : {}, to.get_ty ()->clone ()};
104 : : }
105 : : break;
106 : :
107 : 52 : case TyTy::TypeKind::USIZE:
108 : 52 : case TyTy::TypeKind::ISIZE:
109 : 52 : case TyTy::TypeKind::UINT:
110 : 52 : case TyTy::TypeKind::INT:
111 : 52 : case TyTy::TypeKind::POINTER:
112 : 52 : return TypeCoercionRules::CoercionResult{
113 : 52 : {}, to.get_ty ()->clone ()};
114 : :
115 : 16 : case TyTy::TypeKind::INFER:
116 : 16 : {
117 : 16 : TyTy::InferType *to_infer
118 : 16 : = static_cast<TyTy::InferType *> (to.get_ty ());
119 : :
120 : 16 : switch (to_infer->get_infer_kind ())
121 : : {
122 : 16 : case TyTy::InferType::InferTypeKind::GENERAL:
123 : 16 : case TyTy::InferType::InferTypeKind::INTEGRAL:
124 : 16 : return TypeCoercionRules::CoercionResult{
125 : 16 : {}, to.get_ty ()->clone ()};
126 : :
127 : 0 : default:
128 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
129 : : }
130 : : }
131 : 1 : break;
132 : :
133 : 1 : default:
134 : 1 : return TypeCoercionRules::CoercionResult::get_error ();
135 : : }
136 : : break;
137 : :
138 : 0 : case TyTy::InferType::InferTypeKind::FLOAT:
139 : 0 : switch (to.get_ty ()->get_kind ())
140 : : {
141 : 0 : case TyTy::TypeKind::USIZE:
142 : 0 : case TyTy::TypeKind::ISIZE:
143 : 0 : case TyTy::TypeKind::UINT:
144 : 0 : case TyTy::TypeKind::INT:
145 : 0 : return TypeCoercionRules::CoercionResult{
146 : 0 : {}, to.get_ty ()->clone ()};
147 : :
148 : 0 : case TyTy::TypeKind::INFER:
149 : 0 : {
150 : 0 : TyTy::InferType *to_infer
151 : 0 : = static_cast<TyTy::InferType *> (to.get_ty ());
152 : :
153 : 0 : switch (to_infer->get_infer_kind ())
154 : : {
155 : 0 : case TyTy::InferType::InferTypeKind::GENERAL:
156 : 0 : case TyTy::InferType::InferTypeKind::FLOAT:
157 : 0 : return TypeCoercionRules::CoercionResult{
158 : 0 : {}, to.get_ty ()->clone ()};
159 : :
160 : 0 : default:
161 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
162 : : }
163 : : }
164 : 0 : break;
165 : :
166 : 0 : default:
167 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
168 : : }
169 : : break;
170 : : }
171 : : }
172 : : break;
173 : :
174 : 52 : case TyTy::TypeKind::BOOL:
175 : 52 : switch (to.get_ty ()->get_kind ())
176 : : {
177 : 49 : case TyTy::TypeKind::INFER:
178 : 49 : case TyTy::TypeKind::USIZE:
179 : 49 : case TyTy::TypeKind::ISIZE:
180 : 49 : case TyTy::TypeKind::UINT:
181 : 49 : case TyTy::TypeKind::INT:
182 : 49 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
183 : :
184 : 3 : default:
185 : 3 : return TypeCoercionRules::CoercionResult::get_error ();
186 : : }
187 : 1220 : break;
188 : :
189 : 1220 : case TyTy::TypeKind::CHAR:
190 : 1220 : case TyTy::TypeKind::USIZE:
191 : 1220 : case TyTy::TypeKind::ISIZE:
192 : 1220 : case TyTy::TypeKind::UINT:
193 : 1220 : case TyTy::TypeKind::INT:
194 : 1220 : switch (to.get_ty ()->get_kind ())
195 : : {
196 : 20 : case TyTy::TypeKind::CHAR:
197 : 20 : {
198 : : // only u8 and char
199 : 20 : bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
200 : 20 : bool was_u8 = was_uint
201 : 20 : && (static_cast<TyTy::UintType *> (from.get_ty ())
202 : 18 : ->get_uint_kind ()
203 : 24 : == TyTy::UintType::UintKind::U8);
204 : 16 : if (was_u8)
205 : 16 : return TypeCoercionRules::CoercionResult{{},
206 : 16 : to.get_ty ()->clone ()};
207 : : }
208 : : break;
209 : :
210 : 10 : case TyTy::TypeKind::FLOAT:
211 : 10 : {
212 : : // can only do this for number types not char
213 : 10 : bool from_char
214 : 10 : = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
215 : 10 : if (!from_char)
216 : 9 : return TypeCoercionRules::CoercionResult{{},
217 : 9 : to.get_ty ()->clone ()};
218 : : }
219 : : break;
220 : :
221 : 6 : case TyTy::TypeKind::POINTER:
222 : 6 : {
223 : : // char can't be casted as a ptr
224 : 6 : bool from_char
225 : 6 : = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR;
226 : 6 : if (!from_char)
227 : 6 : return TypeCoercionRules::CoercionResult{{},
228 : 6 : to.get_ty ()->clone ()};
229 : : }
230 : : break;
231 : :
232 : 1181 : case TyTy::TypeKind::INFER:
233 : 1181 : case TyTy::TypeKind::USIZE:
234 : 1181 : case TyTy::TypeKind::ISIZE:
235 : 1181 : case TyTy::TypeKind::UINT:
236 : 1181 : case TyTy::TypeKind::INT:
237 : 1181 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
238 : :
239 : 3 : default:
240 : 3 : return TypeCoercionRules::CoercionResult::get_error ();
241 : : }
242 : : break;
243 : :
244 : 6 : case TyTy::TypeKind::FLOAT:
245 : 6 : switch (to.get_ty ()->get_kind ())
246 : : {
247 : 6 : case TyTy::TypeKind::USIZE:
248 : 6 : case TyTy::TypeKind::ISIZE:
249 : 6 : case TyTy::TypeKind::UINT:
250 : 6 : case TyTy::TypeKind::INT:
251 : 6 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
252 : :
253 : 0 : case TyTy::TypeKind::FLOAT:
254 : 0 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
255 : :
256 : 0 : case TyTy::TypeKind::INFER:
257 : 0 : {
258 : 0 : TyTy::InferType *to_infer
259 : 0 : = static_cast<TyTy::InferType *> (to.get_ty ());
260 : :
261 : 0 : switch (to_infer->get_infer_kind ())
262 : : {
263 : 0 : case TyTy::InferType::InferTypeKind::GENERAL:
264 : 0 : case TyTy::InferType::InferTypeKind::FLOAT:
265 : 0 : return TypeCoercionRules::CoercionResult{
266 : 0 : {}, to.get_ty ()->clone ()};
267 : :
268 : 0 : default:
269 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
270 : : }
271 : : }
272 : 0 : break;
273 : :
274 : 0 : default:
275 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
276 : : }
277 : 3593 : break;
278 : :
279 : 3593 : case TyTy::TypeKind::REF:
280 : 3593 : case TyTy::TypeKind::POINTER:
281 : 3593 : switch (to.get_ty ()->get_kind ())
282 : : {
283 : 7 : case TyTy::TypeKind::USIZE:
284 : 7 : case TyTy::TypeKind::ISIZE:
285 : 7 : case TyTy::TypeKind::UINT:
286 : 7 : case TyTy::TypeKind::INT:
287 : 7 : {
288 : : // refs should not cast to numeric type
289 : 7 : bool from_ptr
290 : 7 : = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
291 : 7 : if (from_ptr)
292 : : {
293 : 6 : return TypeCoercionRules::CoercionResult{
294 : 6 : {}, to.get_ty ()->clone ()};
295 : : }
296 : : }
297 : : break;
298 : :
299 : 3585 : case TyTy::TypeKind::REF:
300 : 3585 : case TyTy::TypeKind::POINTER:
301 : 3585 : return check_ptr_ptr_cast ();
302 : :
303 : 1 : default:
304 : 1 : return TypeCoercionRules::CoercionResult::get_error ();
305 : : }
306 : : break;
307 : :
308 : 7 : default:
309 : 7 : return TypeCoercionRules::CoercionResult::get_error ();
310 : : }
311 : :
312 : 8 : return TypeCoercionRules::CoercionResult::get_error ();
313 : : }
314 : :
315 : : TypeCoercionRules::CoercionResult
316 : 3585 : TypeCastRules::check_ptr_ptr_cast ()
317 : : {
318 : 3585 : 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 : 3585 : bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
323 : 3585 : bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
324 : 3585 : bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
325 : 3585 : bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
326 : :
327 : 3585 : if (from_is_ptr && to_is_ptr)
328 : : {
329 : : // mutability is ignored here as all pointer usage requires unsafe
330 : 1867 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
331 : : }
332 : 1718 : else if (from_is_ref && to_is_ref)
333 : : {
334 : 14 : const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
335 : 14 : const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
336 : :
337 : 14 : if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
338 : : {
339 : : // this needs to be handled by coercion logic
340 : 14 : return TypeCoercionRules::CoercionResult::get_error ();
341 : : }
342 : :
343 : : // are the underlying types safely simple castable?
344 : 7 : const auto to_underly = to_ref.get_base ();
345 : 7 : const auto from_underly = from_ref.get_base ();
346 : 7 : auto res = resolve (locus, TyTy::TyWithLocation (from_underly),
347 : 14 : TyTy::TyWithLocation (to_underly), false);
348 : 7 : if (res.is_error ())
349 : : {
350 : : // this needs to be handled by coercion logic
351 : 7 : return TypeCoercionRules::CoercionResult::get_error ();
352 : : }
353 : :
354 : : // mutability must be coerceable
355 : 0 : TyTy::ReferenceType &f
356 : 0 : = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
357 : 0 : TyTy::ReferenceType &t
358 : 0 : = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
359 : :
360 : 0 : if (TypeCoercionRules::coerceable_mutability (f.mutability (),
361 : : t.mutability ()))
362 : : {
363 : 0 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
364 : : }
365 : 7 : }
366 : :
367 : 1704 : return TypeCoercionRules::CoercionResult::get_error ();
368 : : }
369 : :
370 : : void
371 : 16 : TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
372 : : TyTy::TyWithLocation to)
373 : : {
374 : 16 : rich_location r (line_table, locus);
375 : 16 : r.add_range (from.get_locus ());
376 : 16 : r.add_range (to.get_locus ());
377 : 16 : ErrorCode error_code;
378 : 16 : std::string error_msg;
379 : 16 : switch (to.get_ty ()->get_kind ())
380 : : {
381 : 4 : case TyTy::TypeKind::BOOL:
382 : 4 : error_msg = "cannot cast %qs as %qs";
383 : 4 : error_code = ErrorCode::E0054;
384 : 4 : break;
385 : 7 : case TyTy::TypeKind::CHAR:
386 : 7 : error_msg
387 : 7 : += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
388 : 7 : error_code = ErrorCode::E0604;
389 : 7 : break;
390 : 1 : case TyTy::TypeKind::SLICE:
391 : 1 : error_msg = "cast to unsized type: %qs as %qs";
392 : 1 : error_code = ErrorCode::E0620;
393 : 1 : break;
394 : :
395 : 4 : default:
396 : 4 : error_msg = "casting %qs as %qs is invalid";
397 : 4 : error_code = ErrorCode::E0606;
398 : 4 : break;
399 : : }
400 : 16 : rust_error_at (r, error_code, error_msg.c_str (),
401 : 32 : from.get_ty ()->get_name ().c_str (),
402 : 32 : to.get_ty ()->get_name ().c_str ());
403 : 16 : }
404 : :
405 : : } // namespace Resolver
406 : : } // namespace Rust
|