]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/intrinsic.rs
Add note to src/ci/docker/README.md about multiple docker images
[rust.git] / src / librustc_typeck / check / intrinsic.rs
1 //! Type-checking for the rust-intrinsic and platform-intrinsic
2 //! intrinsics that the compiler exposes.
3
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;
9
10 use rustc_target::spec::abi::Abi;
11 use syntax::symbol::Symbol;
12
13 use rustc::hir;
14
15 use rustc_error_codes::*;
16
17 use std::iter;
18
19 fn equate_intrinsic_type<'tcx>(
20     tcx: TyCtxt<'tcx>,
21     it: &hir::ForeignItem,
22     n_tps: usize,
23     abi: Abi,
24     safety: hir::Unsafety,
25     inputs: Vec<Ty<'tcx>>,
26     output: Ty<'tcx>,
27 ) {
28     let def_id = tcx.hir().local_def_id(it.hir_id);
29
30     match it.kind {
31         hir::ForeignItemKind::Fn(..) => {}
32         _ => {
33             struct_span_err!(tcx.sess, it.span, E0622,
34                              "intrinsic must be a function")
35                 .span_label(it.span, "expected a function")
36                 .emit();
37             return;
38         }
39     }
40
41     let i_n_tps = tcx.generics_of(def_id).own_counts().types;
42     if i_n_tps != n_tps {
43         let span = match it.kind {
44             hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span,
45             _ => bug!()
46         };
47
48         struct_span_err!(tcx.sess, span, E0094,
49                         "intrinsic has wrong number of type \
50                          parameters: found {}, expected {}",
51                         i_n_tps, n_tps)
52             .span_label(span, format!("expected {} type parameter", n_tps))
53             .emit();
54         return;
55     }
56
57     let fty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
58         inputs.into_iter(),
59         output,
60         false,
61         safety,
62         abi
63     )));
64     let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType);
65     require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty);
66 }
67
68 /// Returns `true` if the given intrinsic is unsafe to call or not.
69 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
70     match intrinsic {
71         "size_of" | "min_align_of" | "needs_drop" | "caller_location" |
72         "size_of_val" | "min_align_of_val" |
73         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
74         "wrapping_add" | "wrapping_sub" | "wrapping_mul" |
75         "saturating_add" | "saturating_sub" |
76         "rotate_left" | "rotate_right" |
77         "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" |
78         "discriminant_value" | "type_id" | "likely" | "unlikely" |
79         "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name"
80         => hir::Unsafety::Normal,
81         _ => hir::Unsafety::Unsafe,
82     }
83 }
84
85 /// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs,
86 /// and in libcore/intrinsics.rs
87 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
88     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
89     let name = it.ident.as_str();
90
91     let mk_va_list_ty = |mutbl| {
92         tcx.lang_items().va_list().map(|did| {
93             let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0)));
94             let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
95             let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]);
96             (tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut {
97                 ty: va_list_ty,
98                 mutbl
99             }), va_list_ty)
100         })
101     };
102
103     let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
104         let split : Vec<&str> = name.split('_').collect();
105         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
106
107         //We only care about the operation here
108         let (n_tps, inputs, output) = match split[1] {
109             "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
110                                               param(0),
111                                               param(0)],
112                                       tcx.intern_tup(&[param(0), tcx.types.bool])),
113             "load" => (1, vec![tcx.mk_imm_ptr(param(0))],
114                        param(0)),
115             "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
116                         tcx.mk_unit()),
117
118             "xchg" | "xadd" | "xsub" | "and"  | "nand" | "or" | "xor" | "max" |
119             "min"  | "umax" | "umin" => {
120                 (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
121                  param(0))
122             }
123             "fence" | "singlethreadfence" => {
124                 (0, Vec::new(), tcx.mk_unit())
125             }
126             op => {
127                 struct_span_err!(tcx.sess, it.span, E0092,
128                       "unrecognized atomic operation function: `{}`", op)
129                   .span_label(it.span, "unrecognized atomic operation")
130                   .emit();
131                 return;
132             }
133         };
134         (n_tps, inputs, output, hir::Unsafety::Unsafe)
135     } else if &name[..] == "abort" || &name[..] == "unreachable" {
136         (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
137     } else {
138         let unsafety = intrinsic_operation_unsafety(&name[..]);
139         let (n_tps, inputs, output) = match &name[..] {
140             "breakpoint" => (0, Vec::new(), tcx.mk_unit()),
141             "size_of" |
142             "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
143             "size_of_val" |  "min_align_of_val" => {
144                 (1, vec![
145                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
146                                                                  ty::BrAnon(0))),
147                                    param(0))
148                  ], tcx.types.usize)
149             }
150             "rustc_peek" => (1, vec![param(0)], param(0)),
151             "caller_location" => (
152                 0,
153                 vec![],
154                 tcx.mk_imm_ref(
155                     tcx.lifetimes.re_static,
156                     tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
157                         .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
158                 ),
159             ),
160             "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
161             "init" => (1, Vec::new(), param(0)),
162             "uninit" => (1, Vec::new(), param(0)),
163             "forget" => (1, vec![param(0)], tcx.mk_unit()),
164             "transmute" => (2, vec![ param(0) ], param(1)),
165             "move_val_init" => {
166                 (1,
167                  vec![
168                     tcx.mk_mut_ptr(param(0)),
169                     param(0)
170                   ],
171                tcx.mk_unit())
172             }
173             "prefetch_read_data" | "prefetch_write_data" |
174             "prefetch_read_instruction" | "prefetch_write_instruction" => {
175                 (1, vec![tcx.mk_ptr(ty::TypeAndMut {
176                           ty: param(0),
177                           mutbl: hir::Mutability::Immutable
178                          }), tcx.types.i32],
179                     tcx.mk_unit())
180             }
181             "drop_in_place" => {
182                 (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit())
183             }
184             "needs_drop" => (1, Vec::new(), tcx.types.bool),
185
186             "type_name" => (1, Vec::new(), tcx.mk_static_str()),
187             "type_id" => (1, Vec::new(), tcx.types.u64),
188             "offset" | "arith_offset" => {
189               (1,
190                vec![
191                   tcx.mk_ptr(ty::TypeAndMut {
192                       ty: param(0),
193                       mutbl: hir::Mutability::Immutable
194                   }),
195                   tcx.types.isize
196                ],
197                tcx.mk_ptr(ty::TypeAndMut {
198                    ty: param(0),
199                    mutbl: hir::Mutability::Immutable
200                }))
201             }
202             "copy" | "copy_nonoverlapping" => {
203               (1,
204                vec![
205                   tcx.mk_ptr(ty::TypeAndMut {
206                       ty: param(0),
207                       mutbl: hir::Mutability::Immutable
208                   }),
209                   tcx.mk_ptr(ty::TypeAndMut {
210                       ty: param(0),
211                       mutbl: hir::Mutability::Mutable
212                   }),
213                   tcx.types.usize,
214                ],
215                tcx.mk_unit())
216             }
217             "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => {
218               (1,
219                vec![
220                   tcx.mk_ptr(ty::TypeAndMut {
221                       ty: param(0),
222                       mutbl: hir::Mutability::Mutable
223                   }),
224                   tcx.mk_ptr(ty::TypeAndMut {
225                       ty: param(0),
226                       mutbl: hir::Mutability::Immutable
227                   }),
228                   tcx.types.usize,
229                ],
230                tcx.mk_unit())
231             }
232             "write_bytes" | "volatile_set_memory" => {
233               (1,
234                vec![
235                   tcx.mk_ptr(ty::TypeAndMut {
236                       ty: param(0),
237                       mutbl: hir::Mutability::Mutable
238                   }),
239                   tcx.types.u8,
240                   tcx.types.usize,
241                ],
242                tcx.mk_unit())
243             }
244             "sqrtf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
245             "sqrtf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
246             "powif32" => {
247                (0,
248                 vec![ tcx.types.f32, tcx.types.i32 ],
249                 tcx.types.f32)
250             }
251             "powif64" => {
252                (0,
253                 vec![ tcx.types.f64, tcx.types.i32 ],
254                 tcx.types.f64)
255             }
256             "sinf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
257             "sinf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
258             "cosf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
259             "cosf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
260             "powf32" => {
261                (0,
262                 vec![ tcx.types.f32, tcx.types.f32 ],
263                 tcx.types.f32)
264             }
265             "powf64" => {
266                (0,
267                 vec![ tcx.types.f64, tcx.types.f64 ],
268                 tcx.types.f64)
269             }
270             "expf32"   => (0, vec![ tcx.types.f32 ], tcx.types.f32),
271             "expf64"   => (0, vec![ tcx.types.f64 ], tcx.types.f64),
272             "exp2f32"  => (0, vec![ tcx.types.f32 ], tcx.types.f32),
273             "exp2f64"  => (0, vec![ tcx.types.f64 ], tcx.types.f64),
274             "logf32"   => (0, vec![ tcx.types.f32 ], tcx.types.f32),
275             "logf64"   => (0, vec![ tcx.types.f64 ], tcx.types.f64),
276             "log10f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
277             "log10f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
278             "log2f32"  => (0, vec![ tcx.types.f32 ], tcx.types.f32),
279             "log2f64"  => (0, vec![ tcx.types.f64 ], tcx.types.f64),
280             "fmaf32" => {
281                 (0,
282                  vec![ tcx.types.f32, tcx.types.f32, tcx.types.f32 ],
283                  tcx.types.f32)
284             }
285             "fmaf64" => {
286                 (0,
287                  vec![ tcx.types.f64, tcx.types.f64, tcx.types.f64 ],
288                  tcx.types.f64)
289             }
290             "fabsf32"      => (0, vec![ tcx.types.f32 ], tcx.types.f32),
291             "fabsf64"      => (0, vec![ tcx.types.f64 ], tcx.types.f64),
292             "minnumf32"    => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
293             "minnumf64"    => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
294             "maxnumf32"    => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
295             "maxnumf64"    => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
296             "copysignf32"  => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
297             "copysignf64"  => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
298             "floorf32"     => (0, vec![ tcx.types.f32 ], tcx.types.f32),
299             "floorf64"     => (0, vec![ tcx.types.f64 ], tcx.types.f64),
300             "ceilf32"      => (0, vec![ tcx.types.f32 ], tcx.types.f32),
301             "ceilf64"      => (0, vec![ tcx.types.f64 ], tcx.types.f64),
302             "truncf32"     => (0, vec![ tcx.types.f32 ], tcx.types.f32),
303             "truncf64"     => (0, vec![ tcx.types.f64 ], tcx.types.f64),
304             "rintf32"      => (0, vec![ tcx.types.f32 ], tcx.types.f32),
305             "rintf64"      => (0, vec![ tcx.types.f64 ], tcx.types.f64),
306             "nearbyintf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
307             "nearbyintf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
308             "roundf32"     => (0, vec![ tcx.types.f32 ], tcx.types.f32),
309             "roundf64"     => (0, vec![ tcx.types.f64 ], tcx.types.f64),
310
311             "volatile_load" | "unaligned_volatile_load" =>
312                 (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)),
313             "volatile_store" | "unaligned_volatile_store" =>
314                 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_unit()),
315
316             "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" |
317             "bswap" | "bitreverse" =>
318                 (1, vec![param(0)], param(0)),
319
320             "add_with_overflow" | "sub_with_overflow"  | "mul_with_overflow" =>
321                 (1, vec![param(0), param(0)],
322                 tcx.intern_tup(&[param(0), tcx.types.bool])),
323
324             "ptr_offset_from" =>
325                 (1, vec![ tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0)) ], tcx.types.isize),
326             "unchecked_div" | "unchecked_rem" | "exact_div" =>
327                 (1, vec![param(0), param(0)], param(0)),
328             "unchecked_shl" | "unchecked_shr" |
329             "rotate_left" | "rotate_right" =>
330                 (1, vec![param(0), param(0)], param(0)),
331             "unchecked_add" | "unchecked_sub" | "unchecked_mul" =>
332                 (1, vec![param(0), param(0)], param(0)),
333             "wrapping_add" | "wrapping_sub" | "wrapping_mul" =>
334                 (1, vec![param(0), param(0)], param(0)),
335             "saturating_add" | "saturating_sub" =>
336                 (1, vec![param(0), param(0)], param(0)),
337             "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
338                 (1, vec![param(0), param(0)], param(0)),
339
340             "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
341             "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
342             "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
343
344             "discriminant_value" => (1, vec![
345                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
346                                                                  ty::BrAnon(0))),
347                                    param(0))], tcx.types.u64),
348
349             "try" => {
350                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
351                 let fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
352                     iter::once(mut_u8),
353                     tcx.mk_unit(),
354                     false,
355                     hir::Unsafety::Normal,
356                     Abi::Rust,
357                 ));
358                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
359             }
360
361             "va_start" | "va_end" => {
362                 match mk_va_list_ty(hir::Mutability::Mutable) {
363                     Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()),
364                     None => bug!("`va_list` language item needed for C-variadic intrinsics")
365                 }
366             }
367
368             "va_copy" => {
369                 match mk_va_list_ty(hir::Mutability::Immutable) {
370                     Some((va_list_ref_ty, va_list_ty)) => {
371                         let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty);
372                         (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit())
373                     }
374                     None => bug!("`va_list` language item needed for C-variadic intrinsics")
375                 }
376             }
377
378             "va_arg" => {
379                 match mk_va_list_ty(hir::Mutability::Mutable) {
380                     Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)),
381                     None => bug!("`va_list` language item needed for C-variadic intrinsics")
382                 }
383             }
384
385             "nontemporal_store" => {
386                 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_unit())
387             }
388
389             "miri_start_panic" => {
390                 // FIXME - the relevant types aren't lang items,
391                 // so it's not trivial to check this
392                 return;
393             }
394
395             ref other => {
396                 struct_span_err!(tcx.sess, it.span, E0093,
397                                  "unrecognized intrinsic function: `{}`",
398                                  *other)
399                                  .span_label(it.span, "unrecognized intrinsic")
400                                  .emit();
401                 return;
402             }
403         };
404         (n_tps, inputs, output, unsafety)
405     };
406     equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
407 }
408
409 /// Type-check `extern "platform-intrinsic" { ... }` functions.
410 pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
411     let param = |n| {
412         let name = Symbol::intern(&format!("P{}", n));
413         tcx.mk_ty_param(n, name)
414     };
415
416     let name = it.ident.as_str();
417
418     let (n_tps, inputs, output) = match &*name {
419         "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
420             (2, vec![param(0), param(0)], param(1))
421         }
422         "simd_add" | "simd_sub" | "simd_mul" | "simd_rem" |
423         "simd_div" | "simd_shl" | "simd_shr" |
424         "simd_and" | "simd_or" | "simd_xor" |
425         "simd_fmin" | "simd_fmax" | "simd_fpow" |
426         "simd_saturating_add" | "simd_saturating_sub" => {
427             (1, vec![param(0), param(0)], param(0))
428         }
429         "simd_fsqrt" | "simd_fsin" | "simd_fcos" | "simd_fexp" | "simd_fexp2" |
430         "simd_flog2" | "simd_flog10" | "simd_flog" |
431         "simd_fabs" | "simd_floor" | "simd_ceil" => {
432             (1, vec![param(0)], param(0))
433         }
434         "simd_fpowi" => {
435             (1, vec![param(0), tcx.types.i32], param(0))
436         }
437         "simd_fma" => {
438             (1, vec![param(0), param(0), param(0)], param(0))
439         }
440         "simd_gather" => {
441             (3, vec![param(0), param(1), param(2)], param(0))
442         }
443         "simd_scatter" => {
444             (3, vec![param(0), param(1), param(2)], tcx.mk_unit())
445         }
446         "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
447         "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
448         "simd_cast" => (2, vec![param(0)], param(1)),
449         "simd_bitmask" => (2, vec![param(0)], param(1)),
450         "simd_select" |
451         "simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)),
452         "simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
453         "simd_reduce_add_ordered" | "simd_reduce_mul_ordered"
454             => (2, vec![param(0), param(1)], param(1)),
455         "simd_reduce_add_unordered" | "simd_reduce_mul_unordered" |
456         "simd_reduce_and" | "simd_reduce_or"  | "simd_reduce_xor" |
457         "simd_reduce_min" | "simd_reduce_max" |
458         "simd_reduce_min_nanless" | "simd_reduce_max_nanless"
459             => (2, vec![param(0)], param(1)),
460         name if name.starts_with("simd_shuffle") => {
461             match name["simd_shuffle".len()..].parse() {
462                 Ok(n) => {
463                     let params = vec![param(0), param(0),
464                                       tcx.mk_array(tcx.types.u32, n)];
465                     (2, params, param(1))
466                 }
467                 Err(_) => {
468                     span_err!(tcx.sess, it.span, E0439,
469                               "invalid `simd_shuffle`, needs length: `{}`", name);
470                     return
471                 }
472             }
473         }
474         _ => {
475             let msg = format!("unrecognized platform-specific intrinsic function: `{}`", name);
476             tcx.sess.span_err(it.span, &msg);
477             return;
478         }
479     };
480
481     equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe,
482                           inputs, output)
483 }