Daily bump.
[official-gcc.git] / gcc / rust / typecheck / rust-casts.cc
blob5235069fa231115bb551cb5a4467c44d25df4835
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
19 #include "rust-casts.h"
21 namespace Rust {
22 namespace Resolver {
24 TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
25 TyTy::TyWithLocation to)
26 : locus (locus), from (from), to (to)
29 TypeCoercionRules::CoercionResult
30 TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
31 TyTy::TyWithLocation to)
33 TypeCastRules cast_rules (locus, from, to);
34 return cast_rules.check ();
37 TypeCoercionRules::CoercionResult
38 TypeCastRules::check ()
40 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
41 auto possible_coercion
42 = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
43 true /*allow-autoderef*/,
44 true /*is_cast_site*/);
45 if (!possible_coercion.is_error ())
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,
50 true /*allow-autoderef*/,
51 true /*is_cast_site*/);
54 // try the simple cast rules
55 auto simple_cast = cast_rules ();
56 if (!simple_cast.is_error ())
57 return simple_cast;
59 // failed to cast
60 emit_cast_error ();
61 return TypeCoercionRules::CoercionResult::get_error ();
64 TypeCoercionRules::CoercionResult
65 TypeCastRules::cast_rules ()
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
70 TyTy::BaseType *from_type = from.get_ty ()->destructure ();
72 rust_debug ("cast_rules from={%s} to={%s}", from_type->debug_str ().c_str (),
73 to.get_ty ()->debug_str ().c_str ());
74 switch (from_type->get_kind ())
76 case TyTy::TypeKind::INFER: {
77 TyTy::InferType *from_infer
78 = static_cast<TyTy::InferType *> (from_type);
79 switch (from_infer->get_infer_kind ())
81 case TyTy::InferType::InferTypeKind::GENERAL:
82 return TypeCoercionRules::CoercionResult{{},
83 to.get_ty ()->clone ()};
85 case TyTy::InferType::InferTypeKind::INTEGRAL:
86 switch (to.get_ty ()->get_kind ())
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 ()};
101 break;
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 ()};
111 case TyTy::TypeKind::INFER: {
112 TyTy::InferType *to_infer
113 = static_cast<TyTy::InferType *> (to.get_ty ());
115 switch (to_infer->get_infer_kind ())
117 case TyTy::InferType::InferTypeKind::GENERAL:
118 case TyTy::InferType::InferTypeKind::INTEGRAL:
119 return TypeCoercionRules::CoercionResult{
120 {}, to.get_ty ()->clone ()};
122 default:
123 return TypeCoercionRules::CoercionResult::get_error ();
126 break;
128 default:
129 return TypeCoercionRules::CoercionResult::get_error ();
131 break;
133 case TyTy::InferType::InferTypeKind::FLOAT:
134 switch (to.get_ty ()->get_kind ())
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 ()};
143 case TyTy::TypeKind::INFER: {
144 TyTy::InferType *to_infer
145 = static_cast<TyTy::InferType *> (to.get_ty ());
147 switch (to_infer->get_infer_kind ())
149 case TyTy::InferType::InferTypeKind::GENERAL:
150 case TyTy::InferType::InferTypeKind::FLOAT:
151 return TypeCoercionRules::CoercionResult{
152 {}, to.get_ty ()->clone ()};
154 default:
155 return TypeCoercionRules::CoercionResult::get_error ();
158 break;
160 default:
161 return TypeCoercionRules::CoercionResult::get_error ();
163 break;
166 break;
168 case TyTy::TypeKind::BOOL:
169 switch (to.get_ty ()->get_kind ())
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 ()};
178 default:
179 return TypeCoercionRules::CoercionResult::get_error ();
181 break;
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 ())
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 ()};
201 break;
203 case TyTy::TypeKind::INFER:
204 case TyTy::TypeKind::USIZE:
205 case TyTy::TypeKind::ISIZE:
206 case TyTy::TypeKind::UINT:
207 case TyTy::TypeKind::INT:
208 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
210 default:
211 return TypeCoercionRules::CoercionResult::get_error ();
213 break;
215 case TyTy::TypeKind::FLOAT:
216 switch (to.get_ty ()->get_kind ())
218 case TyTy::TypeKind::FLOAT:
219 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
221 case TyTy::TypeKind::INFER: {
222 TyTy::InferType *to_infer
223 = static_cast<TyTy::InferType *> (to.get_ty ());
225 switch (to_infer->get_infer_kind ())
227 case TyTy::InferType::InferTypeKind::GENERAL:
228 case TyTy::InferType::InferTypeKind::FLOAT:
229 return TypeCoercionRules::CoercionResult{
230 {}, to.get_ty ()->clone ()};
232 default:
233 return TypeCoercionRules::CoercionResult::get_error ();
236 break;
238 default:
239 return TypeCoercionRules::CoercionResult::get_error ();
241 break;
243 case TyTy::TypeKind::REF:
244 case TyTy::TypeKind::POINTER:
245 switch (to.get_ty ()->get_kind ())
247 case TyTy::TypeKind::REF:
248 case TyTy::TypeKind::POINTER:
249 return check_ptr_ptr_cast ();
251 // FIXME can you cast a pointer to a integral type?
253 default:
254 return TypeCoercionRules::CoercionResult::get_error ();
256 break;
258 default:
259 return TypeCoercionRules::CoercionResult::get_error ();
262 return TypeCoercionRules::CoercionResult::get_error ();
265 TypeCoercionRules::CoercionResult
266 TypeCastRules::check_ptr_ptr_cast ()
268 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 ());
272 bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
273 bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
274 bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
275 bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
277 if (from_is_ptr && to_is_ptr)
279 // mutability is ignored here as all pointer usage requires unsafe
280 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
282 else if (from_is_ref && to_is_ref)
284 // mutability must be coercedable
285 TyTy::ReferenceType &f
286 = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
287 TyTy::ReferenceType &t
288 = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
290 if (TypeCoercionRules::coerceable_mutability (f.mutability (),
291 t.mutability ()))
293 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
297 return TypeCoercionRules::CoercionResult::get_error ();
300 void
301 TypeCastRules::emit_cast_error () const
303 rich_location r (line_table, locus);
304 r.add_range (from.get_locus ());
305 r.add_range (to.get_locus ());
306 ErrorCode error_code;
307 std::string error_msg;
308 switch (to.get_ty ()->get_kind ())
310 case TyTy::TypeKind::BOOL:
311 error_msg = "cannot cast %qs as %qs";
312 error_code = ErrorCode::E0054;
313 break;
314 case TyTy::TypeKind::CHAR:
315 error_msg
316 += "cannot cast %qs as %qs, only %<u8%> can be cast as %<char%>";
317 error_code = ErrorCode::E0604;
318 break;
319 case TyTy::TypeKind::SLICE:
320 error_msg = "cast to unsized type: %qs as %qs";
321 error_code = ErrorCode::E0620;
322 break;
324 default:
325 error_msg = "casting %qs as %qs is invalid";
326 error_code = ErrorCode::E0606;
327 break;
329 rust_error_at (r, error_code, error_msg.c_str (),
330 from.get_ty ()->get_name ().c_str (),
331 to.get_ty ()->get_name ().c_str ());
334 } // namespace Resolver
335 } // namespace Rust