Line data Source code
1 : // Copyright (C) 2026 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-hir-type-check-intrinsic.h"
20 : #include "rust-diagnostics.h"
21 : #include "rust-intrinsic-values.h"
22 : #include "rust-system.h"
23 : #include "rust-tyty.h"
24 :
25 : namespace Rust {
26 : namespace Resolver {
27 :
28 : using IValue = Values::Intrinsics;
29 : using IRT = IntrinsicRuleType;
30 :
31 : const std::unordered_map<std::string, IntrinsicRules>
32 : IntrinsicChecker::intrinsic_rules = {
33 : // fn unreachable() -> !;
34 : {IValue::UNREACHABLE, {0, {}, IRT::Never}},
35 :
36 : // pub fn sqrtf32(x: f32) -> f32;
37 : {IValue::SQRTF32, {0, {IRT::F32}, IRT::F32}},
38 : // pub fn sqrtf64(x: f64) -> f64;
39 : {IValue::SQRTF64, {0, {IRT::F64}, IRT::F64}},
40 : // pub fn sinf32(x: f32) -> f32;
41 : {IValue::SINF32, {0, {IRT::F32}, IRT::F32}},
42 : // pub fn sinf64(x: f64) -> f64;
43 : {IValue::SINF64, {0, {IRT::F64}, IRT::F64}},
44 : // pub fn cosf32(x: f32) -> f32;
45 : {IValue::COSF32, {0, {IRT::F32}, IRT::F32}},
46 : // pub fn cosf64(x: f64) -> f64;
47 : {IValue::COSF64, {0, {IRT::F64}, IRT::F64}},
48 : // pub fn expf32(x: f32) -> f32;
49 : {IValue::EXPF32, {0, {IRT::F32}, IRT::F32}},
50 : // pub fn expf64(x: f64) -> f64;
51 : {IValue::EXPF64, {0, {IRT::F64}, IRT::F64}},
52 : // pub fn exp2f32(x: f32) -> f32;
53 : {IValue::EXP2F32, {0, {IRT::F32}, IRT::F32}},
54 : // pub fn exp2f64(x: f64) -> f64;
55 : {IValue::EXP2F64, {0, {IRT::F64}, IRT::F64}},
56 : // pub fn logf32(x: f32) -> f32;
57 : {IValue::LOGF32, {0, {IRT::F32}, IRT::F32}},
58 : // pub fn logf64(x: f64) -> f64;
59 : {IValue::LOGF64, {0, {IRT::F64}, IRT::F64}},
60 : // pub fn log10f32(x: f32) -> f32;
61 : {IValue::LOG10F32, {0, {IRT::F32}, IRT::F32}},
62 : // pub fn log10f64(x: f64) -> f64;
63 : {IValue::LOG10F64, {0, {IRT::F64}, IRT::F64}},
64 : // pub fn log2f32(x: f32) -> f32;
65 : {IValue::LOG2F32, {0, {IRT::F32}, IRT::F32}},
66 : // pub fn log2f64(x: f64) -> f64;
67 : {IValue::LOG2F64, {0, {IRT::F64}, IRT::F64}},
68 : // pub fn fabsf32(x: f32) -> f32;
69 : {IValue::FABSF32, {0, {IRT::F32}, IRT::F32}},
70 : // pub fn fabsf64(x: f64) -> f64;
71 : {IValue::FABSF64, {0, {IRT::F64}, IRT::F64}},
72 : // pub fn floorf32(x: f32) -> f32;
73 : {IValue::FLOORF32, {0, {IRT::F32}, IRT::F32}},
74 : // pub fn floorf64(x: f64) -> f64;
75 : {IValue::FLOORF64, {0, {IRT::F64}, IRT::F64}},
76 : // pub fn ceilf32(x: f32) -> f32;
77 : {IValue::CEILF32, {0, {IRT::F32}, IRT::F32}},
78 : // pub fn ceilf64(x: f64) -> f64;
79 : {IValue::CEILF64, {0, {IRT::F64}, IRT::F64}},
80 : // pub fn truncf32(x: f32) -> f32;
81 : {IValue::TRUNCF32, {0, {IRT::F32}, IRT::F32}},
82 : // pub fn truncf64(x: f64) -> f64;
83 : {IValue::TRUNCF64, {0, {IRT::F64}, IRT::F64}},
84 : // pub fn rintf32(x: f32) -> f32;
85 : {IValue::RINTF32, {0, {IRT::F32}, IRT::F32}},
86 : // pub fn rintf64(x: f64) -> f64;
87 : {IValue::RINTF64, {0, {IRT::F64}, IRT::F64}},
88 : // pub fn nearbyintf32(x: f32) -> f32;
89 : {IValue::NEARBYINTF32, {0, {IRT::F32}, IRT::F32}},
90 : // pub fn nearbyintf64(x: f64) -> f64;
91 : {IValue::NEARBYINTF64, {0, {IRT::F64}, IRT::F64}},
92 : // pub fn roundf32(x: f32) -> f32;
93 : {IValue::ROUNDF32, {0, {IRT::F32}, IRT::F32}},
94 : // pub fn roundf64(x: f64) -> f64;
95 : {IValue::ROUNDF64, {0, {IRT::F64}, IRT::F64}},
96 : // pub fn minnumf32(x: f32, y: f32) -> f32;
97 : {IValue::MINNUMF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
98 : // pub fn minnumf64(x: f64, y: f64) -> f64;
99 : {IValue::MINNUMF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
100 : // pub fn maxnumf32(x: f32, y: f32) -> f32;
101 : {IValue::MAXNUMF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
102 : // pub fn maxnumf64(x: f64, y: f64) -> f64;
103 : {IValue::MAXNUMF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
104 :
105 : // pub fn powf32(a: f32, x: f32) -> f32;
106 : {IValue::POWF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
107 : // pub fn powf64(a: f64, x: f64) -> f64;
108 : {IValue::POWF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
109 : // pub fn copysignf32(x: f32, y: f32) -> f32;
110 : {IValue::COPYSIGNF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
111 : // pub fn copysignf64(x: f64, y: f64) -> f64;
112 : {IValue::COPYSIGNF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
113 :
114 : // pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
115 : {IValue::FMAF32, {0, {IRT::F32, IRT::F32, IRT::F32}, IRT::F32}},
116 : // pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
117 : {IValue::FMAF64, {0, {IRT::F64, IRT::F64, IRT::F64}, IRT::F64}},
118 :
119 : // pub fn powif32(a: f32, x: i32) -> f32;
120 : {IValue::POWIF32, {0, {IRT::F32, IRT::I32}, IRT::F32}},
121 : // pub fn powif64(a: f64, x: i32) -> f64;
122 : {IValue::POWIF64, {0, {IRT::F64, IRT::I32}, IRT::F64}},
123 :
124 : // pub fn abort() -> !;
125 : {IValue::ABORT, {0, {}, IRT::Never}},
126 : // pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
127 : {IValue::OFFSET,
128 : {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
129 : // pub fn size_of<T>() -> usize;
130 : {IValue::SIZE_OF, {1, {}, IRT::Usize}},
131 : // pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
132 : {IValue::SIZE_OF_VAL, {1, {IRT::ConstPtrFirstGeneric}, IRT::Usize}},
133 : // pub fn transmute<T, U>(e: T) -> U;
134 : {IValue::TRANSMUTE, {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
135 : // pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
136 : {IValue::ADD_WITH_OVERFLOW,
137 : {1,
138 : {IRT::FirstGeneric, IRT::FirstGeneric},
139 : IRT::TupleFirstGenericAndBool}},
140 : // pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
141 : {IValue::SUB_WITH_OVERFLOW,
142 : {1,
143 : {IRT::FirstGeneric, IRT::FirstGeneric},
144 : IRT::TupleFirstGenericAndBool}},
145 : // pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
146 : {IValue::MUL_WITH_OVERFLOW,
147 : {1,
148 : {IRT::FirstGeneric, IRT::FirstGeneric},
149 : IRT::TupleFirstGenericAndBool}},
150 : // fn copy<T>(src: *const T, dst: *mut T, count: usize);
151 : {IValue::COPY,
152 : {1,
153 : {IRT::ConstPtrFirstGeneric, IRT::MutPtrFirstGeneric, IRT::Usize},
154 : IRT::Unit}},
155 : // fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
156 : {IValue::COPY_NONOVERLAPPING,
157 : {1,
158 : {IRT::ConstPtrFirstGeneric, IRT::MutPtrFirstGeneric, IRT::Usize},
159 : IRT::Unit}},
160 : // pub fn prefetch_read_data<T>(data: *const T, locality: i32);
161 : {IValue::PREFETCH_READ_DATA,
162 : {1, {IRT::ConstPtrFirstGeneric, IRT::I32}, IRT::Unit}},
163 : // pub fn prefetch_write_data<T>(data: *const T, locality: i32);
164 : {IValue::PREFETCH_WRITE_DATA,
165 : {1, {IRT::ConstPtrFirstGeneric, IRT::I32}, IRT::Unit}},
166 : // pub unsafe fn atomic_store_seqcst<T: Copy>(_dst: *mut T, _val: T);
167 : {IValue::ATOMIC_STORE_SEQCST,
168 : {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
169 : // pub unsafe fn atomic_store_release<T: Copy>(_dst: *mut T, _val: T);
170 : {IValue::ATOMIC_STORE_RELEASE,
171 : {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
172 : // pub unsafe fn atomic_store_relaxed<T: Copy>(_dst: *mut T, _val: T);
173 : {IValue::ATOMIC_STORE_RELAXED,
174 : {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
175 : // pub unsafe fn atomic_store_unordered<T: Copy>(_dst: *mut T, _val: T);
176 : {IValue::ATOMIC_STORE_UNORDERED,
177 : {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
178 : // pub unsafe fn atomic_load_seqcst<T: Copy>(_src: *const T) -> T;
179 : {IValue::ATOMIC_LOAD_SEQCST,
180 : {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
181 : // pub unsafe fn atomic_load_acquire<T: Copy>(_src: *const T) -> T;
182 : {IValue::ATOMIC_LOAD_ACQUIRE,
183 : {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
184 : // pub unsafe fn atomic_load_relaxed<T: Copy>(_src: *const T) -> T;
185 : {IValue::ATOMIC_LOAD_RELAXED,
186 : {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
187 : // pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T;
188 : {IValue::ATOMIC_LOAD_UNORDERED,
189 : {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
190 : // pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
191 : {IValue::UNCHECKED_ADD,
192 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
193 : // pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
194 : {IValue::UNCHECKED_SUB,
195 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
196 : // pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
197 : {IValue::UNCHECKED_MUL,
198 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
199 : // pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
200 : {IValue::UNCHECKED_DIV,
201 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
202 : // pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T;
203 : {IValue::UNCHECKED_REM,
204 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
205 : // pub fn unchecked_shl<T: Copy>(x: T, y: T) -> T;
206 : {IValue::UNCHECKED_SHL,
207 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
208 : // pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
209 : {IValue::UNCHECKED_SHR,
210 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
211 : // pub unsafe fn uninit<T>() -> T
212 : {IValue::UNINIT, {1, {}, IRT::FirstGeneric}},
213 : // pub fn move_val_init<T>(dst: *mut T, src: T);
214 : {IValue::MOVE_VAL_INIT,
215 : {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
216 : // pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
217 : {IValue::ROTATE_LEFT,
218 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
219 : // pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
220 : {IValue::ROTATE_RIGHT,
221 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
222 : // pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
223 : {IValue::WRAPPING_ADD,
224 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
225 : // pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
226 : {IValue::WRAPPING_SUB,
227 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
228 : // pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
229 : {IValue::WRAPPING_MUL,
230 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
231 : // pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
232 : {IValue::SATURATING_ADD,
233 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
234 : // pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
235 : {IValue::SATURATING_SUB,
236 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
237 : // pub fn likely(b: bool) -> bool;
238 : {IValue::LIKELY, {0, {IRT::Bool}, IRT::Bool}},
239 : // pub fn unlikely(b: bool) -> bool;
240 : {IValue::UNLIKELY, {0, {IRT::Bool}, IRT::Bool}},
241 : // fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
242 : {IValue::DISCRIMINANT_VALUE,
243 : {1, {IRT::RefFirstGeneric}, IRT::AssocTypePlaceholder}},
244 : // pub fn variant_count<T>() -> usize;
245 : {IValue::VARIANT_COUNT, {1, {}, IRT::Usize}},
246 : // NOTE: The return value was temporarily set to () instead of i32.
247 : // pub unsafe fn catch_unwind(
248 : // _try_fn: fn(_: *mut u8),
249 : // _data: *mut u8,
250 : // _catch_fn: fn(_: *mut u8, _: *mut u8),
251 : // ) -> i32
252 : {IValue::CATCH_UNWIND,
253 : {0,
254 : {IRT::Fn_MutPtrU8, IRT::MutPtrU8, IRT::Fn_MutPtrU8MutPtrU8},
255 : IRT::Unit}},
256 : // pub fn r#try(
257 : // try_fn: fn(*mut u8),
258 : // data: *mut u8,
259 : // catch_fn: fn(*mut u8,
260 : // *mut u8)
261 : // ) -> i32;
262 : {IValue::TRY,
263 : {0,
264 : {IRT::Fn_MutPtrU8, IRT::MutPtrU8, IRT::Fn_MutPtrU8MutPtrU8},
265 : IRT::I32}},
266 : // pub fn assume(b: bool);
267 : {IValue::ASSUME, {0, {IRT::Bool}, IRT::Unit}},
268 : // pub fn min_align_of<T>() -> usize;
269 : {IValue::MIN_ALIGN_OF, {1, {}, IRT::Usize}},
270 : // pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
271 : {IValue::MIN_ALIGN_OF_VAL, {1, {IRT::ConstPtrFirstGeneric}, IRT::Usize}},
272 : // pub fn needs_drop<T>() -> bool;
273 : {IValue::NEEDS_DROP, {1, {}, IRT::Bool}},
274 : // pub fn caller_location() -> &'static crate::panic::Location<'static>;
275 : {IValue::CALLER_LOCATION, {0, {}, IRT::RefAdt}},
276 : // pub fn ctpop<T: Copy>(x: T) -> T;
277 : {IValue::CTPOP, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
278 :
279 : // pub fn ctlz<T: Copy>(x: T) -> T;
280 : {IValue::CTLZ, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
281 : // pub fn ctlz_nonzero<T: Copy>(x: T) -> T;
282 : {IValue::CTLZ_NONZERO, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
283 : // pub fn cttz<T: Copy>(x: T) -> T;
284 : {IValue::CTTZ, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
285 : // pub fn cttz_nonzero<T: Copy>(x: T) -> T;
286 : {IValue::CTTZ_NONZERO, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
287 : // pub fn bswap<T: Copy>(x: T) -> T;
288 : {IValue::BSWAP, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
289 : // pub fn bitreverse<T: Copy>(x: T) -> T;
290 : {IValue::BITREVERSE, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
291 : // pub fn type_id<T: ?Sized + 'static>() -> u64;
292 : {IValue::TYPE_ID, {1, {}, IRT::U64}},
293 : // pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
294 : {IValue::PTR_GUARANTEED_EQ,
295 : {1, {IRT::ConstPtrFirstGeneric, IRT::ConstPtrFirstGeneric}, IRT::Bool}},
296 : // pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
297 : {IValue::PTR_GUARANTEED_NE,
298 : {1, {IRT::ConstPtrFirstGeneric, IRT::ConstPtrFirstGeneric}, IRT::Bool}},
299 : // pub fn rustc_peek<T>(_: T) -> T;
300 : {IValue::RUSTC_PEEK, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
301 : // pub fn type_name<T: ?Sized>() -> &'static str;
302 : {IValue::TYPE_NAME, {1, {}, IRT::RefStaticStr}},
303 : // pub fn forget<T: ?Sized>(_: T);
304 : {IValue::FORGET, {1, {IRT::FirstGeneric}, IRT::Unit}},
305 : // pub fn black_box<T>(mut dummy: T) -> T
306 : {IValue::BLACK_BOX, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
307 :
308 : // pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
309 : {IValue::ARITH_OFFSET,
310 : {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
311 : // fn write_bytes<T>(dst: *mut T, val: u8, count: usize)
312 : {IValue::WRITE_BYTES,
313 : {1, {IRT::MutPtrFirstGeneric, IRT::U8, IRT::Usize}, IRT::Unit}},
314 :
315 : };
316 :
317 : IntrinsicCheckResult
318 1439 : IntrinsicChecker::check (const TyTy::FnType *fntype)
319 : {
320 2878 : auto it = intrinsic_rules.find (fntype->get_identifier ());
321 1439 : if (it == intrinsic_rules.end ())
322 : {
323 16 : rust_error_at (fntype->get_locus (), ErrorCode::E0093,
324 : "unrecognized intrinsic function: %qs",
325 8 : fntype->get_identifier ().c_str ());
326 8 : return IntrinsicCheckResult::Invalid;
327 : }
328 1431 : auto rule = &it->second;
329 :
330 1431 : if (fntype->get_substs ().size () != rule->generic_count)
331 : {
332 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0094,
333 : "intrinsic has wrong number of type parameters: found "
334 : "%lu, expected %lu",
335 1 : (unsigned long) fntype->get_substs ().size (),
336 : (unsigned long) rule->generic_count);
337 1 : return IntrinsicCheckResult::Invalid;
338 : }
339 :
340 1430 : IntrinsicCheckResult result = IntrinsicCheckResult::Valid;
341 :
342 1430 : if (fntype->get_num_params () != rule->param_types.size ())
343 : {
344 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
345 : "intrinsic has wrong number of function parameters: found "
346 : "%lu, expected %lu",
347 1 : (unsigned long) fntype->get_params ().size (),
348 1 : (unsigned long) rule->param_types.size ());
349 1 : result = IntrinsicCheckResult::Invalid;
350 : }
351 : else
352 : {
353 3236 : for (size_t i = 0; i < rule->param_types.size (); i++)
354 : {
355 1807 : const TyTy::BaseType *actual_param
356 1807 : = fntype->get_params ().at (i).get_type ();
357 1807 : IntrinsicRuleType expected_type = rule->param_types.at (i);
358 :
359 1807 : if (!check_type (actual_param, expected_type, fntype))
360 : {
361 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
362 : "intrinsic has wrong type");
363 3 : result = IntrinsicCheckResult::Invalid;
364 : }
365 : }
366 : }
367 :
368 1430 : if (!check_type (fntype->get_return_type (), rule->return_type, fntype))
369 : {
370 2 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
371 : "intrinsic has wrong type");
372 2 : result = IntrinsicCheckResult::Invalid;
373 : }
374 :
375 1430 : if (result == IntrinsicCheckResult::Invalid)
376 : {
377 5 : rust_inform (fntype->get_locus (), "expected fn pointer %qs",
378 5 : expected_intrinsic_as_string (fntype).c_str ());
379 5 : rust_inform (fntype->get_locus (), " found fn pointer %qs",
380 10 : found_intrinsic_as_string (fntype).c_str ());
381 : }
382 : return result;
383 : }
384 :
385 : bool
386 3290 : IntrinsicChecker::check_type (const TyTy::BaseType *actual,
387 : IntrinsicRuleType expected,
388 : const TyTy::FnType *fntype)
389 : {
390 3802 : switch (expected)
391 : {
392 1 : case IRT::Bool:
393 1 : return actual->get_kind () == TyTy::TypeKind::BOOL;
394 336 : case IRT::F32:
395 336 : return actual->get_kind () == TyTy::TypeKind::FLOAT
396 336 : && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
397 : == TyTy::FloatType::FloatKind::F32;
398 336 : case IRT::F64:
399 336 : return actual->get_kind () == TyTy::TypeKind::FLOAT
400 336 : && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
401 : == TyTy::FloatType::FloatKind::F64;
402 29 : case IRT::I32:
403 29 : return actual->get_kind () == TyTy::TypeKind::INT
404 29 : && static_cast<const TyTy::IntType *> (actual)->get_int_kind ()
405 : == TyTy::IntType::IntKind::I32;
406 106 : case IRT::Isize:
407 106 : return actual->get_kind () == TyTy::TypeKind::ISIZE;
408 12 : case IRT::U8:
409 12 : return actual->get_kind () == TyTy::TypeKind::UINT
410 12 : && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
411 : == TyTy::UintType::UintKind::U8;
412 0 : case IRT::U64:
413 0 : return actual->get_kind () == TyTy::TypeKind::UINT
414 0 : && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
415 : == TyTy::UintType::UintKind::U64;
416 138 : case IRT::Usize:
417 138 : return actual->get_kind () == TyTy::TypeKind::USIZE;
418 148 : case IRT::Unit:
419 148 : return actual->is_unit ();
420 156 : case IRT::Never:
421 156 : return actual->get_kind () == TyTy::TypeKind::NEVER;
422 :
423 1904 : case IRT::FirstGeneric:
424 1904 : case IRT::SecondGeneric:
425 1904 : {
426 1904 : if (actual->get_kind () != TyTy::TypeKind::PARAM)
427 : return false;
428 :
429 1902 : auto param = static_cast<const TyTy::ParamType *> (actual);
430 1902 : size_t expected_index = (expected == IRT::FirstGeneric) ? 0 : 1;
431 1902 : if (fntype->get_substs ().size () <= expected_index)
432 : return false;
433 1902 : auto expected_param
434 1902 : = fntype->get_substs ().at (expected_index).get_param_ty ();
435 1902 : return param->get_ty_ref () == expected_param->get_ty_ref ();
436 : }
437 297 : case IRT::ConstPtrFirstGeneric:
438 297 : {
439 297 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
440 : return false;
441 296 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
442 296 : if (!ptr->is_const ())
443 : return false;
444 296 : return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
445 296 : fntype);
446 : }
447 131 : case IRT::MutPtrFirstGeneric:
448 131 : {
449 131 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
450 : return false;
451 131 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
452 131 : if (!ptr->is_mutable ())
453 : return false;
454 131 : return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
455 131 : fntype);
456 : }
457 72 : case IRT::RefFirstGeneric:
458 72 : {
459 72 : if (actual->get_kind () != TyTy::TypeKind::REF)
460 : return false;
461 72 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
462 72 : if (ref->is_mutable ())
463 : return false;
464 72 : return check_type (ref->get_base (), IntrinsicRuleType::FirstGeneric,
465 72 : fntype);
466 : }
467 0 : case IRT::RefAdt:
468 0 : {
469 0 : if (actual->get_kind () != TyTy::TypeKind::REF)
470 : return false;
471 0 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
472 0 : if (ref->is_mutable ())
473 : return false;
474 0 : return ref->get_base ()->get_kind () == TyTy::TypeKind::ADT;
475 : }
476 11 : case IRT::MutPtrU8:
477 11 : {
478 11 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
479 : return false;
480 11 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
481 11 : if (!ptr->is_mutable ())
482 : return false;
483 11 : return check_type (ptr->get_base (), IRT::U8, fntype);
484 : }
485 0 : case IRT::RefStaticStr:
486 0 : {
487 0 : if (actual->get_kind () != TyTy::TypeKind::REF)
488 : return false;
489 0 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
490 0 : if (ref->is_mutable ())
491 : return false;
492 0 : return ref->get_base ()->get_kind () == TyTy::TypeKind::STR;
493 : }
494 : case IRT::AssocTypePlaceholder:
495 : return true;
496 :
497 47 : case IRT::TupleFirstGenericAndBool:
498 47 : {
499 47 : if (actual->get_kind () != TyTy::TypeKind::TUPLE)
500 : return false;
501 47 : auto tuple = static_cast<const TyTy::TupleType *> (actual);
502 47 : if (tuple->num_fields () != 2)
503 : return false;
504 47 : return tuple->get_field (1)->get_kind () == TyTy::TypeKind::BOOL
505 47 : && check_type (tuple->get_field (0),
506 : IntrinsicRuleType::FirstGeneric, fntype);
507 : }
508 :
509 3 : case IRT::Fn_MutPtrU8:
510 3 : {
511 3 : if (actual->get_kind () != TyTy::TypeKind::FNPTR)
512 : return false;
513 2 : auto fn = static_cast<const TyTy::FnPtr *> (actual);
514 2 : if (!fn->get_return_type ()->is_unit ())
515 : return false;
516 2 : if (fn->get_num_params () != 1)
517 : return false;
518 2 : return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype);
519 : }
520 3 : case IRT::Fn_MutPtrU8MutPtrU8:
521 3 : {
522 3 : if (actual->get_kind () != TyTy::TypeKind::FNPTR)
523 : return false;
524 3 : auto fn = static_cast<const TyTy::FnPtr *> (actual);
525 3 : if (!fn->get_return_type ()->is_unit ())
526 : return false;
527 3 : if (fn->get_num_params () != 2)
528 : return false;
529 3 : return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype)
530 3 : && check_type (fn->get_param_type_at (1), IRT::MutPtrU8, fntype);
531 : }
532 :
533 0 : default:
534 0 : rust_unreachable ();
535 : };
536 : return true;
537 : }
538 :
539 : static std::string
540 22 : to_string (const TyTy::BaseType *type, const TyTy::FnType *fntype)
541 : {
542 22 : switch (type->get_kind ())
543 : {
544 1 : case TyTy::TypeKind::BOOL:
545 1 : return "bool";
546 3 : case TyTy::TypeKind::USIZE:
547 3 : return "usize";
548 1 : case TyTy::TypeKind::ISIZE:
549 1 : return "isize";
550 1 : case TyTy::TypeKind::NEVER:
551 1 : return "!";
552 0 : case TyTy::TypeKind::STR:
553 0 : return "str";
554 :
555 3 : case TyTy::TypeKind::INT:
556 3 : {
557 3 : auto int_ty = static_cast<const TyTy::IntType *> (type);
558 3 : switch (int_ty->get_int_kind ())
559 : {
560 0 : case TyTy::IntType::IntKind::I8:
561 0 : return "i8";
562 0 : case TyTy::IntType::IntKind::I16:
563 0 : return "i16";
564 3 : case TyTy::IntType::IntKind::I32:
565 3 : return "i32";
566 0 : case TyTy::IntType::IntKind::I64:
567 0 : return "i64";
568 0 : case TyTy::IntType::IntKind::I128:
569 0 : return "i128";
570 : }
571 0 : rust_unreachable ();
572 : }
573 :
574 3 : case TyTy::TypeKind::UINT:
575 3 : {
576 3 : auto uint_ty = static_cast<const TyTy::UintType *> (type);
577 3 : switch (uint_ty->get_uint_kind ())
578 : {
579 3 : case TyTy::UintType::UintKind::U8:
580 3 : return "u8";
581 0 : case TyTy::UintType::UintKind::U16:
582 0 : return "u16";
583 0 : case TyTy::UintType::UintKind::U32:
584 0 : return "u32";
585 0 : case TyTy::UintType::UintKind::U64:
586 0 : return "u64";
587 0 : case TyTy::UintType::UintKind::U128:
588 0 : return "u128";
589 : }
590 0 : rust_unreachable ();
591 : }
592 :
593 0 : case TyTy::TypeKind::FLOAT:
594 0 : {
595 0 : auto float_ty = static_cast<const TyTy::FloatType *> (type);
596 0 : switch (float_ty->get_float_kind ())
597 : {
598 0 : case TyTy::FloatType::FloatKind::F32:
599 0 : return "f32";
600 0 : case TyTy::FloatType::FloatKind::F64:
601 0 : return "f64";
602 : }
603 0 : rust_unreachable ();
604 : }
605 :
606 4 : case TyTy::TypeKind::PARAM:
607 4 : {
608 4 : auto param = static_cast<const TyTy::ParamType *> (type);
609 4 : if (fntype != nullptr)
610 : {
611 4 : auto substs = fntype->get_substs ();
612 4 : for (size_t i = 0; i < substs.size (); i++)
613 : {
614 8 : if (substs[i].get_param_ty ()->get_ty_ref ()
615 4 : == param->get_ty_ref ())
616 4 : return "P" + std::to_string (i);
617 : }
618 4 : }
619 0 : return param->get_symbol ();
620 : }
621 :
622 4 : case TyTy::TypeKind::POINTER:
623 4 : {
624 4 : auto ptr = static_cast<const TyTy::PointerType *> (type);
625 4 : std::string prefix = ptr->is_mutable () ? "*mut "
626 1 : : ptr->is_const () ? "*const "
627 5 : : "*";
628 4 : return prefix + to_string (ptr->get_base (), fntype);
629 4 : }
630 :
631 0 : case TyTy::TypeKind::REF:
632 0 : {
633 0 : auto ref = static_cast<const TyTy::ReferenceType *> (type);
634 0 : std::string prefix = ref->is_mutable () ? "&mut " : "&";
635 0 : return prefix + to_string (ref->get_base (), fntype);
636 0 : }
637 :
638 1 : case TyTy::TypeKind::TUPLE:
639 1 : {
640 1 : auto tuple = static_cast<const TyTy::TupleType *> (type);
641 1 : if (tuple->num_fields () == 0)
642 0 : return "()";
643 :
644 1 : std::string res = "(";
645 3 : for (size_t i = 0; i < tuple->num_fields (); i++)
646 : {
647 2 : if (i > 0)
648 1 : res += ", ";
649 4 : res += to_string (tuple->get_field (i), fntype);
650 : }
651 1 : res += ")";
652 1 : return res;
653 1 : }
654 :
655 1 : case TyTy::TypeKind::FNPTR:
656 1 : {
657 1 : auto fnptr = static_cast<const TyTy::FnPtr *> (type);
658 1 : std::string res = "fn(";
659 3 : for (size_t i = 0; i < fnptr->get_num_params (); i++)
660 : {
661 2 : if (i > 0)
662 1 : res += ", ";
663 4 : res += to_string (fnptr->get_param_type_at (i), fntype);
664 : }
665 1 : res += ")";
666 1 : if (!fnptr->get_return_type ()->is_unit ()
667 1 : || fnptr->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
668 : {
669 0 : res += " -> ";
670 0 : res += to_string (fnptr->get_return_type (), fntype);
671 : }
672 1 : return res;
673 1 : }
674 :
675 0 : case TyTy::TypeKind::ADT:
676 0 : {
677 0 : auto adt = static_cast<const TyTy::ADTType *> (type);
678 0 : return adt->get_name ();
679 : }
680 :
681 0 : case TyTy::TypeKind::PLACEHOLDER:
682 0 : {
683 0 : auto ph = static_cast<const TyTy::PlaceholderType *> (type);
684 0 : return "<" + ph->get_symbol () + ">";
685 : }
686 :
687 0 : default:
688 0 : return type->as_string ();
689 : }
690 : }
691 :
692 : static std::string
693 12 : to_string (IntrinsicRuleType ty)
694 : {
695 12 : switch (ty)
696 : {
697 0 : case IRT::Bool:
698 0 : return "bool";
699 0 : case IRT::F32:
700 0 : return "f32";
701 0 : case IRT::F64:
702 0 : return "f64";
703 0 : case IRT::I32:
704 0 : return "i32";
705 1 : case IRT::Isize:
706 1 : return "isize";
707 0 : case IRT::U8:
708 0 : return "u8";
709 0 : case IRT::U64:
710 0 : return "u64";
711 0 : case IRT::Usize:
712 0 : return "usize";
713 0 : case IRT::Unit:
714 0 : return "()";
715 1 : case IRT::Never:
716 1 : return "!";
717 :
718 3 : case IRT::FirstGeneric:
719 3 : return "P0";
720 1 : case IRT::SecondGeneric:
721 1 : return "P1";
722 :
723 2 : case IRT::ConstPtrFirstGeneric:
724 2 : return "*const P0";
725 0 : case IRT::MutPtrFirstGeneric:
726 0 : return "*mut P0";
727 0 : case IRT::RefFirstGeneric:
728 0 : return "&P0";
729 :
730 0 : case IRT::RefAdt:
731 0 : return "&<ADT>";
732 1 : case IRT::MutPtrU8:
733 1 : return "*mut u8";
734 0 : case IRT::RefStaticStr:
735 0 : return "&'static str";
736 0 : case IRT::AssocTypePlaceholder:
737 0 : return "<AssocType>";
738 :
739 1 : case IRT::TupleFirstGenericAndBool:
740 1 : return "(P0, bool)";
741 :
742 1 : case IRT::Fn_MutPtrU8:
743 1 : return "fn(*mut u8)";
744 1 : case IRT::Fn_MutPtrU8MutPtrU8:
745 1 : return "fn(*mut u8, *mut u8)";
746 0 : };
747 0 : rust_unreachable ();
748 : }
749 :
750 : std::string
751 5 : IntrinsicChecker::expected_intrinsic_as_string (const TyTy::FnType *fntype)
752 : {
753 10 : auto it = intrinsic_rules.find (fntype->get_identifier ());
754 5 : rust_assert (it != intrinsic_rules.end ());
755 5 : auto rule = &it->second;
756 5 : std::stringstream result;
757 5 : result << "extern \"rust-intrinsic\" fn(";
758 5 : if (rule->param_types.size () > 0)
759 : {
760 12 : for (size_t i = 0; i < rule->param_types.size (); i++)
761 : {
762 8 : if (i != 0)
763 4 : result << ", ";
764 16 : result << to_string (rule->param_types.at (i));
765 : }
766 : }
767 5 : result << ")";
768 5 : if (rule->return_type != IntrinsicRuleType::Unit)
769 : {
770 8 : result << " -> " << to_string (rule->return_type);
771 : }
772 5 : return result.str ();
773 5 : }
774 :
775 : std::string
776 5 : IntrinsicChecker::found_intrinsic_as_string (const TyTy::FnType *fntype)
777 : {
778 5 : std::stringstream result;
779 5 : result << "extern \"rust-intrinsic\" fn(";
780 5 : if (fntype->get_num_params () > 0)
781 : {
782 5 : const auto ¶ms = fntype->get_params ();
783 14 : for (size_t i = 0; i < params.size (); i++)
784 : {
785 9 : if (i != 0)
786 4 : result << ", ";
787 18 : result << to_string (params.at (i).get_type (), fntype);
788 : }
789 : }
790 5 : result << ")";
791 5 : if (!fntype->get_return_type ()->is_unit ()
792 5 : || fntype->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
793 : {
794 10 : result << " -> " << to_string (fntype->get_return_type (), fntype);
795 : }
796 5 : return result.str ();
797 5 : }
798 :
799 : } // namespace Resolver
800 : } // namespace Rust
|