1 //! Type-checking for the rust-intrinsic and platform-intrinsic
2 //! intrinsics that the compiler exposes.
4 use rustc::middle::lang_items::PanicLocationLangItem;
5 use rustc::traits::{ObligationCause, ObligationCauseCode};
6 use rustc::ty::{self, TyCtxt, Ty};
7 use rustc::ty::subst::Subst;
8 use crate::require_same_types;
10 use rustc_target::spec::abi::Abi;
11 use syntax::symbol::Symbol;
17 fn equate_intrinsic_type<'tcx>(
19 it: &hir::ForeignItem,
22 safety: hir::Unsafety,
23 inputs: Vec<Ty<'tcx>>,
26 let def_id = tcx.hir().local_def_id(it.hir_id);
29 hir::ForeignItemKind::Fn(..) => {}
31 struct_span_err!(tcx.sess, it.span, E0622,
32 "intrinsic must be a function")
33 .span_label(it.span, "expected a function")
39 let i_n_tps = tcx.generics_of(def_id).own_counts().types;
41 let span = match it.kind {
42 hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span,
46 struct_span_err!(tcx.sess, span, E0094,
47 "intrinsic has wrong number of type \
48 parameters: found {}, expected {}",
50 .span_label(span, format!("expected {} type parameter", n_tps))
55 let fty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
62 let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType);
63 require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty);
66 /// Returns `true` if the given intrinsic is unsafe to call or not.
67 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
69 "size_of" | "min_align_of" | "needs_drop" | "caller_location" |
70 "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
71 "wrapping_add" | "wrapping_sub" | "wrapping_mul" |
72 "saturating_add" | "saturating_sub" |
73 "rotate_left" | "rotate_right" |
74 "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" |
75 "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name"
76 => hir::Unsafety::Normal,
77 _ => hir::Unsafety::Unsafe,
81 /// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs,
82 /// and in libcore/intrinsics.rs
83 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
84 let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
85 let name = it.ident.as_str();
87 let mk_va_list_ty = |mutbl| {
88 tcx.lang_items().va_list().map(|did| {
89 let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0)));
90 let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
91 let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]);
92 (tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut {
99 let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
100 let split : Vec<&str> = name.split('_').collect();
101 assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
103 //We only care about the operation here
104 let (n_tps, inputs, output) = match split[1] {
105 "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
108 tcx.intern_tup(&[param(0), tcx.types.bool])),
109 "load" => (1, vec![tcx.mk_imm_ptr(param(0))],
111 "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
114 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
115 "min" | "umax" | "umin" => {
116 (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
119 "fence" | "singlethreadfence" => {
120 (0, Vec::new(), tcx.mk_unit())
123 struct_span_err!(tcx.sess, it.span, E0092,
124 "unrecognized atomic operation function: `{}`", op)
125 .span_label(it.span, "unrecognized atomic operation")
130 (n_tps, inputs, output, hir::Unsafety::Unsafe)
131 } else if &name[..] == "abort" || &name[..] == "unreachable" {
132 (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
134 let unsafety = intrinsic_operation_unsafety(&name[..]);
135 let (n_tps, inputs, output) = match &name[..] {
136 "breakpoint" => (0, Vec::new(), tcx.mk_unit()),
138 "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
139 "size_of_val" | "min_align_of_val" => {
141 tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
146 "rustc_peek" => (1, vec![param(0)], param(0)),
147 "caller_location" => (
151 tcx.lifetimes.re_static,
152 tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
153 .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
156 "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
157 "init" => (1, Vec::new(), param(0)),
158 "uninit" => (1, Vec::new(), param(0)),
159 "forget" => (1, vec![param(0)], tcx.mk_unit()),
160 "transmute" => (2, vec![ param(0) ], param(1)),
164 tcx.mk_mut_ptr(param(0)),
169 "prefetch_read_data" | "prefetch_write_data" |
170 "prefetch_read_instruction" | "prefetch_write_instruction" => {
171 (1, vec![tcx.mk_ptr(ty::TypeAndMut {
173 mutbl: hir::MutImmutable
178 (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit())
180 "needs_drop" => (1, Vec::new(), tcx.types.bool),
182 "type_name" => (1, Vec::new(), tcx.mk_static_str()),
183 "type_id" => (1, Vec::new(), tcx.types.u64),
184 "offset" | "arith_offset" => {
187 tcx.mk_ptr(ty::TypeAndMut {
189 mutbl: hir::MutImmutable
193 tcx.mk_ptr(ty::TypeAndMut {
195 mutbl: hir::MutImmutable
198 "copy" | "copy_nonoverlapping" => {
201 tcx.mk_ptr(ty::TypeAndMut {
203 mutbl: hir::MutImmutable
205 tcx.mk_ptr(ty::TypeAndMut {
207 mutbl: hir::MutMutable
213 "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => {
216 tcx.mk_ptr(ty::TypeAndMut {
218 mutbl: hir::MutMutable
220 tcx.mk_ptr(ty::TypeAndMut {
222 mutbl: hir::MutImmutable
228 "write_bytes" | "volatile_set_memory" => {
231 tcx.mk_ptr(ty::TypeAndMut {
233 mutbl: hir::MutMutable
240 "sqrtf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
241 "sqrtf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
244 vec![ tcx.types.f32, tcx.types.i32 ],
249 vec![ tcx.types.f64, tcx.types.i32 ],
252 "sinf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
253 "sinf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
254 "cosf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
255 "cosf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
258 vec![ tcx.types.f32, tcx.types.f32 ],
263 vec![ tcx.types.f64, tcx.types.f64 ],
266 "expf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
267 "expf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
268 "exp2f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
269 "exp2f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
270 "logf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
271 "logf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
272 "log10f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
273 "log10f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
274 "log2f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
275 "log2f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
278 vec![ tcx.types.f32, tcx.types.f32, tcx.types.f32 ],
283 vec![ tcx.types.f64, tcx.types.f64, tcx.types.f64 ],
286 "fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
287 "fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
288 "minnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
289 "minnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
290 "maxnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
291 "maxnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
292 "copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
293 "copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
294 "floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
295 "floorf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
296 "ceilf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
297 "ceilf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
298 "truncf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
299 "truncf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
300 "rintf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
301 "rintf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
302 "nearbyintf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
303 "nearbyintf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
304 "roundf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
305 "roundf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
307 "volatile_load" | "unaligned_volatile_load" =>
308 (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)),
309 "volatile_store" | "unaligned_volatile_store" =>
310 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_unit()),
312 "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" |
313 "bswap" | "bitreverse" =>
314 (1, vec![param(0)], param(0)),
316 "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>
317 (1, vec![param(0), param(0)],
318 tcx.intern_tup(&[param(0), tcx.types.bool])),
321 (1, vec![ tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0)) ], tcx.types.isize),
322 "unchecked_div" | "unchecked_rem" | "exact_div" =>
323 (1, vec![param(0), param(0)], param(0)),
324 "unchecked_shl" | "unchecked_shr" |
325 "rotate_left" | "rotate_right" =>
326 (1, vec![param(0), param(0)], param(0)),
327 "unchecked_add" | "unchecked_sub" | "unchecked_mul" =>
328 (1, vec![param(0), param(0)], param(0)),
329 "wrapping_add" | "wrapping_sub" | "wrapping_mul" =>
330 (1, vec![param(0), param(0)], param(0)),
331 "saturating_add" | "saturating_sub" =>
332 (1, vec![param(0), param(0)], param(0)),
333 "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
334 (1, vec![param(0), param(0)], param(0)),
336 "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
337 "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
338 "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
340 "discriminant_value" => (1, vec![
341 tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
343 param(0))], tcx.types.u64),
346 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
347 let fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
351 hir::Unsafety::Normal,
354 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
357 "va_start" | "va_end" => {
358 match mk_va_list_ty(hir::MutMutable) {
359 Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()),
360 None => bug!("`va_list` language item needed for C-variadic intrinsics")
365 match mk_va_list_ty(hir::MutImmutable) {
366 Some((va_list_ref_ty, va_list_ty)) => {
367 let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty);
368 (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit())
370 None => bug!("`va_list` language item needed for C-variadic intrinsics")
375 match mk_va_list_ty(hir::MutMutable) {
376 Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)),
377 None => bug!("`va_list` language item needed for C-variadic intrinsics")
381 "nontemporal_store" => {
382 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_unit())
386 struct_span_err!(tcx.sess, it.span, E0093,
387 "unrecognized intrinsic function: `{}`",
389 .span_label(it.span, "unrecognized intrinsic")
394 (n_tps, inputs, output, unsafety)
396 equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
399 /// Type-check `extern "platform-intrinsic" { ... }` functions.
400 pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
402 let name = Symbol::intern(&format!("P{}", n));
403 tcx.mk_ty_param(n, name)
406 let name = it.ident.as_str();
408 let (n_tps, inputs, output) = match &*name {
409 "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
410 (2, vec![param(0), param(0)], param(1))
412 "simd_add" | "simd_sub" | "simd_mul" | "simd_rem" |
413 "simd_div" | "simd_shl" | "simd_shr" |
414 "simd_and" | "simd_or" | "simd_xor" |
415 "simd_fmin" | "simd_fmax" | "simd_fpow" |
416 "simd_saturating_add" | "simd_saturating_sub" => {
417 (1, vec![param(0), param(0)], param(0))
419 "simd_fsqrt" | "simd_fsin" | "simd_fcos" | "simd_fexp" | "simd_fexp2" |
420 "simd_flog2" | "simd_flog10" | "simd_flog" |
421 "simd_fabs" | "simd_floor" | "simd_ceil" => {
422 (1, vec![param(0)], param(0))
425 (1, vec![param(0), tcx.types.i32], param(0))
428 (1, vec![param(0), param(0), param(0)], param(0))
431 (3, vec![param(0), param(1), param(2)], param(0))
434 (3, vec![param(0), param(1), param(2)], tcx.mk_unit())
436 "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
437 "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
438 "simd_cast" => (2, vec![param(0)], param(1)),
439 "simd_bitmask" => (2, vec![param(0)], param(1)),
441 "simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)),
442 "simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
443 "simd_reduce_add_ordered" | "simd_reduce_mul_ordered"
444 => (2, vec![param(0), param(1)], param(1)),
445 "simd_reduce_add_unordered" | "simd_reduce_mul_unordered" |
446 "simd_reduce_and" | "simd_reduce_or" | "simd_reduce_xor" |
447 "simd_reduce_min" | "simd_reduce_max" |
448 "simd_reduce_min_nanless" | "simd_reduce_max_nanless"
449 => (2, vec![param(0)], param(1)),
450 name if name.starts_with("simd_shuffle") => {
451 match name["simd_shuffle".len()..].parse() {
453 let params = vec![param(0), param(0),
454 tcx.mk_array(tcx.types.u32, n)];
455 (2, params, param(1))
458 span_err!(tcx.sess, it.span, E0439,
459 "invalid `simd_shuffle`, needs length: `{}`", name);
465 let msg = format!("unrecognized platform-specific intrinsic function: `{}`", name);
466 tcx.sess.span_err(it.span, &msg);
471 equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe,