]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | //! Type-checking for the rust-intrinsic and platform-intrinsic |
2 | //! intrinsics that the compiler exposes. | |
3 | ||
1b1a35ee | 4 | use crate::errors::{ |
c295e0f8 | 5 | UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, |
136023e0 | 6 | WrongNumberOfGenericArgumentsToIntrinsic, |
1b1a35ee | 7 | }; |
9fa01778 | 8 | use crate::require_same_types; |
e9174d1e | 9 | |
2b03887a FG |
10 | use hir::def_id::DefId; |
11 | use rustc_errors::{struct_span_err, DiagnosticMessage}; | |
dfeec247 | 12 | use rustc_hir as hir; |
ba9703b0 | 13 | use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; |
fc512014 | 14 | use rustc_middle::ty::{self, TyCtxt}; |
f035d41b | 15 | use rustc_span::symbol::{kw, sym, Symbol}; |
83c7162d | 16 | use rustc_target::spec::abi::Abi; |
60c5eb7d | 17 | |
dc9dc135 XL |
18 | fn equate_intrinsic_type<'tcx>( |
19 | tcx: TyCtxt<'tcx>, | |
dfeec247 | 20 | it: &hir::ForeignItem<'_>, |
b7449926 | 21 | n_tps: usize, |
136023e0 | 22 | n_lts: usize, |
fc512014 | 23 | sig: ty::PolyFnSig<'tcx>, |
b7449926 | 24 | ) { |
136023e0 XL |
25 | let (own_counts, span) = match &it.kind { |
26 | hir::ForeignItemKind::Fn(.., generics) => { | |
2b03887a | 27 | let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts(); |
136023e0 XL |
28 | (own_counts, generics.span) |
29 | } | |
041b39d2 | 30 | _ => { |
dfeec247 | 31 | struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function") |
041b39d2 XL |
32 | .span_label(it.span, "expected a function") |
33 | .emit(); | |
34 | return; | |
35 | } | |
136023e0 | 36 | }; |
54a0048b | 37 | |
136023e0 XL |
38 | let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool { |
39 | if found != expected { | |
40 | tcx.sess.emit_err(WrongNumberOfGenericArgumentsToIntrinsic { | |
41 | span, | |
42 | found, | |
43 | expected, | |
136023e0 XL |
44 | descr, |
45 | }); | |
46 | false | |
47 | } else { | |
48 | true | |
49 | } | |
50 | }; | |
9e0c209e | 51 | |
136023e0 XL |
52 | if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime") |
53 | && gen_count_ok(own_counts.types, n_tps, "type") | |
54 | && gen_count_ok(own_counts.consts, 0, "const") | |
55 | { | |
56 | let fty = tcx.mk_fn_ptr(sig); | |
9ffffee4 FG |
57 | let it_def_id = it.owner_id.def_id; |
58 | let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); | |
59 | require_same_types( | |
60 | tcx, | |
61 | &cause, | |
353b0b11 | 62 | ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? |
9ffffee4 FG |
63 | tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), |
64 | fty, | |
65 | ); | |
e9174d1e SL |
66 | } |
67 | } | |
68 | ||
136023e0 | 69 | /// Returns the unsafety of the given intrinsic. |
2b03887a FG |
70 | pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety { |
71 | let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) { | |
72 | true => hir::Unsafety::Normal, | |
73 | false => hir::Unsafety::Unsafe, | |
74 | }; | |
75 | let is_in_list = match tcx.item_name(intrinsic_id) { | |
136023e0 XL |
76 | // When adding a new intrinsic to this list, |
77 | // it's usually worth updating that intrinsic's documentation | |
78 | // to note that it's safe to call, since | |
79 | // safe extern fns are otherwise unprecedented. | |
f035d41b | 80 | sym::abort |
f2b60f7d FG |
81 | | sym::assert_inhabited |
82 | | sym::assert_zero_valid | |
9c376795 | 83 | | sym::assert_mem_uninitialized_valid |
f035d41b XL |
84 | | sym::size_of |
85 | | sym::min_align_of | |
86 | | sym::needs_drop | |
87 | | sym::caller_location | |
f035d41b XL |
88 | | sym::add_with_overflow |
89 | | sym::sub_with_overflow | |
90 | | sym::mul_with_overflow | |
91 | | sym::wrapping_add | |
92 | | sym::wrapping_sub | |
93 | | sym::wrapping_mul | |
94 | | sym::saturating_add | |
95 | | sym::saturating_sub | |
96 | | sym::rotate_left | |
97 | | sym::rotate_right | |
98 | | sym::ctpop | |
99 | | sym::ctlz | |
100 | | sym::cttz | |
101 | | sym::bswap | |
102 | | sym::bitreverse | |
103 | | sym::discriminant_value | |
104 | | sym::type_id | |
105 | | sym::likely | |
106 | | sym::unlikely | |
f2b60f7d | 107 | | sym::ptr_guaranteed_cmp |
f035d41b XL |
108 | | sym::minnumf32 |
109 | | sym::minnumf64 | |
110 | | sym::maxnumf32 | |
111 | | sym::rustc_peek | |
112 | | sym::maxnumf64 | |
113 | | sym::type_name | |
5869c6ff | 114 | | sym::forget |
94222f64 | 115 | | sym::black_box |
f2b60f7d FG |
116 | | sym::variant_count |
117 | | sym::ptr_mask => hir::Unsafety::Normal, | |
0731742a | 118 | _ => hir::Unsafety::Unsafe, |
2b03887a FG |
119 | }; |
120 | ||
121 | if has_safe_attr != is_in_list { | |
122 | tcx.sess.struct_span_err( | |
123 | tcx.def_span(intrinsic_id), | |
124 | DiagnosticMessage::Str(format!( | |
125 | "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`", | |
126 | tcx.item_name(intrinsic_id) | |
127 | ))).emit(); | |
0731742a | 128 | } |
2b03887a FG |
129 | |
130 | is_in_list | |
0731742a XL |
131 | } |
132 | ||
1b1a35ee XL |
133 | /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, |
134 | /// and in `library/core/src/intrinsics.rs`. | |
dfeec247 | 135 | pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { |
e74abb32 | 136 | let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); |
2b03887a FG |
137 | let intrinsic_id = it.owner_id.to_def_id(); |
138 | let intrinsic_name = tcx.item_name(intrinsic_id); | |
f035d41b | 139 | let name_str = intrinsic_name.as_str(); |
a1dfa0c6 | 140 | |
9ffffee4 | 141 | let bound_vars = tcx.mk_bound_variable_kinds(&[ |
353b0b11 | 142 | ty::BoundVariableKind::Region(ty::BrAnon(None)), |
9ffffee4 FG |
143 | ty::BoundVariableKind::Region(ty::BrEnv), |
144 | ]); | |
dc9dc135 | 145 | let mk_va_list_ty = |mutbl| { |
a1dfa0c6 | 146 | tcx.lang_items().va_list().map(|did| { |
9ffffee4 | 147 | let region = tcx.mk_re_late_bound( |
cdc7bbd5 | 148 | ty::INNERMOST, |
353b0b11 | 149 | ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, |
9ffffee4 FG |
150 | ); |
151 | let env_region = tcx.mk_re_late_bound( | |
cdc7bbd5 XL |
152 | ty::INNERMOST, |
153 | ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, | |
9ffffee4 FG |
154 | ); |
155 | let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); | |
fc512014 | 156 | (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) |
a1dfa0c6 XL |
157 | }) |
158 | }; | |
159 | ||
136023e0 | 160 | let (n_tps, n_lts, inputs, output, unsafety) = if name_str.starts_with("atomic_") { |
f035d41b | 161 | let split: Vec<&str> = name_str.split('_').collect(); |
0bf4aa26 | 162 | assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format"); |
e9174d1e SL |
163 | |
164 | //We only care about the operation here | |
165 | let (n_tps, inputs, output) = match split[1] { | |
dfeec247 XL |
166 | "cxchg" | "cxchgweak" => ( |
167 | 1, | |
168 | vec![tcx.mk_mut_ptr(param(0)), param(0), param(0)], | |
9ffffee4 | 169 | tcx.mk_tup(&[param(0), tcx.types.bool]), |
dfeec247 XL |
170 | ), |
171 | "load" => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), | |
172 | "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), | |
173 | ||
174 | "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | |
175 | | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)), | |
176 | "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()), | |
e9174d1e | 177 | op => { |
1b1a35ee | 178 | tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op }); |
e9174d1e SL |
179 | return; |
180 | } | |
181 | }; | |
136023e0 | 182 | (n_tps, 0, inputs, output, hir::Unsafety::Unsafe) |
e9174d1e | 183 | } else { |
2b03887a | 184 | let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id); |
f035d41b XL |
185 | let (n_tps, inputs, output) = match intrinsic_name { |
186 | sym::abort => (0, Vec::new(), tcx.types.never), | |
187 | sym::unreachable => (0, Vec::new(), tcx.types.never), | |
188 | sym::breakpoint => (0, Vec::new(), tcx.mk_unit()), | |
189 | sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { | |
190 | (1, Vec::new(), tcx.types.usize) | |
191 | } | |
192 | sym::size_of_val | sym::min_align_of_val => { | |
ba9703b0 XL |
193 | (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) |
194 | } | |
f035d41b XL |
195 | sym::rustc_peek => (1, vec![param(0)], param(0)), |
196 | sym::caller_location => (0, vec![], tcx.caller_location_ty()), | |
9c376795 FG |
197 | sym::assert_inhabited |
198 | | sym::assert_zero_valid | |
199 | | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()), | |
f035d41b XL |
200 | sym::forget => (1, vec![param(0)], tcx.mk_unit()), |
201 | sym::transmute => (2, vec![param(0)], param(1)), | |
f035d41b XL |
202 | sym::prefetch_read_data |
203 | | sym::prefetch_write_data | |
204 | | sym::prefetch_read_instruction | |
205 | | sym::prefetch_write_instruction => ( | |
dfeec247 XL |
206 | 1, |
207 | vec![ | |
208 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
209 | tcx.types.i32, | |
210 | ], | |
211 | tcx.mk_unit(), | |
212 | ), | |
f035d41b XL |
213 | sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()), |
214 | sym::needs_drop => (1, Vec::new(), tcx.types.bool), | |
e9174d1e | 215 | |
f035d41b XL |
216 | sym::type_name => (1, Vec::new(), tcx.mk_static_str()), |
217 | sym::type_id => (1, Vec::new(), tcx.types.u64), | |
218 | sym::offset | sym::arith_offset => ( | |
dfeec247 XL |
219 | 1, |
220 | vec![ | |
221 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
222 | tcx.types.isize, | |
223 | ], | |
224 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
225 | ), | |
353b0b11 FG |
226 | sym::option_payload_ptr => { |
227 | let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); | |
228 | let p0 = param(0); | |
229 | ( | |
230 | 1, | |
231 | vec![tcx.mk_ptr(ty::TypeAndMut { | |
232 | ty: tcx.mk_adt( | |
233 | tcx.adt_def(option_def_id), | |
234 | tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), | |
235 | ), | |
236 | mutbl: hir::Mutability::Not, | |
237 | })], | |
238 | tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), | |
239 | ) | |
240 | } | |
f2b60f7d FG |
241 | sym::ptr_mask => ( |
242 | 1, | |
243 | vec![ | |
244 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
245 | tcx.types.usize, | |
246 | ], | |
247 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
248 | ), | |
249 | ||
f035d41b | 250 | sym::copy | sym::copy_nonoverlapping => ( |
dfeec247 XL |
251 | 1, |
252 | vec![ | |
253 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
254 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), | |
255 | tcx.types.usize, | |
256 | ], | |
257 | tcx.mk_unit(), | |
258 | ), | |
f035d41b | 259 | sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( |
dfeec247 XL |
260 | 1, |
261 | vec![ | |
262 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), | |
263 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), | |
264 | tcx.types.usize, | |
265 | ], | |
266 | tcx.mk_unit(), | |
267 | ), | |
f035d41b | 268 | sym::write_bytes | sym::volatile_set_memory => ( |
dfeec247 XL |
269 | 1, |
270 | vec![ | |
271 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }), | |
272 | tcx.types.u8, | |
273 | tcx.types.usize, | |
274 | ], | |
275 | tcx.mk_unit(), | |
276 | ), | |
f035d41b XL |
277 | sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32), |
278 | sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
279 | sym::powif32 => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32), | |
280 | sym::powif64 => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64), | |
281 | sym::sinf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
282 | sym::sinf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
283 | sym::cosf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
284 | sym::cosf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
285 | sym::powf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), | |
286 | sym::powf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), | |
287 | sym::expf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
288 | sym::expf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
289 | sym::exp2f32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
290 | sym::exp2f64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
291 | sym::logf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
292 | sym::logf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
293 | sym::log10f32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
294 | sym::log10f64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
295 | sym::log2f32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
296 | sym::log2f64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
297 | sym::fmaf32 => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), | |
298 | sym::fmaf64 => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), | |
299 | sym::fabsf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
300 | sym::fabsf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
301 | sym::minnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), | |
302 | sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), | |
303 | sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), | |
304 | sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), | |
305 | sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), | |
306 | sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), | |
307 | sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
308 | sym::floorf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
309 | sym::ceilf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
310 | sym::ceilf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
311 | sym::truncf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
312 | sym::truncf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
313 | sym::rintf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
314 | sym::rintf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
315 | sym::nearbyintf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
316 | sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
317 | sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32), | |
318 | sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
353b0b11 FG |
319 | sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32), |
320 | sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64), | |
f035d41b XL |
321 | |
322 | sym::volatile_load | sym::unaligned_volatile_load => { | |
dfeec247 | 323 | (1, vec![tcx.mk_imm_ptr(param(0))], param(0)) |
e9174d1e | 324 | } |
f035d41b | 325 | sym::volatile_store | sym::unaligned_volatile_store => { |
dfeec247 | 326 | (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()) |
e9174d1e | 327 | } |
dfeec247 | 328 | |
f035d41b XL |
329 | sym::ctpop |
330 | | sym::ctlz | |
331 | | sym::ctlz_nonzero | |
332 | | sym::cttz | |
333 | | sym::cttz_nonzero | |
334 | | sym::bswap | |
335 | | sym::bitreverse => (1, vec![param(0)], param(0)), | |
dfeec247 | 336 | |
f035d41b | 337 | sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { |
9ffffee4 | 338 | (1, vec![param(0), param(0)], tcx.mk_tup(&[param(0), tcx.types.bool])) |
e9174d1e | 339 | } |
dfeec247 | 340 | |
f2b60f7d FG |
341 | sym::ptr_guaranteed_cmp => { |
342 | (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8) | |
f035d41b XL |
343 | } |
344 | ||
fc512014 XL |
345 | sym::const_allocate => { |
346 | (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) | |
347 | } | |
5099ac24 FG |
348 | sym::const_deallocate => ( |
349 | 0, | |
350 | vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize], | |
351 | tcx.mk_unit(), | |
352 | ), | |
fc512014 | 353 | |
f035d41b | 354 | sym::ptr_offset_from => { |
dfeec247 | 355 | (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) |
e9174d1e | 356 | } |
04454e1e FG |
357 | sym::ptr_offset_from_unsigned => { |
358 | (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.usize) | |
359 | } | |
f035d41b | 360 | sym::unchecked_div | sym::unchecked_rem | sym::exact_div => { |
dfeec247 | 361 | (1, vec![param(0), param(0)], param(0)) |
e9174d1e | 362 | } |
f035d41b | 363 | sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => { |
dfeec247 | 364 | (1, vec![param(0), param(0)], param(0)) |
e9174d1e | 365 | } |
f035d41b | 366 | sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { |
dfeec247 | 367 | (1, vec![param(0), param(0)], param(0)) |
e9174d1e | 368 | } |
f035d41b | 369 | sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { |
dfeec247 | 370 | (1, vec![param(0), param(0)], param(0)) |
e9174d1e | 371 | } |
f035d41b XL |
372 | sym::saturating_add | sym::saturating_sub => (1, vec![param(0), param(0)], param(0)), |
373 | sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { | |
dfeec247 | 374 | (1, vec![param(0), param(0)], param(0)) |
e9174d1e | 375 | } |
f035d41b | 376 | sym::float_to_int_unchecked => (2, vec![param(0)], param(1)), |
e9174d1e | 377 | |
f035d41b XL |
378 | sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()), |
379 | sym::likely => (0, vec![tcx.types.bool], tcx.types.bool), | |
380 | sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), | |
e9174d1e | 381 | |
353b0b11 FG |
382 | sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), |
383 | ||
f035d41b | 384 | sym::discriminant_value => { |
3c0e092e XL |
385 | let assoc_items = tcx.associated_item_def_ids( |
386 | tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), | |
387 | ); | |
388 | let discriminant_def_id = assoc_items[0]; | |
f9f354fc | 389 | |
353b0b11 | 390 | let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; |
f9f354fc XL |
391 | ( |
392 | 1, | |
9ffffee4 FG |
393 | vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], |
394 | tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])), | |
f9f354fc XL |
395 | ) |
396 | } | |
e9174d1e | 397 | |
f035d41b | 398 | kw::Try => { |
e9174d1e | 399 | let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); |
29967ef6 | 400 | let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( |
9ffffee4 | 401 | [mut_u8], |
b7449926 | 402 | tcx.mk_unit(), |
8bb4bdeb XL |
403 | false, |
404 | hir::Unsafety::Normal, | |
405 | Abi::Rust, | |
406 | )); | |
29967ef6 | 407 | let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( |
9ffffee4 | 408 | [mut_u8, mut_u8], |
ba9703b0 XL |
409 | tcx.mk_unit(), |
410 | false, | |
411 | hir::Unsafety::Normal, | |
412 | Abi::Rust, | |
413 | )); | |
414 | ( | |
415 | 0, | |
416 | vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)], | |
417 | tcx.types.i32, | |
418 | ) | |
e9174d1e SL |
419 | } |
420 | ||
f035d41b | 421 | sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { |
dfeec247 XL |
422 | Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), |
423 | None => bug!("`va_list` language item needed for C-variadic intrinsics"), | |
424 | }, | |
a1dfa0c6 | 425 | |
f035d41b | 426 | sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { |
dfeec247 XL |
427 | Some((va_list_ref_ty, va_list_ty)) => { |
428 | let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); | |
429 | (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) | |
a1dfa0c6 | 430 | } |
dfeec247 XL |
431 | None => bug!("`va_list` language item needed for C-variadic intrinsics"), |
432 | }, | |
a1dfa0c6 | 433 | |
f035d41b | 434 | sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) { |
dfeec247 XL |
435 | Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)), |
436 | None => bug!("`va_list` language item needed for C-variadic intrinsics"), | |
437 | }, | |
a1dfa0c6 | 438 | |
f035d41b | 439 | sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), |
ff7c6d11 | 440 | |
136023e0 | 441 | sym::raw_eq => { |
353b0b11 | 442 | let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; |
9ffffee4 | 443 | let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); |
136023e0 XL |
444 | (1, vec![param_ty; 2], tcx.types.bool) |
445 | } | |
446 | ||
94222f64 XL |
447 | sym::black_box => (1, vec![param(0)], param(0)), |
448 | ||
c295e0f8 XL |
449 | sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), |
450 | ||
064997fb FG |
451 | sym::vtable_size | sym::vtable_align => { |
452 | (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) | |
453 | } | |
454 | ||
f035d41b | 455 | other => { |
1b1a35ee | 456 | tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); |
e9174d1e SL |
457 | return; |
458 | } | |
459 | }; | |
136023e0 | 460 | (n_tps, 0, inputs, output, unsafety) |
e9174d1e | 461 | }; |
9ffffee4 | 462 | let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic); |
cdc7bbd5 | 463 | let sig = ty::Binder::bind_with_vars(sig, bound_vars); |
136023e0 | 464 | equate_intrinsic_type(tcx, it, n_tps, n_lts, sig) |
e9174d1e SL |
465 | } |
466 | ||
467 | /// Type-check `extern "platform-intrinsic" { ... }` functions. | |
dfeec247 | 468 | pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { |
e9174d1e | 469 | let param = |n| { |
e74abb32 | 470 | let name = Symbol::intern(&format!("P{}", n)); |
94b46f34 | 471 | tcx.mk_ty_param(n, name) |
e9174d1e SL |
472 | }; |
473 | ||
3dfed10e | 474 | let name = it.ident.name; |
e9174d1e | 475 | |
3dfed10e XL |
476 | let (n_tps, inputs, output) = match name { |
477 | sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => { | |
e9174d1e SL |
478 | (2, vec![param(0), param(0)], param(1)) |
479 | } | |
3dfed10e XL |
480 | sym::simd_add |
481 | | sym::simd_sub | |
482 | | sym::simd_mul | |
483 | | sym::simd_rem | |
484 | | sym::simd_div | |
485 | | sym::simd_shl | |
486 | | sym::simd_shr | |
487 | | sym::simd_and | |
488 | | sym::simd_or | |
489 | | sym::simd_xor | |
490 | | sym::simd_fmin | |
491 | | sym::simd_fmax | |
492 | | sym::simd_fpow | |
493 | | sym::simd_saturating_add | |
494 | | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)), | |
04454e1e | 495 | sym::simd_arith_offset => (2, vec![param(0), param(1)], param(0)), |
cdc7bbd5 XL |
496 | sym::simd_neg |
497 | | sym::simd_fsqrt | |
3dfed10e XL |
498 | | sym::simd_fsin |
499 | | sym::simd_fcos | |
500 | | sym::simd_fexp | |
501 | | sym::simd_fexp2 | |
502 | | sym::simd_flog2 | |
503 | | sym::simd_flog10 | |
504 | | sym::simd_flog | |
505 | | sym::simd_fabs | |
cdc7bbd5 | 506 | | sym::simd_ceil |
3dfed10e | 507 | | sym::simd_floor |
cdc7bbd5 XL |
508 | | sym::simd_round |
509 | | sym::simd_trunc => (1, vec![param(0)], param(0)), | |
3dfed10e XL |
510 | sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)), |
511 | sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)), | |
512 | sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)), | |
513 | sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), | |
514 | sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), | |
515 | sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), | |
f2b60f7d FG |
516 | sym::simd_cast |
517 | | sym::simd_as | |
518 | | sym::simd_cast_ptr | |
519 | | sym::simd_expose_addr | |
520 | | sym::simd_from_exposed_addr => (2, vec![param(0)], param(1)), | |
3dfed10e XL |
521 | sym::simd_bitmask => (2, vec![param(0)], param(1)), |
522 | sym::simd_select | sym::simd_select_bitmask => { | |
523 | (2, vec![param(0), param(1), param(1)], param(1)) | |
94b46f34 | 524 | } |
3dfed10e XL |
525 | sym::simd_reduce_all | sym::simd_reduce_any => (1, vec![param(0)], tcx.types.bool), |
526 | sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { | |
dfeec247 | 527 | (2, vec![param(0), param(1)], param(1)) |
e9174d1e | 528 | } |
3dfed10e XL |
529 | sym::simd_reduce_add_unordered |
530 | | sym::simd_reduce_mul_unordered | |
531 | | sym::simd_reduce_and | |
532 | | sym::simd_reduce_or | |
533 | | sym::simd_reduce_xor | |
534 | | sym::simd_reduce_min | |
535 | | sym::simd_reduce_max | |
536 | | sym::simd_reduce_min_nanless | |
537 | | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)), | |
c295e0f8 | 538 | sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)), |
3dfed10e XL |
539 | name if name.as_str().starts_with("simd_shuffle") => { |
540 | match name.as_str()["simd_shuffle".len()..].parse() { | |
541 | Ok(n) => { | |
542 | let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)]; | |
543 | (2, params, param(1)) | |
544 | } | |
545 | Err(_) => { | |
c295e0f8 | 546 | let msg = |
04454e1e | 547 | format!("unrecognized platform-specific intrinsic function: `{name}`"); |
c295e0f8 | 548 | tcx.sess.struct_span_err(it.span, &msg).emit(); |
3dfed10e XL |
549 | return; |
550 | } | |
dfeec247 | 551 | } |
3dfed10e | 552 | } |
e9174d1e | 553 | _ => { |
04454e1e | 554 | let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); |
dfeec247 | 555 | tcx.sess.struct_span_err(it.span, &msg).emit(); |
0731742a | 556 | return; |
e9174d1e SL |
557 | } |
558 | }; | |
559 | ||
9ffffee4 | 560 | let sig = tcx.mk_fn_sig(inputs, output, false, hir::Unsafety::Unsafe, Abi::PlatformIntrinsic); |
fc512014 | 561 | let sig = ty::Binder::dummy(sig); |
136023e0 | 562 | equate_intrinsic_type(tcx, it, n_tps, 0, sig) |
e9174d1e | 563 | } |