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 : 3313 : TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
25 : 3313 : TyTy::TyWithLocation to)
26 : 3313 : : locus (locus), from (from), to (to)
27 : 3313 : {}
28 : :
29 : : TypeCoercionRules::CoercionResult
30 : 3313 : TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
31 : : TyTy::TyWithLocation to)
32 : : {
33 : 3313 : TypeCastRules cast_rules (locus, from, to);
34 : 3313 : return cast_rules.check ();
35 : : }
36 : :
37 : : TypeCoercionRules::CoercionResult
38 : 3313 : TypeCastRules::check ()
39 : : {
40 : : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
41 : 3313 : auto possible_coercion
42 : : = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
43 : : true /*allow-autoderef*/,
44 : 3313 : true /*is_cast_site*/);
45 : 3313 : 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 : 1577 : return TypeCoercionRules::Coerce (from.get_ty (), to.get_ty (), locus,
50 : : true /*allow-autoderef*/,
51 : 1577 : true /*is_cast_site*/);
52 : : }
53 : :
54 : : // try the simple cast rules
55 : 1736 : auto simple_cast = cast_rules ();
56 : 1736 : if (!simple_cast.is_error ())
57 : 1720 : return simple_cast;
58 : :
59 : : // failed to cast
60 : 16 : emit_cast_error ();
61 : 16 : return TypeCoercionRules::CoercionResult::get_error ();
62 : 1736 : }
63 : :
64 : : TypeCoercionRules::CoercionResult
65 : 1736 : 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 : 1736 : TyTy::BaseType *from_type = from.get_ty ()->destructure ();
71 : :
72 : 1736 : rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
73 : : to.get_ty ()->debug_str ().c_str ());
74 : 1736 : switch (from_type->get_kind ())
75 : : {
76 : 4 : case TyTy::TypeKind::INFER: {
77 : 4 : TyTy::InferType *from_infer
78 : : = static_cast<TyTy::InferType *> (from_type);
79 : 4 : 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 : 4 : case TyTy::InferType::InferTypeKind::INTEGRAL:
86 : 4 : switch (to.get_ty ()->get_kind ())
87 : : {
88 : 2 : case TyTy::TypeKind::CHAR: {
89 : : // only u8 and char
90 : 2 : bool was_uint
91 : 2 : = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
92 : 2 : bool was_u8
93 : : = was_uint
94 : 2 : && (static_cast<TyTy::UintType *> (from.get_ty ())
95 : 0 : ->get_uint_kind ()
96 : 6 : == 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 : 1 : case TyTy::TypeKind::USIZE:
104 : 1 : case TyTy::TypeKind::ISIZE:
105 : 1 : case TyTy::TypeKind::UINT:
106 : 1 : case TyTy::TypeKind::INT:
107 : 1 : case TyTy::TypeKind::POINTER:
108 : 1 : return TypeCoercionRules::CoercionResult{
109 : 1 : {}, 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 : 1 : break;
127 : :
128 : 1 : default:
129 : 1 : 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 : 52 : case TyTy::TypeKind::BOOL:
169 : 52 : switch (to.get_ty ()->get_kind ())
170 : : {
171 : 49 : case TyTy::TypeKind::INFER:
172 : 49 : case TyTy::TypeKind::USIZE:
173 : 49 : case TyTy::TypeKind::ISIZE:
174 : 49 : case TyTy::TypeKind::UINT:
175 : 49 : case TyTy::TypeKind::INT:
176 : 49 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
177 : :
178 : 3 : default:
179 : 3 : return TypeCoercionRules::CoercionResult::get_error ();
180 : : }
181 : 350 : break;
182 : :
183 : 350 : case TyTy::TypeKind::CHAR:
184 : 350 : case TyTy::TypeKind::USIZE:
185 : 350 : case TyTy::TypeKind::ISIZE:
186 : 350 : case TyTy::TypeKind::UINT:
187 : 350 : case TyTy::TypeKind::INT:
188 : 350 : switch (to.get_ty ()->get_kind ())
189 : : {
190 : 19 : case TyTy::TypeKind::CHAR: {
191 : : // only u8 and char
192 : 19 : bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
193 : 19 : bool was_u8 = was_uint
194 : 19 : && (static_cast<TyTy::UintType *> (from.get_ty ())
195 : 17 : ->get_uint_kind ()
196 : 21 : == TyTy::UintType::UintKind::U8);
197 : 15 : if (was_u8)
198 : 15 : return TypeCoercionRules::CoercionResult{{},
199 : 15 : to.get_ty ()->clone ()};
200 : : }
201 : : break;
202 : :
203 : 327 : case TyTy::TypeKind::INFER:
204 : 327 : case TyTy::TypeKind::USIZE:
205 : 327 : case TyTy::TypeKind::ISIZE:
206 : 327 : case TyTy::TypeKind::UINT:
207 : 327 : case TyTy::TypeKind::INT:
208 : 327 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
209 : :
210 : 4 : default:
211 : 4 : return TypeCoercionRules::CoercionResult::get_error ();
212 : : }
213 : : break;
214 : :
215 : 0 : case TyTy::TypeKind::FLOAT:
216 : 0 : switch (to.get_ty ()->get_kind ())
217 : : {
218 : 0 : case TyTy::TypeKind::FLOAT:
219 : 0 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
220 : :
221 : 0 : case TyTy::TypeKind::INFER: {
222 : 0 : TyTy::InferType *to_infer
223 : 0 : = static_cast<TyTy::InferType *> (to.get_ty ());
224 : :
225 : 0 : switch (to_infer->get_infer_kind ())
226 : : {
227 : 0 : case TyTy::InferType::InferTypeKind::GENERAL:
228 : 0 : case TyTy::InferType::InferTypeKind::FLOAT:
229 : 0 : return TypeCoercionRules::CoercionResult{
230 : 0 : {}, to.get_ty ()->clone ()};
231 : :
232 : 0 : default:
233 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
234 : : }
235 : : }
236 : 0 : break;
237 : :
238 : 0 : default:
239 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
240 : : }
241 : 1330 : break;
242 : :
243 : 1330 : case TyTy::TypeKind::REF:
244 : 1330 : case TyTy::TypeKind::POINTER:
245 : 1330 : switch (to.get_ty ()->get_kind ())
246 : : {
247 : 1328 : case TyTy::TypeKind::REF:
248 : 1328 : case TyTy::TypeKind::POINTER:
249 : 1328 : return check_ptr_ptr_cast ();
250 : :
251 : : // FIXME can you cast a pointer to a integral type?
252 : :
253 : 2 : default:
254 : 2 : return TypeCoercionRules::CoercionResult::get_error ();
255 : : }
256 : 0 : break;
257 : :
258 : 0 : default:
259 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
260 : : }
261 : :
262 : 6 : return TypeCoercionRules::CoercionResult::get_error ();
263 : : }
264 : :
265 : : TypeCoercionRules::CoercionResult
266 : 1328 : TypeCastRules::check_ptr_ptr_cast ()
267 : : {
268 : 1328 : rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
269 : : from.get_ty ()->debug_str ().c_str (),
270 : : to.get_ty ()->debug_str ().c_str ());
271 : :
272 : 1328 : bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
273 : 1328 : bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
274 : 1328 : bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
275 : 1328 : bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
276 : :
277 : 1328 : if (from_is_ptr && to_is_ptr)
278 : : {
279 : : // mutability is ignored here as all pointer usage requires unsafe
280 : 1328 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
281 : : }
282 : 0 : else if (from_is_ref && to_is_ref)
283 : : {
284 : : // mutability must be coercedable
285 : 0 : TyTy::ReferenceType &f
286 : 0 : = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
287 : 0 : TyTy::ReferenceType &t
288 : 0 : = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
289 : :
290 : 0 : if (TypeCoercionRules::coerceable_mutability (f.mutability (),
291 : : t.mutability ()))
292 : : {
293 : 0 : return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
294 : : }
295 : : }
296 : :
297 : 0 : return TypeCoercionRules::CoercionResult::get_error ();
298 : : }
299 : :
300 : : void
301 : 16 : TypeCastRules::emit_cast_error () const
302 : : {
303 : 16 : rich_location r (line_table, locus);
304 : 16 : r.add_range (from.get_locus ());
305 : 16 : r.add_range (to.get_locus ());
306 : 16 : ErrorCode error_code;
307 : 16 : std::string error_msg;
308 : 16 : switch (to.get_ty ()->get_kind ())
309 : : {
310 : 4 : case TyTy::TypeKind::BOOL:
311 : 4 : error_msg = "cannot cast %qs as %qs";
312 : 4 : error_code = ErrorCode::E0054;
313 : 4 : break;
314 : 7 : case TyTy::TypeKind::CHAR:
315 : 7 : error_msg
316 : 7 : += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
317 : 7 : error_code = ErrorCode::E0604;
318 : 7 : break;
319 : 1 : case TyTy::TypeKind::SLICE:
320 : 1 : error_msg = "cast to unsized type: %qs as %qs";
321 : 1 : error_code = ErrorCode::E0620;
322 : 1 : break;
323 : :
324 : 4 : default:
325 : 4 : error_msg = "casting %qs as %qs is invalid";
326 : 4 : error_code = ErrorCode::E0606;
327 : 4 : break;
328 : : }
329 : 16 : rust_error_at (r, error_code, error_msg.c_str (),
330 : 32 : from.get_ty ()->get_name ().c_str (),
331 : 32 : to.get_ty ()->get_name ().c_str ());
332 : 16 : }
333 : :
334 : : } // namespace Resolver
335 : : } // namespace Rust
|