]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/typecheck/rust-casts.cc
1 // Copyright (C) 2020-2024 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
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
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"
24 TypeCastRules::TypeCastRules (Location locus
, TyTy::TyWithLocation from
,
25 TyTy::TyWithLocation to
)
26 : locus (locus
), from (from
), to (to
)
29 TypeCoercionRules::CoercionResult
30 TypeCastRules::resolve (Location 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 if (!possible_coercion
.is_error ())
44 return possible_coercion
;
46 // try the simple cast rules
47 auto simple_cast
= cast_rules ();
48 if (!simple_cast
.is_error ())
53 return TypeCoercionRules::CoercionResult::get_error ();
56 TypeCoercionRules::CoercionResult
57 TypeCastRules::cast_rules ()
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
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 ());
66 switch (from
.get_ty ()->get_kind ())
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 ())
73 case TyTy::InferType::InferTypeKind::GENERAL
:
74 return TypeCoercionRules::CoercionResult
{{},
75 to
.get_ty ()->clone ()};
77 case TyTy::InferType::InferTypeKind::INTEGRAL
:
78 switch (to
.get_ty ()->get_kind ())
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 ()};
90 case TyTy::TypeKind::INFER
: {
91 TyTy::InferType
*to_infer
92 = static_cast<TyTy::InferType
*> (to
.get_ty ());
94 switch (to_infer
->get_infer_kind ())
96 case TyTy::InferType::InferTypeKind::GENERAL
:
97 case TyTy::InferType::InferTypeKind::INTEGRAL
:
98 return TypeCoercionRules::CoercionResult
{
99 {}, to
.get_ty ()->clone ()};
102 return TypeCoercionRules::CoercionResult::get_error ();
108 return TypeCoercionRules::CoercionResult::get_error ();
112 case TyTy::InferType::InferTypeKind::FLOAT
:
113 switch (to
.get_ty ()->get_kind ())
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 ()};
122 case TyTy::TypeKind::INFER
: {
123 TyTy::InferType
*to_infer
124 = static_cast<TyTy::InferType
*> (to
.get_ty ());
126 switch (to_infer
->get_infer_kind ())
128 case TyTy::InferType::InferTypeKind::GENERAL
:
129 case TyTy::InferType::InferTypeKind::FLOAT
:
130 return TypeCoercionRules::CoercionResult
{
131 {}, to
.get_ty ()->clone ()};
134 return TypeCoercionRules::CoercionResult::get_error ();
140 return TypeCoercionRules::CoercionResult::get_error ();
147 case TyTy::TypeKind::BOOL
:
148 switch (to
.get_ty ()->get_kind ())
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 ()};
158 return TypeCoercionRules::CoercionResult::get_error ();
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 ())
169 case TyTy::TypeKind::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 ())
175 == TyTy::UintType::UintKind::U8
);
177 return TypeCoercionRules::CoercionResult
{{},
178 to
.get_ty ()->clone ()};
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 ()};
190 return TypeCoercionRules::CoercionResult::get_error ();
194 case TyTy::TypeKind::FLOAT
:
195 switch (to
.get_ty ()->get_kind ())
197 case TyTy::TypeKind::FLOAT
:
198 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
200 case TyTy::TypeKind::INFER
: {
201 TyTy::InferType
*to_infer
202 = static_cast<TyTy::InferType
*> (to
.get_ty ());
204 switch (to_infer
->get_infer_kind ())
206 case TyTy::InferType::InferTypeKind::GENERAL
:
207 case TyTy::InferType::InferTypeKind::FLOAT
:
208 return TypeCoercionRules::CoercionResult
{
209 {}, to
.get_ty ()->clone ()};
212 return TypeCoercionRules::CoercionResult::get_error ();
218 return TypeCoercionRules::CoercionResult::get_error ();
222 case TyTy::TypeKind::REF
:
223 case TyTy::TypeKind::POINTER
:
224 switch (to
.get_ty ()->get_kind ())
226 case TyTy::TypeKind::REF
:
227 case TyTy::TypeKind::POINTER
:
228 return check_ptr_ptr_cast ();
230 // FIXME can you cast a pointer to a integral type?
233 return TypeCoercionRules::CoercionResult::get_error ();
238 return TypeCoercionRules::CoercionResult::get_error ();
241 return TypeCoercionRules::CoercionResult::get_error ();
244 TypeCoercionRules::CoercionResult
245 TypeCastRules::check_ptr_ptr_cast ()
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 ());
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
;
256 if (from_is_ptr
&& to_is_ptr
)
258 // mutability is ignored here as all pointer usage requires unsafe
259 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
261 else if (from_is_ref
&& to_is_ref
)
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 ());
269 if (TypeCoercionRules::coerceable_mutability (f
.mutability (),
272 return TypeCoercionRules::CoercionResult
{{}, to
.get_ty ()->clone ()};
276 return TypeCoercionRules::CoercionResult::get_error ();
280 TypeCastRules::emit_cast_error () const
283 RichLocation
r (locus
);
284 r
.add_range (from
.get_locus ());
285 r
.add_range (to
.get_locus ());
286 rust_error_at (r
, ErrorCode ("E0054"), "invalid cast %<%s%> to %<%s%>",
287 from
.get_ty ()->get_name ().c_str (),
288 to
.get_ty ()->get_name ().c_str ());
291 } // namespace Resolver