]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-casts.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / typecheck / rust-casts.cc
CommitLineData
a945c346 1// Copyright (C) 2020-2024 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"
20
21namespace Rust {
22namespace Resolver {
23
24TypeCastRules::TypeCastRules (Location locus, TyTy::TyWithLocation from,
25 TyTy::TyWithLocation to)
26 : locus (locus), from (from), to (to)
27{}
28
29TypeCoercionRules::CoercionResult
30TypeCastRules::resolve (Location locus, TyTy::TyWithLocation from,
31 TyTy::TyWithLocation to)
32{
33 TypeCastRules cast_rules (locus, from, to);
34 return cast_rules.check ();
35}
36
37TypeCoercionRules::CoercionResult
38TypeCastRules::check ()
39{
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 if (!possible_coercion.is_error ())
44 return possible_coercion;
45
46 // try the simple cast rules
47 auto simple_cast = cast_rules ();
48 if (!simple_cast.is_error ())
49 return simple_cast;
50
51 // failed to cast
52 emit_cast_error ();
53 return TypeCoercionRules::CoercionResult::get_error ();
54}
55
56TypeCoercionRules::CoercionResult
57TypeCastRules::cast_rules ()
58{
59 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L596
60 // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L654
61
62 rust_debug ("cast_rules from={%s} to={%s}",
63 from.get_ty ()->debug_str ().c_str (),
64 to.get_ty ()->debug_str ().c_str ());
65
66 switch (from.get_ty ()->get_kind ())
67 {
68 case TyTy::TypeKind::INFER: {
69 TyTy::InferType *from_infer
70 = static_cast<TyTy::InferType *> (from.get_ty ());
71 switch (from_infer->get_infer_kind ())
72 {
73 case TyTy::InferType::InferTypeKind::GENERAL:
74 return TypeCoercionRules::CoercionResult{{},
75 to.get_ty ()->clone ()};
76
77 case TyTy::InferType::InferTypeKind::INTEGRAL:
78 switch (to.get_ty ()->get_kind ())
79 {
80 case TyTy::TypeKind::CHAR:
81 case TyTy::TypeKind::BOOL:
82 case TyTy::TypeKind::USIZE:
83 case TyTy::TypeKind::ISIZE:
84 case TyTy::TypeKind::UINT:
85 case TyTy::TypeKind::INT:
86 case TyTy::TypeKind::POINTER:
87 return TypeCoercionRules::CoercionResult{
88 {}, to.get_ty ()->clone ()};
89
90 case TyTy::TypeKind::INFER: {
91 TyTy::InferType *to_infer
92 = static_cast<TyTy::InferType *> (to.get_ty ());
93
94 switch (to_infer->get_infer_kind ())
95 {
96 case TyTy::InferType::InferTypeKind::GENERAL:
97 case TyTy::InferType::InferTypeKind::INTEGRAL:
98 return TypeCoercionRules::CoercionResult{
99 {}, to.get_ty ()->clone ()};
100
101 default:
102 return TypeCoercionRules::CoercionResult::get_error ();
103 }
104 }
105 break;
106
107 default:
108 return TypeCoercionRules::CoercionResult::get_error ();
109 }
110 break;
111
112 case TyTy::InferType::InferTypeKind::FLOAT:
113 switch (to.get_ty ()->get_kind ())
114 {
115 case TyTy::TypeKind::USIZE:
116 case TyTy::TypeKind::ISIZE:
117 case TyTy::TypeKind::UINT:
118 case TyTy::TypeKind::INT:
119 return TypeCoercionRules::CoercionResult{
120 {}, to.get_ty ()->clone ()};
121
122 case TyTy::TypeKind::INFER: {
123 TyTy::InferType *to_infer
124 = static_cast<TyTy::InferType *> (to.get_ty ());
125
126 switch (to_infer->get_infer_kind ())
127 {
128 case TyTy::InferType::InferTypeKind::GENERAL:
129 case TyTy::InferType::InferTypeKind::FLOAT:
130 return TypeCoercionRules::CoercionResult{
131 {}, to.get_ty ()->clone ()};
132
133 default:
134 return TypeCoercionRules::CoercionResult::get_error ();
135 }
136 }
137 break;
138
139 default:
140 return TypeCoercionRules::CoercionResult::get_error ();
141 }
142 break;
143 }
144 }
145 break;
146
147 case TyTy::TypeKind::BOOL:
148 switch (to.get_ty ()->get_kind ())
149 {
150 case TyTy::TypeKind::INFER:
151 case TyTy::TypeKind::USIZE:
152 case TyTy::TypeKind::ISIZE:
153 case TyTy::TypeKind::UINT:
154 case TyTy::TypeKind::INT:
155 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
156
157 default:
158 return TypeCoercionRules::CoercionResult::get_error ();
159 }
160 break;
161
162 case TyTy::TypeKind::CHAR:
163 case TyTy::TypeKind::USIZE:
164 case TyTy::TypeKind::ISIZE:
165 case TyTy::TypeKind::UINT:
166 case TyTy::TypeKind::INT:
167 switch (to.get_ty ()->get_kind ())
168 {
169 case TyTy::TypeKind::CHAR: {
170 // only u8 and char
171 bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
172 bool was_u8 = was_uint
173 && (static_cast<TyTy::UintType *> (from.get_ty ())
174 ->get_uint_kind ()
175 == TyTy::UintType::UintKind::U8);
176 if (was_u8)
177 return TypeCoercionRules::CoercionResult{{},
178 to.get_ty ()->clone ()};
179 }
180 break;
181
182 case TyTy::TypeKind::INFER:
183 case TyTy::TypeKind::USIZE:
184 case TyTy::TypeKind::ISIZE:
185 case TyTy::TypeKind::UINT:
186 case TyTy::TypeKind::INT:
187 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
188
189 default:
190 return TypeCoercionRules::CoercionResult::get_error ();
191 }
192 break;
193
194 case TyTy::TypeKind::FLOAT:
195 switch (to.get_ty ()->get_kind ())
196 {
197 case TyTy::TypeKind::FLOAT:
198 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
199
200 case TyTy::TypeKind::INFER: {
201 TyTy::InferType *to_infer
202 = static_cast<TyTy::InferType *> (to.get_ty ());
203
204 switch (to_infer->get_infer_kind ())
205 {
206 case TyTy::InferType::InferTypeKind::GENERAL:
207 case TyTy::InferType::InferTypeKind::FLOAT:
208 return TypeCoercionRules::CoercionResult{
209 {}, to.get_ty ()->clone ()};
210
211 default:
212 return TypeCoercionRules::CoercionResult::get_error ();
213 }
214 }
215 break;
216
217 default:
218 return TypeCoercionRules::CoercionResult::get_error ();
219 }
220 break;
221
222 case TyTy::TypeKind::REF:
223 case TyTy::TypeKind::POINTER:
224 switch (to.get_ty ()->get_kind ())
225 {
226 case TyTy::TypeKind::REF:
227 case TyTy::TypeKind::POINTER:
228 return check_ptr_ptr_cast ();
229
230 // FIXME can you cast a pointer to a integral type?
231
232 default:
233 return TypeCoercionRules::CoercionResult::get_error ();
234 }
235 break;
236
237 default:
238 return TypeCoercionRules::CoercionResult::get_error ();
239 }
240
241 return TypeCoercionRules::CoercionResult::get_error ();
242}
243
244TypeCoercionRules::CoercionResult
245TypeCastRules::check_ptr_ptr_cast ()
246{
247 rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
248 from.get_ty ()->debug_str ().c_str (),
249 to.get_ty ()->debug_str ().c_str ());
250
251 bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
252 bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
253 bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
254 bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
255
256 if (from_is_ptr && to_is_ptr)
257 {
258 // mutability is ignored here as all pointer usage requires unsafe
259 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
260 }
261 else if (from_is_ref && to_is_ref)
262 {
263 // mutability must be coercedable
264 TyTy::ReferenceType &f
265 = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
266 TyTy::ReferenceType &t
267 = static_cast<TyTy::ReferenceType &> (*to.get_ty ());
268
269 if (TypeCoercionRules::coerceable_mutability (f.mutability (),
270 t.mutability ()))
271 {
272 return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
273 }
274 }
275
276 return TypeCoercionRules::CoercionResult::get_error ();
277}
278
279void
280TypeCastRules::emit_cast_error () const
281{
282 // error[E0604]
283 RichLocation r (locus);
284 r.add_range (from.get_locus ());
285 r.add_range (to.get_locus ());
1aee5d2a 286 rust_error_at (r, ErrorCode ("E0054"), "invalid cast %<%s%> to %<%s%>",
06688fe4
PH
287 from.get_ty ()->get_name ().c_str (),
288 to.get_ty ()->get_name ().c_str ());
289}
290
291} // namespace Resolver
292} // namespace Rust