1 //! Type-checking for the rust-intrinsic and platform-intrinsic
2 //! intrinsics that the compiler exposes.
5 SimdShuffleMissingLength
, UnrecognizedAtomicOperation
, UnrecognizedIntrinsicFunction
,
6 WrongNumberOfTypeArgumentsToInstrinsic
,
8 use crate::require_same_types
;
10 use rustc_errors
::struct_span_err
;
12 use rustc_hir
::def_id
::DefId
;
13 use rustc_middle
::traits
::{ObligationCause, ObligationCauseCode}
;
14 use rustc_middle
::ty
::subst
::Subst
;
15 use rustc_middle
::ty
::{self, Ty, TyCtxt}
;
16 use rustc_span
::symbol
::{kw, sym, Symbol}
;
17 use rustc_target
::spec
::abi
::Abi
;
21 fn equate_intrinsic_type
<'tcx
>(
23 it
: &hir
::ForeignItem
<'_
>,
27 safety
: hir
::Unsafety
,
28 inputs
: Vec
<Ty
<'tcx
>>,
32 hir
::ForeignItemKind
::Fn(..) => {}
34 struct_span_err
!(tcx
.sess
, it
.span
, E0622
, "intrinsic must be a function")
35 .span_label(it
.span
, "expected a function")
41 let i_n_tps
= tcx
.generics_of(def_id
).own_counts().types
;
43 let span
= match it
.kind
{
44 hir
::ForeignItemKind
::Fn(_
, _
, ref generics
) => generics
.span
,
48 tcx
.sess
.emit_err(WrongNumberOfTypeArgumentsToInstrinsic
{
56 let fty
= tcx
.mk_fn_ptr(ty
::Binder
::bind(tcx
.mk_fn_sig(
63 let cause
= ObligationCause
::new(it
.span
, it
.hir_id
, ObligationCauseCode
::IntrinsicType
);
64 require_same_types(tcx
, &cause
, tcx
.mk_fn_ptr(tcx
.fn_sig(def_id
)), fty
);
67 /// Returns `true` if the given intrinsic is unsafe to call or not.
68 pub fn intrinsic_operation_unsafety(intrinsic
: Symbol
) -> hir
::Unsafety
{
74 | sym
::caller_location
76 | sym
::min_align_of_val
77 | sym
::add_with_overflow
78 | sym
::sub_with_overflow
79 | sym
::mul_with_overflow
92 | sym
::discriminant_value
96 | sym
::ptr_guaranteed_eq
97 | sym
::ptr_guaranteed_ne
104 | sym
::variant_count
=> hir
::Unsafety
::Normal
,
105 _
=> hir
::Unsafety
::Unsafe
,
109 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
110 /// and in `library/core/src/intrinsics.rs`.
111 pub fn check_intrinsic_type(tcx
: TyCtxt
<'_
>, it
: &hir
::ForeignItem
<'_
>) {
112 let param
= |n
| tcx
.mk_ty_param(n
, Symbol
::intern(&format
!("P{}", n
)));
113 let def_id
= tcx
.hir().local_def_id(it
.hir_id
).to_def_id();
114 let intrinsic_name
= tcx
.item_name(def_id
);
115 let name_str
= intrinsic_name
.as_str();
117 let mk_va_list_ty
= |mutbl
| {
118 tcx
.lang_items().va_list().map(|did
| {
119 let region
= tcx
.mk_region(ty
::ReLateBound(ty
::INNERMOST
, ty
::BrAnon(0)));
120 let env_region
= ty
::ReLateBound(ty
::INNERMOST
, ty
::BrEnv
);
121 let va_list_ty
= tcx
.type_of(did
).subst(tcx
, &[region
.into()]);
123 tcx
.mk_ref(tcx
.mk_region(env_region
), ty
::TypeAndMut { ty: va_list_ty, mutbl }
),
129 let (n_tps
, inputs
, output
, unsafety
) = if name_str
.starts_with("atomic_") {
130 let split
: Vec
<&str> = name_str
.split('_'
).collect();
131 assert
!(split
.len() >= 2, "Atomic intrinsic in an incorrect format");
133 //We only care about the operation here
134 let (n_tps
, inputs
, output
) = match split
[1] {
135 "cxchg" | "cxchgweak" => (
137 vec
![tcx
.mk_mut_ptr(param(0)), param(0), param(0)],
138 tcx
.intern_tup(&[param(0), tcx
.types
.bool
]),
140 "load" => (1, vec
![tcx
.mk_imm_ptr(param(0))], param(0)),
141 "store" => (1, vec
![tcx
.mk_mut_ptr(param(0)), param(0)], tcx
.mk_unit()),
143 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax"
144 | "umin" => (1, vec
![tcx
.mk_mut_ptr(param(0)), param(0)], param(0)),
145 "fence" | "singlethreadfence" => (0, Vec
::new(), tcx
.mk_unit()),
147 tcx
.sess
.emit_err(UnrecognizedAtomicOperation { span: it.span, op }
);
151 (n_tps
, inputs
, output
, hir
::Unsafety
::Unsafe
)
153 let unsafety
= intrinsic_operation_unsafety(intrinsic_name
);
154 let (n_tps
, inputs
, output
) = match intrinsic_name
{
155 sym
::abort
=> (0, Vec
::new(), tcx
.types
.never
),
156 sym
::unreachable
=> (0, Vec
::new(), tcx
.types
.never
),
157 sym
::breakpoint
=> (0, Vec
::new(), tcx
.mk_unit()),
158 sym
::size_of
| sym
::pref_align_of
| sym
::min_align_of
| sym
::variant_count
=> {
159 (1, Vec
::new(), tcx
.types
.usize)
161 sym
::size_of_val
| sym
::min_align_of_val
=> {
162 (1, vec
![tcx
.mk_imm_ptr(param(0))], tcx
.types
.usize)
164 sym
::rustc_peek
=> (1, vec
![param(0)], param(0)),
165 sym
::caller_location
=> (0, vec
![], tcx
.caller_location_ty()),
166 sym
::assert_inhabited
| sym
::assert_zero_valid
| sym
::assert_uninit_valid
=> {
167 (1, Vec
::new(), tcx
.mk_unit())
169 sym
::forget
=> (1, vec
![param(0)], tcx
.mk_unit()),
170 sym
::transmute
=> (2, vec
![param(0)], param(1)),
171 sym
::move_val_init
=> (1, vec
![tcx
.mk_mut_ptr(param(0)), param(0)], tcx
.mk_unit()),
172 sym
::prefetch_read_data
173 | sym
::prefetch_write_data
174 | sym
::prefetch_read_instruction
175 | sym
::prefetch_write_instruction
=> (
178 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }
),
183 sym
::drop_in_place
=> (1, vec
![tcx
.mk_mut_ptr(param(0))], tcx
.mk_unit()),
184 sym
::needs_drop
=> (1, Vec
::new(), tcx
.types
.bool
),
186 sym
::type_name
=> (1, Vec
::new(), tcx
.mk_static_str()),
187 sym
::type_id
=> (1, Vec
::new(), tcx
.types
.u64),
188 sym
::offset
| sym
::arith_offset
=> (
191 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }
),
194 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }
),
196 sym
::copy
| sym
::copy_nonoverlapping
=> (
199 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }
),
200 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }
),
205 sym
::volatile_copy_memory
| sym
::volatile_copy_nonoverlapping_memory
=> (
208 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }
),
209 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }
),
214 sym
::write_bytes
| sym
::volatile_set_memory
=> (
217 tcx
.mk_ptr(ty
::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }
),
223 sym
::sqrtf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
224 sym
::sqrtf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
225 sym
::powif32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.i32], tcx
.types
.f32),
226 sym
::powif64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.i32], tcx
.types
.f64),
227 sym
::sinf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
228 sym
::sinf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
229 sym
::cosf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
230 sym
::cosf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
231 sym
::powf32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.f32], tcx
.types
.f32),
232 sym
::powf64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.f64], tcx
.types
.f64),
233 sym
::expf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
234 sym
::expf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
235 sym
::exp2f32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
236 sym
::exp2f64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
237 sym
::logf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
238 sym
::logf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
239 sym
::log10f32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
240 sym
::log10f64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
241 sym
::log2f32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
242 sym
::log2f64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
243 sym
::fmaf32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.f32, tcx
.types
.f32], tcx
.types
.f32),
244 sym
::fmaf64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.f64, tcx
.types
.f64], tcx
.types
.f64),
245 sym
::fabsf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
246 sym
::fabsf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
247 sym
::minnumf32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.f32], tcx
.types
.f32),
248 sym
::minnumf64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.f64], tcx
.types
.f64),
249 sym
::maxnumf32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.f32], tcx
.types
.f32),
250 sym
::maxnumf64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.f64], tcx
.types
.f64),
251 sym
::copysignf32
=> (0, vec
![tcx
.types
.f32, tcx
.types
.f32], tcx
.types
.f32),
252 sym
::copysignf64
=> (0, vec
![tcx
.types
.f64, tcx
.types
.f64], tcx
.types
.f64),
253 sym
::floorf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
254 sym
::floorf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
255 sym
::ceilf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
256 sym
::ceilf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
257 sym
::truncf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
258 sym
::truncf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
259 sym
::rintf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
260 sym
::rintf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
261 sym
::nearbyintf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
262 sym
::nearbyintf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
263 sym
::roundf32
=> (0, vec
![tcx
.types
.f32], tcx
.types
.f32),
264 sym
::roundf64
=> (0, vec
![tcx
.types
.f64], tcx
.types
.f64),
266 sym
::volatile_load
| sym
::unaligned_volatile_load
=> {
267 (1, vec
![tcx
.mk_imm_ptr(param(0))], param(0))
269 sym
::volatile_store
| sym
::unaligned_volatile_store
=> {
270 (1, vec
![tcx
.mk_mut_ptr(param(0)), param(0)], tcx
.mk_unit())
279 | sym
::bitreverse
=> (1, vec
![param(0)], param(0)),
281 sym
::add_with_overflow
| sym
::sub_with_overflow
| sym
::mul_with_overflow
=> {
282 (1, vec
![param(0), param(0)], tcx
.intern_tup(&[param(0), tcx
.types
.bool
]))
285 sym
::ptr_guaranteed_eq
| sym
::ptr_guaranteed_ne
=> {
286 (1, vec
![tcx
.mk_imm_ptr(param(0)), tcx
.mk_imm_ptr(param(0))], tcx
.types
.bool
)
289 sym
::ptr_offset_from
=> {
290 (1, vec
![tcx
.mk_imm_ptr(param(0)), tcx
.mk_imm_ptr(param(0))], tcx
.types
.isize)
292 sym
::unchecked_div
| sym
::unchecked_rem
| sym
::exact_div
=> {
293 (1, vec
![param(0), param(0)], param(0))
295 sym
::unchecked_shl
| sym
::unchecked_shr
| sym
::rotate_left
| sym
::rotate_right
=> {
296 (1, vec
![param(0), param(0)], param(0))
298 sym
::unchecked_add
| sym
::unchecked_sub
| sym
::unchecked_mul
=> {
299 (1, vec
![param(0), param(0)], param(0))
301 sym
::wrapping_add
| sym
::wrapping_sub
| sym
::wrapping_mul
=> {
302 (1, vec
![param(0), param(0)], param(0))
304 sym
::saturating_add
| sym
::saturating_sub
=> (1, vec
![param(0), param(0)], param(0)),
305 sym
::fadd_fast
| sym
::fsub_fast
| sym
::fmul_fast
| sym
::fdiv_fast
| sym
::frem_fast
=> {
306 (1, vec
![param(0), param(0)], param(0))
308 sym
::float_to_int_unchecked
=> (2, vec
![param(0)], param(1)),
310 sym
::assume
=> (0, vec
![tcx
.types
.bool
], tcx
.mk_unit()),
311 sym
::likely
=> (0, vec
![tcx
.types
.bool
], tcx
.types
.bool
),
312 sym
::unlikely
=> (0, vec
![tcx
.types
.bool
], tcx
.types
.bool
),
314 sym
::discriminant_value
=> {
316 tcx
.associated_items(tcx
.lang_items().discriminant_kind_trait().unwrap());
317 let discriminant_def_id
= assoc_items
.in_definition_order().next().unwrap().def_id
;
322 tcx
.mk_region(ty
::ReLateBound(ty
::INNERMOST
, ty
::BrAnon(0))),
325 tcx
.mk_projection(discriminant_def_id
, tcx
.mk_substs([param(0).into()].iter())),
330 let mut_u8
= tcx
.mk_mut_ptr(tcx
.types
.u8);
331 let try_fn_ty
= ty
::Binder
::bind(tcx
.mk_fn_sig(
335 hir
::Unsafety
::Normal
,
338 let catch_fn_ty
= ty
::Binder
::bind(tcx
.mk_fn_sig(
339 [mut_u8
, mut_u8
].iter().cloned(),
342 hir
::Unsafety
::Normal
,
347 vec
![tcx
.mk_fn_ptr(try_fn_ty
), mut_u8
, tcx
.mk_fn_ptr(catch_fn_ty
)],
352 sym
::va_start
| sym
::va_end
=> match mk_va_list_ty(hir
::Mutability
::Mut
) {
353 Some((va_list_ref_ty
, _
)) => (0, vec
![va_list_ref_ty
], tcx
.mk_unit()),
354 None
=> bug
!("`va_list` language item needed for C-variadic intrinsics"),
357 sym
::va_copy
=> match mk_va_list_ty(hir
::Mutability
::Not
) {
358 Some((va_list_ref_ty
, va_list_ty
)) => {
359 let va_list_ptr_ty
= tcx
.mk_mut_ptr(va_list_ty
);
360 (0, vec
![va_list_ptr_ty
, va_list_ref_ty
], tcx
.mk_unit())
362 None
=> bug
!("`va_list` language item needed for C-variadic intrinsics"),
365 sym
::va_arg
=> match mk_va_list_ty(hir
::Mutability
::Mut
) {
366 Some((va_list_ref_ty
, _
)) => (1, vec
![va_list_ref_ty
], param(0)),
367 None
=> bug
!("`va_list` language item needed for C-variadic intrinsics"),
370 sym
::nontemporal_store
=> (1, vec
![tcx
.mk_mut_ptr(param(0)), param(0)], tcx
.mk_unit()),
373 tcx
.sess
.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }
);
377 (n_tps
, inputs
, output
, unsafety
)
379 equate_intrinsic_type(tcx
, it
, def_id
, n_tps
, Abi
::RustIntrinsic
, unsafety
, inputs
, output
)
382 /// Type-check `extern "platform-intrinsic" { ... }` functions.
383 pub fn check_platform_intrinsic_type(tcx
: TyCtxt
<'_
>, it
: &hir
::ForeignItem
<'_
>) {
385 let name
= Symbol
::intern(&format
!("P{}", n
));
386 tcx
.mk_ty_param(n
, name
)
389 let def_id
= tcx
.hir().local_def_id(it
.hir_id
).to_def_id();
390 let name
= it
.ident
.name
;
392 let (n_tps
, inputs
, output
) = match name
{
393 sym
::simd_eq
| sym
::simd_ne
| sym
::simd_lt
| sym
::simd_le
| sym
::simd_gt
| sym
::simd_ge
=> {
394 (2, vec
![param(0), param(0)], param(1))
409 | sym
::simd_saturating_add
410 | sym
::simd_saturating_sub
=> (1, vec
![param(0), param(0)], param(0)),
421 | sym
::simd_ceil
=> (1, vec
![param(0)], param(0)),
422 sym
::simd_fpowi
=> (1, vec
![param(0), tcx
.types
.i32], param(0)),
423 sym
::simd_fma
=> (1, vec
![param(0), param(0), param(0)], param(0)),
424 sym
::simd_gather
=> (3, vec
![param(0), param(1), param(2)], param(0)),
425 sym
::simd_scatter
=> (3, vec
![param(0), param(1), param(2)], tcx
.mk_unit()),
426 sym
::simd_insert
=> (2, vec
![param(0), tcx
.types
.u32, param(1)], param(0)),
427 sym
::simd_extract
=> (2, vec
![param(0), tcx
.types
.u32], param(1)),
428 sym
::simd_cast
=> (2, vec
![param(0)], param(1)),
429 sym
::simd_bitmask
=> (2, vec
![param(0)], param(1)),
430 sym
::simd_select
| sym
::simd_select_bitmask
=> {
431 (2, vec
![param(0), param(1), param(1)], param(1))
433 sym
::simd_reduce_all
| sym
::simd_reduce_any
=> (1, vec
![param(0)], tcx
.types
.bool
),
434 sym
::simd_reduce_add_ordered
| sym
::simd_reduce_mul_ordered
=> {
435 (2, vec
![param(0), param(1)], param(1))
437 sym
::simd_reduce_add_unordered
438 | sym
::simd_reduce_mul_unordered
439 | sym
::simd_reduce_and
440 | sym
::simd_reduce_or
441 | sym
::simd_reduce_xor
442 | sym
::simd_reduce_min
443 | sym
::simd_reduce_max
444 | sym
::simd_reduce_min_nanless
445 | sym
::simd_reduce_max_nanless
=> (2, vec
![param(0)], param(1)),
446 name
if name
.as_str().starts_with("simd_shuffle") => {
447 match name
.as_str()["simd_shuffle".len()..].parse() {
449 let params
= vec
![param(0), param(0), tcx
.mk_array(tcx
.types
.u32, n
)];
450 (2, params
, param(1))
453 tcx
.sess
.emit_err(SimdShuffleMissingLength { span: it.span, name }
);
459 let msg
= format
!("unrecognized platform-specific intrinsic function: `{}`", name
);
460 tcx
.sess
.struct_span_err(it
.span
, &msg
).emit();
465 equate_intrinsic_type(
470 Abi
::PlatformIntrinsic
,
471 hir
::Unsafety
::Unsafe
,