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