mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-02 11:44:28 +00:00
Create "platform-intrinsic" ABI for SIMD/platform intrinsics.
This is purposely separate to the "rust-intrinsic" ABI, because these intrinsics are theoretically going to become stable, and should be fine to be independent of the compiler/language internals since they're intimately to the platform.
This commit is contained in:
parent
58891278a3
commit
717da9513f
@ -704,7 +704,7 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
|
||||
}
|
||||
|
||||
fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) {
|
||||
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
|
||||
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1501,7 +1501,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
|
||||
encode_family(rbml_w, FN_FAMILY);
|
||||
encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id);
|
||||
encode_name(rbml_w, nitem.ident.name);
|
||||
if abi == abi::RustIntrinsic {
|
||||
if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic {
|
||||
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem));
|
||||
}
|
||||
encode_attributes(rbml_w, &*nitem.attrs);
|
||||
|
@ -603,6 +603,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
match bare_fn.abi {
|
||||
abi::Rust |
|
||||
abi::RustIntrinsic |
|
||||
abi::PlatformIntrinsic |
|
||||
abi::RustCall => {
|
||||
return FfiUnsafe(
|
||||
"found function pointer with Rust calling \
|
||||
@ -717,7 +718,9 @@ impl LintPass for ImproperCTypes {
|
||||
}
|
||||
|
||||
match it.node {
|
||||
ast::ItemForeignMod(ref nmod) if nmod.abi != abi::RustIntrinsic => {
|
||||
ast::ItemForeignMod(ref nmod)
|
||||
if nmod.abi != abi::RustIntrinsic &&
|
||||
nmod.abi != abi::PlatformIntrinsic => {
|
||||
for ni in &nmod.items {
|
||||
match ni.node {
|
||||
ast::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl),
|
||||
|
@ -91,7 +91,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::mem;
|
||||
use std::str;
|
||||
use std::{i8, i16, i32, i64};
|
||||
use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi};
|
||||
use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi};
|
||||
use syntax::ast_util::local_def;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::attr;
|
||||
@ -671,7 +671,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
Rust | RustCall => {
|
||||
get_extern_rust_fn(ccx, t, &name[..], did)
|
||||
}
|
||||
RustIntrinsic => {
|
||||
RustIntrinsic | PlatformIntrinsic => {
|
||||
ccx.sess().bug("unexpected intrinsic in trans_external_path")
|
||||
}
|
||||
_ => {
|
||||
|
@ -150,7 +150,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
||||
}
|
||||
}
|
||||
def::DefFn(did, _) if match expr_ty.sty {
|
||||
ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic,
|
||||
ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic ||
|
||||
f.abi == synabi::PlatformIntrinsic,
|
||||
_ => false
|
||||
} => {
|
||||
let substs = common::node_id_substs(bcx.ccx(),
|
||||
@ -671,7 +672,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
(d.llfn, Some(d.llself))
|
||||
}
|
||||
Intrinsic(node, substs) => {
|
||||
assert!(abi == synabi::RustIntrinsic);
|
||||
assert!(abi == synabi::RustIntrinsic || abi == synabi::PlatformIntrinsic);
|
||||
assert!(dest.is_some());
|
||||
|
||||
let call_info = match debug_loc {
|
||||
@ -701,7 +702,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
|
||||
// Intrinsics should not become actual functions.
|
||||
// We trans them in place in `trans_intrinsic_call`
|
||||
assert!(abi != synabi::RustIntrinsic);
|
||||
assert!(abi != synabi::RustIntrinsic && abi != synabi::PlatformIntrinsic);
|
||||
|
||||
let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall;
|
||||
|
||||
|
@ -34,7 +34,7 @@ use middle::subst::Substs;
|
||||
use std::cmp;
|
||||
use libc::c_uint;
|
||||
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
|
||||
use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
|
||||
use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::{InternedString, special_idents};
|
||||
use syntax::ast;
|
||||
@ -81,6 +81,10 @@ pub fn llvm_calling_convention(ccx: &CrateContext,
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register intrinsic fn");
|
||||
}
|
||||
PlatformIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register platform intrinsic fn");
|
||||
}
|
||||
|
||||
Rust => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
@ -475,7 +479,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
|
||||
|
||||
if let ast::ForeignItemFn(ref decl, _) = foreign_item.node {
|
||||
match foreign_mod.abi {
|
||||
Rust | RustIntrinsic => {}
|
||||
Rust | RustIntrinsic | PlatformIntrinsic => {}
|
||||
abi => {
|
||||
let ty = ccx.tcx().node_id_to_type(foreign_item.id);
|
||||
match ty.sty {
|
||||
@ -612,7 +616,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// normal Rust function. This will be the type of the wrappee fn.
|
||||
match t.sty {
|
||||
ty::TyBareFn(_, ref f) => {
|
||||
assert!(f.abi != Rust && f.abi != RustIntrinsic);
|
||||
assert!(f.abi != Rust && f.abi != RustIntrinsic && f.abi != PlatformIntrinsic);
|
||||
}
|
||||
_ => {
|
||||
ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
|
||||
|
@ -90,7 +90,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
});
|
||||
|
||||
if let ast_map::NodeForeignItem(_) = map_node {
|
||||
if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
|
||||
let abi = ccx.tcx().map.get_foreign_abi(fn_id.node);
|
||||
if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic {
|
||||
// Foreign externs don't have to be monomorphized.
|
||||
return (get_item_val(ccx, fn_id.node), mono_ty, true);
|
||||
}
|
||||
|
@ -720,6 +720,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
|
||||
for item in &m.items {
|
||||
check_intrinsic_type(ccx, &**item);
|
||||
}
|
||||
} else if m.abi == abi::PlatformIntrinsic {
|
||||
for item in &m.items {
|
||||
check_platform_intrinsic_type(ccx, &**item);
|
||||
}
|
||||
} else {
|
||||
for item in &m.items {
|
||||
let pty = ccx.tcx.lookup_item_type(local_def(item.id));
|
||||
@ -5093,7 +5097,6 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
|
||||
let tcx = ccx.tcx;
|
||||
let name = it.ident.name.as_str();
|
||||
let mut infer_ctxt = None;
|
||||
let (n_tps, inputs, output) = if name.starts_with("atomic_") {
|
||||
let split : Vec<&str> = name.split('_').collect();
|
||||
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
|
||||
@ -5342,35 +5345,6 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
|
||||
ty::BrAnon(0))),
|
||||
param(ccx, 0))], tcx.types.u64),
|
||||
"simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
|
||||
(2, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 1))
|
||||
}
|
||||
"simd_add" | "simd_sub" | "simd_mul" |
|
||||
"simd_div" | "simd_shl" | "simd_shr" |
|
||||
"simd_and" | "simd_or" | "simd_xor" => {
|
||||
(1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0))
|
||||
}
|
||||
"simd_insert" => (2, vec![param(ccx, 0), tcx.types.u32, param(ccx, 1)], param(ccx, 0)),
|
||||
"simd_extract" => (2, vec![param(ccx, 0), tcx.types.u32], param(ccx, 1)),
|
||||
"simd_cast" => (2, vec![param(ccx, 0)], param(ccx, 1)),
|
||||
name if name.starts_with("simd_shuffle") => {
|
||||
match name["simd_shuffle".len()..].parse() {
|
||||
Ok(n) => {
|
||||
let mut params = vec![param(ccx, 0), param(ccx, 0)];
|
||||
params.extend(iter::repeat(tcx.types.u32).take(n));
|
||||
|
||||
let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
|
||||
let ret = ictxt.next_ty_var();
|
||||
infer_ctxt = Some(ictxt);
|
||||
(2, params, ret)
|
||||
}
|
||||
Err(_) => {
|
||||
span_err!(tcx.sess, it.span, E0439,
|
||||
"invalid `simd_shuffle`, needs length: `{}`", name);
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"try" => {
|
||||
let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
|
||||
@ -5388,17 +5362,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
}
|
||||
|
||||
ref other => {
|
||||
match intrinsics::Intrinsic::find(tcx, other) {
|
||||
Some(intr) => {
|
||||
check_platform_intrinsic_type(ccx, intr, it);
|
||||
return
|
||||
}
|
||||
None => {
|
||||
span_err!(tcx.sess, it.span, E0093,
|
||||
"unrecognized intrinsic function: `{}`", *other);
|
||||
return;
|
||||
}
|
||||
}
|
||||
span_err!(tcx.sess, it.span, E0093,
|
||||
"unrecognized intrinsic function: `{}`", *other);
|
||||
return;
|
||||
}
|
||||
};
|
||||
(n_tps, inputs, ty::FnConverging(output))
|
||||
@ -5421,7 +5387,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
i_n_tps, n_tps);
|
||||
} else {
|
||||
require_same_types(tcx,
|
||||
infer_ctxt.as_ref(),
|
||||
None,
|
||||
false,
|
||||
it.span,
|
||||
i_ty.ty,
|
||||
@ -5434,95 +5400,177 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
}
|
||||
|
||||
fn check_platform_intrinsic_type(ccx: &CrateCtxt,
|
||||
expected: intrinsics::Intrinsic, it: &ast::ForeignItem) {
|
||||
it: &ast::ForeignItem) {
|
||||
let param = |n| {
|
||||
let name = token::intern(&format!("P{}", n));
|
||||
ccx.tcx.mk_param(subst::FnSpace, n, name)
|
||||
};
|
||||
|
||||
let tcx = ccx.tcx;
|
||||
let i_ty = tcx.lookup_item_type(local_def(it.id));
|
||||
let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
|
||||
if i_n_tps != 0 {
|
||||
tcx.sess.span_err(it.span,
|
||||
&format!("intrinsic has wrong number of type parameters: \
|
||||
found {}, expected 0",
|
||||
i_n_tps));
|
||||
return
|
||||
}
|
||||
let name = it.ident.name.as_str();
|
||||
let mut infer_ctxt = None;
|
||||
|
||||
let mut structural_to_nomimal = HashMap::new();
|
||||
let (n_tps, inputs, output) = match &*name {
|
||||
"simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
|
||||
(2, vec![param(0), param(0)], param(1))
|
||||
}
|
||||
"simd_add" | "simd_sub" | "simd_mul" |
|
||||
"simd_div" | "simd_shl" | "simd_shr" |
|
||||
"simd_and" | "simd_or" | "simd_xor" => {
|
||||
(1, vec![param(0), param(0)], param(0))
|
||||
}
|
||||
"simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
|
||||
"simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
|
||||
"simd_cast" => (2, vec![param(0)], param(1)),
|
||||
name if name.starts_with("simd_shuffle") => {
|
||||
match name["simd_shuffle".len()..].parse() {
|
||||
Ok(n) => {
|
||||
let mut params = vec![param(0), param(0)];
|
||||
params.extend(iter::repeat(tcx.types.u32).take(n));
|
||||
|
||||
let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap();
|
||||
for (i, (expected_arg, arg)) in expected.inputs.iter().zip(&sig.inputs).enumerate() {
|
||||
match_types(tcx, &format!("argument {}", i + 1), it.span,
|
||||
&mut structural_to_nomimal, expected_arg, arg);
|
||||
}
|
||||
match_types(tcx, "return value", it.span, &mut structural_to_nomimal,
|
||||
&expected.output, sig.output.unwrap());
|
||||
|
||||
// walk the expected type and the actual type in lock step, checking they're
|
||||
// the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
|
||||
// exactly the right element type
|
||||
fn match_types<'tcx, 'a>(tcx: &ty::ctxt<'tcx>,
|
||||
position: &str,
|
||||
span: Span,
|
||||
structural_to_nominal: &mut HashMap<&'a intrinsics::Type,
|
||||
ty::Ty<'tcx>>,
|
||||
expected: &'a intrinsics::Type, t: ty::Ty<'tcx>) {
|
||||
use intrinsics::Type::*;
|
||||
match *expected {
|
||||
Integer(bits) => match (bits, &t.sty) {
|
||||
(8, &ty::TyInt(ast::TyI8)) | (8, &ty::TyUint(ast::TyU8)) |
|
||||
(16, &ty::TyInt(ast::TyI16)) | (16, &ty::TyUint(ast::TyU16)) |
|
||||
(32, &ty::TyInt(ast::TyI32)) | (32, &ty::TyUint(ast::TyU32)) |
|
||||
(64, &ty::TyInt(ast::TyI64)) | (64, &ty::TyUint(ast::TyU64)) => {},
|
||||
_ => tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
expected `i{n}` or `u{n}`",
|
||||
position,
|
||||
t, n = bits)),
|
||||
},
|
||||
Float(bits) => match (bits, &t.sty) {
|
||||
(32, &ty::TyFloat(ast::TyF32)) |
|
||||
(64, &ty::TyFloat(ast::TyF64)) => {},
|
||||
_ => tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
expected `f{n}`",
|
||||
position,
|
||||
t, n = bits)),
|
||||
},
|
||||
Pointer(_) => unimplemented!(),
|
||||
Vector(ref inner_expected, len) => {
|
||||
if t.is_simd(tcx) {
|
||||
let t_len = t.simd_size(tcx);
|
||||
if len as usize != t_len {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found \
|
||||
vector with length {}, expected length {}",
|
||||
position,
|
||||
t_len, len));
|
||||
return;
|
||||
}
|
||||
let t_ty = t.simd_type(tcx);
|
||||
{
|
||||
let previous = structural_to_nominal.entry(expected).or_insert(t);
|
||||
if *previous != t {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
but already seen this vector type as `{}`",
|
||||
position, t, previous));
|
||||
return;
|
||||
}
|
||||
}
|
||||
match_types(tcx,
|
||||
position,
|
||||
span,
|
||||
structural_to_nominal,
|
||||
inner_expected,
|
||||
t_ty)
|
||||
} else {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found non-simd type {}, \
|
||||
expected simd type",
|
||||
position, t));
|
||||
let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
|
||||
let ret = ictxt.next_ty_var();
|
||||
infer_ctxt = Some(ictxt);
|
||||
(2, params, ret)
|
||||
}
|
||||
Err(_) => {
|
||||
span_err!(tcx.sess, it.span, E0439,
|
||||
"invalid `simd_shuffle`, needs length: `{}`", name);
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match intrinsics::Intrinsic::find(tcx, &name) {
|
||||
Some(intr) => {
|
||||
// this function is a platform specific intrinsic
|
||||
if i_n_tps != 0 {
|
||||
tcx.sess.span_err(it.span,
|
||||
&format!("intrinsic has wrong number of type parameters: \
|
||||
found {}, expected 0",
|
||||
i_n_tps));
|
||||
return
|
||||
}
|
||||
|
||||
let mut structural_to_nomimal = HashMap::new();
|
||||
|
||||
let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap();
|
||||
let input_pairs = intr.inputs.iter().zip(&sig.inputs);
|
||||
for (i, (expected_arg, arg)) in input_pairs.enumerate() {
|
||||
match_intrinsic_type_to_type(tcx, &format!("argument {}", i + 1), it.span,
|
||||
&mut structural_to_nomimal, expected_arg, arg);
|
||||
}
|
||||
match_intrinsic_type_to_type(tcx, "return value", it.span,
|
||||
&mut structural_to_nomimal,
|
||||
&intr.output, sig.output.unwrap());
|
||||
return
|
||||
}
|
||||
None => {
|
||||
tcx.sess.span_err(it.span,
|
||||
&format!("unrecognized intrinsic function: `{}`", name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy {
|
||||
unsafety: ast::Unsafety::Unsafe,
|
||||
abi: abi::PlatformIntrinsic,
|
||||
sig: ty::Binder(FnSig {
|
||||
inputs: inputs,
|
||||
output: ty::FnConverging(output),
|
||||
variadic: false,
|
||||
}),
|
||||
}));
|
||||
if i_n_tps != n_tps {
|
||||
span_err!(tcx.sess, it.span, E0094,
|
||||
"intrinsic has wrong number of type \
|
||||
parameters: found {}, expected {}",
|
||||
i_n_tps, n_tps);
|
||||
} else {
|
||||
require_same_types(tcx,
|
||||
infer_ctxt.as_ref(),
|
||||
false,
|
||||
it.span,
|
||||
i_ty.ty,
|
||||
fty,
|
||||
|| {
|
||||
format!("intrinsic has wrong type: expected `{}`",
|
||||
fty)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// walk the expected type and the actual type in lock step, checking they're
|
||||
// the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
|
||||
// exactly the right element type
|
||||
fn match_intrinsic_type_to_type<'tcx, 'a>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
position: &str,
|
||||
span: Span,
|
||||
structural_to_nominal: &mut HashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
|
||||
expected: &'a intrinsics::Type, t: ty::Ty<'tcx>)
|
||||
{
|
||||
use intrinsics::Type::*;
|
||||
match *expected {
|
||||
Integer(bits) => match (bits, &t.sty) {
|
||||
(8, &ty::TyInt(ast::TyI8)) | (8, &ty::TyUint(ast::TyU8)) |
|
||||
(16, &ty::TyInt(ast::TyI16)) | (16, &ty::TyUint(ast::TyU16)) |
|
||||
(32, &ty::TyInt(ast::TyI32)) | (32, &ty::TyUint(ast::TyU32)) |
|
||||
(64, &ty::TyInt(ast::TyI64)) | (64, &ty::TyUint(ast::TyU64)) => {},
|
||||
_ => tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
expected `i{n}` or `u{n}`",
|
||||
position,
|
||||
t, n = bits)),
|
||||
},
|
||||
Float(bits) => match (bits, &t.sty) {
|
||||
(32, &ty::TyFloat(ast::TyF32)) |
|
||||
(64, &ty::TyFloat(ast::TyF64)) => {},
|
||||
_ => tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
expected `f{n}`",
|
||||
position,
|
||||
t, n = bits)),
|
||||
},
|
||||
Pointer(_) => unimplemented!(),
|
||||
Vector(ref inner_expected, len) => {
|
||||
if !t.is_simd(tcx) {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found non-simd type {}, \
|
||||
expected simd type",
|
||||
position, t));
|
||||
return;
|
||||
}
|
||||
let t_len = t.simd_size(tcx);
|
||||
if len as usize != t_len {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found \
|
||||
vector with length {}, expected length {}",
|
||||
position,
|
||||
t_len, len));
|
||||
return;
|
||||
}
|
||||
let t_ty = t.simd_type(tcx);
|
||||
{
|
||||
let previous = structural_to_nominal.entry(expected).or_insert(t);
|
||||
if *previous != t {
|
||||
tcx.sess.span_err(span,
|
||||
&format!("intrinsic {} has wrong type: found `{}`, \
|
||||
but already seen this vector type as `{}`",
|
||||
position, t, previous));
|
||||
return;
|
||||
}
|
||||
}
|
||||
match_intrinsic_type_to_type(tcx,
|
||||
position,
|
||||
span,
|
||||
structural_to_nominal,
|
||||
inner_expected,
|
||||
t_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ pub enum Abi {
|
||||
System,
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
PlatformIntrinsic,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -95,6 +96,7 @@ const AbiDatas: &'static [AbiData] = &[
|
||||
AbiData {abi: System, name: "system" },
|
||||
AbiData {abi: RustIntrinsic, name: "rust-intrinsic" },
|
||||
AbiData {abi: RustCall, name: "rust-call" },
|
||||
AbiData {abi: PlatformIntrinsic, name: "platform-intrinsic" }
|
||||
];
|
||||
|
||||
/// Returns the ABI with the given name (if any).
|
||||
|
@ -184,6 +184,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
|
||||
|
||||
// Allows cfg(target_feature = "...").
|
||||
("cfg_target_feature", "1.3.0", Active),
|
||||
|
||||
// allow `extern "platform-intrinsic" { ... }`
|
||||
("platform_intrinsics", "1.4.0", Active),
|
||||
];
|
||||
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
||||
|
||||
@ -694,10 +697,16 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
||||
across platforms, it is recommended to \
|
||||
use `#[link(name = \"foo\")]` instead")
|
||||
}
|
||||
if foreign_module.abi == Abi::RustIntrinsic {
|
||||
self.gate_feature("intrinsics",
|
||||
i.span,
|
||||
"intrinsics are subject to change")
|
||||
let maybe_feature = match foreign_module.abi {
|
||||
Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
|
||||
Abi::PlatformIntrinsic => {
|
||||
Some(("platform_intrinsics",
|
||||
"platform intrinsics are experimental and possibly buggy"))
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
if let Some((feature, msg)) = maybe_feature {
|
||||
self.gate_feature(feature, i.span, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user