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 : // pub fn assert_zero_valid<T>();
315 : {IValue::ASSERT_ZERO_VALID, {1, {}, IRT::Unit}},
316 :
317 : // pub fn fadd_fast<T>(a: T, b: T) -> T
318 : // same for fsub_fast, fmul_fast, fdiv_fast and frem_fast
319 : {IValue::FADD_FAST,
320 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
321 : {IValue::FSUB_FAST,
322 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
323 : {IValue::FMUL_FAST,
324 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
325 : {IValue::FDIV_FAST,
326 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
327 : {IValue::FREM_FAST,
328 : {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
329 :
330 : // fn float_to_int_unchecked<Float, Int>(x: Float) -> Int
331 : // where Float: FloatPrimitive, Int: Copy
332 : {IValue::FLOAT_TO_INT_UNCHECKED,
333 : {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
334 :
335 : };
336 :
337 : IntrinsicCheckResult
338 1546 : IntrinsicChecker::check (const TyTy::FnType *fntype)
339 : {
340 3092 : auto it = intrinsic_rules.find (fntype->get_identifier ());
341 1546 : if (it == intrinsic_rules.end ())
342 : {
343 16 : rust_error_at (fntype->get_locus (), ErrorCode::E0093,
344 : "unrecognized intrinsic function: %qs",
345 8 : fntype->get_identifier ().c_str ());
346 8 : return IntrinsicCheckResult::Invalid;
347 : }
348 1538 : auto rule = &it->second;
349 :
350 1538 : if (fntype->get_substs ().size () != rule->generic_count)
351 : {
352 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0094,
353 : "intrinsic has wrong number of type parameters: found "
354 : "%lu, expected %lu",
355 1 : (unsigned long) fntype->get_substs ().size (),
356 : (unsigned long) rule->generic_count);
357 1 : return IntrinsicCheckResult::Invalid;
358 : }
359 :
360 1537 : IntrinsicCheckResult result = IntrinsicCheckResult::Valid;
361 :
362 1537 : if (fntype->get_num_params () != rule->param_types.size ())
363 : {
364 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
365 : "intrinsic has wrong number of function parameters: found "
366 : "%lu, expected %lu",
367 1 : (unsigned long) fntype->get_params ().size (),
368 1 : (unsigned long) rule->param_types.size ());
369 1 : result = IntrinsicCheckResult::Invalid;
370 : }
371 : else
372 : {
373 3512 : for (size_t i = 0; i < rule->param_types.size (); i++)
374 : {
375 1976 : const TyTy::BaseType *actual_param
376 1976 : = fntype->get_params ().at (i).get_type ();
377 1976 : IntrinsicRuleType expected_type = rule->param_types.at (i);
378 :
379 1976 : if (!check_type (actual_param, expected_type, fntype))
380 : {
381 3 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
382 : "intrinsic has wrong type");
383 3 : result = IntrinsicCheckResult::Invalid;
384 : }
385 : }
386 : }
387 :
388 1537 : if (!check_type (fntype->get_return_type (), rule->return_type, fntype))
389 : {
390 2 : rust_error_at (fntype->get_locus (), ErrorCode::E0308,
391 : "intrinsic has wrong type");
392 2 : result = IntrinsicCheckResult::Invalid;
393 : }
394 :
395 1537 : if (result == IntrinsicCheckResult::Invalid)
396 : {
397 5 : rust_inform (fntype->get_locus (), "expected fn pointer %qs",
398 5 : expected_intrinsic_as_string (fntype).c_str ());
399 5 : rust_inform (fntype->get_locus (), " found fn pointer %qs",
400 10 : found_intrinsic_as_string (fntype).c_str ());
401 : }
402 : return result;
403 : }
404 :
405 : bool
406 3574 : IntrinsicChecker::check_type (const TyTy::BaseType *actual,
407 : IntrinsicRuleType expected,
408 : const TyTy::FnType *fntype)
409 : {
410 4131 : switch (expected)
411 : {
412 1 : case IRT::Bool:
413 1 : return actual->get_kind () == TyTy::TypeKind::BOOL;
414 336 : case IRT::F32:
415 336 : return actual->get_kind () == TyTy::TypeKind::FLOAT
416 336 : && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
417 : == TyTy::FloatType::FloatKind::F32;
418 336 : case IRT::F64:
419 336 : return actual->get_kind () == TyTy::TypeKind::FLOAT
420 336 : && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
421 : == TyTy::FloatType::FloatKind::F64;
422 29 : case IRT::I32:
423 29 : return actual->get_kind () == TyTy::TypeKind::INT
424 29 : && static_cast<const TyTy::IntType *> (actual)->get_int_kind ()
425 : == TyTy::IntType::IntKind::I32;
426 116 : case IRT::Isize:
427 116 : return actual->get_kind () == TyTy::TypeKind::ISIZE;
428 12 : case IRT::U8:
429 12 : return actual->get_kind () == TyTy::TypeKind::UINT
430 12 : && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
431 : == TyTy::UintType::UintKind::U8;
432 0 : case IRT::U64:
433 0 : return actual->get_kind () == TyTy::TypeKind::UINT
434 0 : && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
435 : == TyTy::UintType::UintKind::U64;
436 156 : case IRT::Usize:
437 156 : return actual->get_kind () == TyTy::TypeKind::USIZE;
438 165 : case IRT::Unit:
439 165 : return actual->is_unit ();
440 156 : case IRT::Never:
441 156 : return actual->get_kind () == TyTy::TypeKind::NEVER;
442 :
443 2135 : case IRT::FirstGeneric:
444 2135 : case IRT::SecondGeneric:
445 2135 : {
446 2135 : if (actual->get_kind () != TyTy::TypeKind::PARAM)
447 : return false;
448 :
449 2133 : auto param = static_cast<const TyTy::ParamType *> (actual);
450 2133 : size_t expected_index = (expected == IRT::FirstGeneric) ? 0 : 1;
451 2133 : if (fntype->get_substs ().size () <= expected_index)
452 : return false;
453 2133 : auto expected_param
454 2133 : = fntype->get_substs ().at (expected_index).get_param_ty ();
455 2133 : return param->get_ty_ref () == expected_param->get_ty_ref ();
456 : }
457 326 : case IRT::ConstPtrFirstGeneric:
458 326 : {
459 326 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
460 : return false;
461 325 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
462 325 : if (!ptr->is_const ())
463 : return false;
464 325 : return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
465 325 : fntype);
466 : }
467 147 : case IRT::MutPtrFirstGeneric:
468 147 : {
469 147 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
470 : return false;
471 147 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
472 147 : if (!ptr->is_mutable ())
473 : return false;
474 147 : return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
475 147 : fntype);
476 : }
477 72 : case IRT::RefFirstGeneric:
478 72 : {
479 72 : if (actual->get_kind () != TyTy::TypeKind::REF)
480 : return false;
481 72 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
482 72 : if (ref->is_mutable ())
483 : return false;
484 72 : return check_type (ref->get_base (), IntrinsicRuleType::FirstGeneric,
485 72 : fntype);
486 : }
487 0 : case IRT::RefAdt:
488 0 : {
489 0 : if (actual->get_kind () != TyTy::TypeKind::REF)
490 : return false;
491 0 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
492 0 : if (ref->is_mutable ())
493 : return false;
494 0 : return ref->get_base ()->get_kind () == TyTy::TypeKind::ADT;
495 : }
496 11 : case IRT::MutPtrU8:
497 11 : {
498 11 : if (actual->get_kind () != TyTy::TypeKind::POINTER)
499 : return false;
500 11 : auto ptr = static_cast<const TyTy::PointerType *> (actual);
501 11 : if (!ptr->is_mutable ())
502 : return false;
503 11 : return check_type (ptr->get_base (), IRT::U8, fntype);
504 : }
505 0 : case IRT::RefStaticStr:
506 0 : {
507 0 : if (actual->get_kind () != TyTy::TypeKind::REF)
508 : return false;
509 0 : auto ref = static_cast<const TyTy::ReferenceType *> (actual);
510 0 : if (ref->is_mutable ())
511 : return false;
512 0 : return ref->get_base ()->get_kind () == TyTy::TypeKind::STR;
513 : }
514 : case IRT::AssocTypePlaceholder:
515 : return true;
516 :
517 55 : case IRT::TupleFirstGenericAndBool:
518 55 : {
519 55 : if (actual->get_kind () != TyTy::TypeKind::TUPLE)
520 : return false;
521 55 : auto tuple = static_cast<const TyTy::TupleType *> (actual);
522 55 : if (tuple->num_fields () != 2)
523 : return false;
524 55 : return tuple->get_field (1)->get_kind () == TyTy::TypeKind::BOOL
525 55 : && check_type (tuple->get_field (0),
526 : IntrinsicRuleType::FirstGeneric, fntype);
527 : }
528 :
529 3 : case IRT::Fn_MutPtrU8:
530 3 : {
531 3 : if (actual->get_kind () != TyTy::TypeKind::FNPTR)
532 : return false;
533 2 : auto fn = static_cast<const TyTy::FnPtr *> (actual);
534 2 : if (!fn->get_return_type ()->is_unit ())
535 : return false;
536 2 : if (fn->get_num_params () != 1)
537 : return false;
538 2 : return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype);
539 : }
540 3 : case IRT::Fn_MutPtrU8MutPtrU8:
541 3 : {
542 3 : if (actual->get_kind () != TyTy::TypeKind::FNPTR)
543 : return false;
544 3 : auto fn = static_cast<const TyTy::FnPtr *> (actual);
545 3 : if (!fn->get_return_type ()->is_unit ())
546 : return false;
547 3 : if (fn->get_num_params () != 2)
548 : return false;
549 3 : return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype)
550 3 : && check_type (fn->get_param_type_at (1), IRT::MutPtrU8, fntype);
551 : }
552 :
553 0 : default:
554 0 : rust_unreachable ();
555 : };
556 : return true;
557 : }
558 :
559 : static std::string
560 22 : to_string (const TyTy::BaseType *type, const TyTy::FnType *fntype)
561 : {
562 22 : switch (type->get_kind ())
563 : {
564 1 : case TyTy::TypeKind::BOOL:
565 1 : return "bool";
566 3 : case TyTy::TypeKind::USIZE:
567 3 : return "usize";
568 1 : case TyTy::TypeKind::ISIZE:
569 1 : return "isize";
570 1 : case TyTy::TypeKind::NEVER:
571 1 : return "!";
572 0 : case TyTy::TypeKind::STR:
573 0 : return "str";
574 :
575 3 : case TyTy::TypeKind::INT:
576 3 : {
577 3 : auto int_ty = static_cast<const TyTy::IntType *> (type);
578 3 : switch (int_ty->get_int_kind ())
579 : {
580 0 : case TyTy::IntType::IntKind::I8:
581 0 : return "i8";
582 0 : case TyTy::IntType::IntKind::I16:
583 0 : return "i16";
584 3 : case TyTy::IntType::IntKind::I32:
585 3 : return "i32";
586 0 : case TyTy::IntType::IntKind::I64:
587 0 : return "i64";
588 0 : case TyTy::IntType::IntKind::I128:
589 0 : return "i128";
590 : }
591 0 : rust_unreachable ();
592 : }
593 :
594 3 : case TyTy::TypeKind::UINT:
595 3 : {
596 3 : auto uint_ty = static_cast<const TyTy::UintType *> (type);
597 3 : switch (uint_ty->get_uint_kind ())
598 : {
599 3 : case TyTy::UintType::UintKind::U8:
600 3 : return "u8";
601 0 : case TyTy::UintType::UintKind::U16:
602 0 : return "u16";
603 0 : case TyTy::UintType::UintKind::U32:
604 0 : return "u32";
605 0 : case TyTy::UintType::UintKind::U64:
606 0 : return "u64";
607 0 : case TyTy::UintType::UintKind::U128:
608 0 : return "u128";
609 : }
610 0 : rust_unreachable ();
611 : }
612 :
613 0 : case TyTy::TypeKind::FLOAT:
614 0 : {
615 0 : auto float_ty = static_cast<const TyTy::FloatType *> (type);
616 0 : switch (float_ty->get_float_kind ())
617 : {
618 0 : case TyTy::FloatType::FloatKind::F32:
619 0 : return "f32";
620 0 : case TyTy::FloatType::FloatKind::F64:
621 0 : return "f64";
622 : }
623 0 : rust_unreachable ();
624 : }
625 :
626 4 : case TyTy::TypeKind::PARAM:
627 4 : {
628 4 : auto param = static_cast<const TyTy::ParamType *> (type);
629 4 : if (fntype != nullptr)
630 : {
631 4 : auto substs = fntype->get_substs ();
632 8 : for (size_t i = 0; i < substs.size (); i++)
633 : {
634 8 : if (substs[i].get_param_ty ()->get_ty_ref ()
635 4 : == param->get_ty_ref ())
636 4 : return "P" + std::to_string (i);
637 : }
638 4 : }
639 0 : return param->get_symbol ();
640 : }
641 :
642 4 : case TyTy::TypeKind::POINTER:
643 4 : {
644 4 : auto ptr = static_cast<const TyTy::PointerType *> (type);
645 4 : std::string prefix = ptr->is_mutable () ? "*mut "
646 1 : : ptr->is_const () ? "*const "
647 5 : : "*";
648 4 : return prefix + to_string (ptr->get_base (), fntype);
649 4 : }
650 :
651 0 : case TyTy::TypeKind::REF:
652 0 : {
653 0 : auto ref = static_cast<const TyTy::ReferenceType *> (type);
654 0 : std::string prefix = ref->is_mutable () ? "&mut " : "&";
655 0 : return prefix + to_string (ref->get_base (), fntype);
656 0 : }
657 :
658 1 : case TyTy::TypeKind::TUPLE:
659 1 : {
660 1 : auto tuple = static_cast<const TyTy::TupleType *> (type);
661 1 : if (tuple->num_fields () == 0)
662 0 : return "()";
663 :
664 1 : std::string res = "(";
665 3 : for (size_t i = 0; i < tuple->num_fields (); i++)
666 : {
667 2 : if (i > 0)
668 1 : res += ", ";
669 4 : res += to_string (tuple->get_field (i), fntype);
670 : }
671 1 : res += ")";
672 1 : return res;
673 1 : }
674 :
675 1 : case TyTy::TypeKind::FNPTR:
676 1 : {
677 1 : auto fnptr = static_cast<const TyTy::FnPtr *> (type);
678 1 : std::string res = "fn(";
679 3 : for (size_t i = 0; i < fnptr->get_num_params (); i++)
680 : {
681 2 : if (i > 0)
682 1 : res += ", ";
683 4 : res += to_string (fnptr->get_param_type_at (i), fntype);
684 : }
685 1 : res += ")";
686 1 : if (!fnptr->get_return_type ()->is_unit ()
687 1 : || fnptr->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
688 : {
689 0 : res += " -> ";
690 0 : res += to_string (fnptr->get_return_type (), fntype);
691 : }
692 1 : return res;
693 1 : }
694 :
695 0 : case TyTy::TypeKind::ADT:
696 0 : {
697 0 : auto adt = static_cast<const TyTy::ADTType *> (type);
698 0 : return adt->get_name ();
699 : }
700 :
701 0 : case TyTy::TypeKind::PLACEHOLDER:
702 0 : {
703 0 : auto ph = static_cast<const TyTy::PlaceholderType *> (type);
704 0 : return "<" + ph->get_symbol () + ">";
705 : }
706 :
707 0 : default:
708 0 : return type->as_string ();
709 : }
710 : }
711 :
712 : static std::string
713 12 : to_string (IntrinsicRuleType ty)
714 : {
715 12 : switch (ty)
716 : {
717 0 : case IRT::Bool:
718 0 : return "bool";
719 0 : case IRT::F32:
720 0 : return "f32";
721 0 : case IRT::F64:
722 0 : return "f64";
723 0 : case IRT::I32:
724 0 : return "i32";
725 1 : case IRT::Isize:
726 1 : return "isize";
727 0 : case IRT::U8:
728 0 : return "u8";
729 0 : case IRT::U64:
730 0 : return "u64";
731 0 : case IRT::Usize:
732 0 : return "usize";
733 0 : case IRT::Unit:
734 0 : return "()";
735 1 : case IRT::Never:
736 1 : return "!";
737 :
738 3 : case IRT::FirstGeneric:
739 3 : return "P0";
740 1 : case IRT::SecondGeneric:
741 1 : return "P1";
742 :
743 2 : case IRT::ConstPtrFirstGeneric:
744 2 : return "*const P0";
745 0 : case IRT::MutPtrFirstGeneric:
746 0 : return "*mut P0";
747 0 : case IRT::RefFirstGeneric:
748 0 : return "&P0";
749 :
750 0 : case IRT::RefAdt:
751 0 : return "&<ADT>";
752 1 : case IRT::MutPtrU8:
753 1 : return "*mut u8";
754 0 : case IRT::RefStaticStr:
755 0 : return "&'static str";
756 0 : case IRT::AssocTypePlaceholder:
757 0 : return "<AssocType>";
758 :
759 1 : case IRT::TupleFirstGenericAndBool:
760 1 : return "(P0, bool)";
761 :
762 1 : case IRT::Fn_MutPtrU8:
763 1 : return "fn(*mut u8)";
764 1 : case IRT::Fn_MutPtrU8MutPtrU8:
765 1 : return "fn(*mut u8, *mut u8)";
766 0 : };
767 0 : rust_unreachable ();
768 : }
769 :
770 : std::string
771 5 : IntrinsicChecker::expected_intrinsic_as_string (const TyTy::FnType *fntype)
772 : {
773 10 : auto it = intrinsic_rules.find (fntype->get_identifier ());
774 5 : rust_assert (it != intrinsic_rules.end ());
775 5 : auto rule = &it->second;
776 5 : std::stringstream result;
777 5 : result << "extern \"rust-intrinsic\" fn(";
778 5 : if (rule->param_types.size () > 0)
779 : {
780 12 : for (size_t i = 0; i < rule->param_types.size (); i++)
781 : {
782 8 : if (i != 0)
783 4 : result << ", ";
784 16 : result << to_string (rule->param_types.at (i));
785 : }
786 : }
787 5 : result << ")";
788 5 : if (rule->return_type != IntrinsicRuleType::Unit)
789 : {
790 8 : result << " -> " << to_string (rule->return_type);
791 : }
792 5 : return result.str ();
793 5 : }
794 :
795 : std::string
796 5 : IntrinsicChecker::found_intrinsic_as_string (const TyTy::FnType *fntype)
797 : {
798 5 : std::stringstream result;
799 5 : result << "extern \"rust-intrinsic\" fn(";
800 5 : if (fntype->get_num_params () > 0)
801 : {
802 5 : const auto ¶ms = fntype->get_params ();
803 14 : for (size_t i = 0; i < params.size (); i++)
804 : {
805 9 : if (i != 0)
806 4 : result << ", ";
807 18 : result << to_string (params.at (i).get_type (), fntype);
808 : }
809 : }
810 5 : result << ")";
811 5 : if (!fntype->get_return_type ()->is_unit ()
812 5 : || fntype->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
813 : {
814 10 : result << " -> " << to_string (fntype->get_return_type (), fntype);
815 : }
816 5 : return result.str ();
817 5 : }
818 :
819 : } // namespace Resolver
820 : } // namespace Rust
|