use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::closure;
-use trans::common::{self, Block, Result, NodeIdAndSpan, CrateContext, FunctionContext};
+use trans::common::{self, Block, Result, CrateContext, FunctionContext};
use trans::common::{C_uint, C_undef};
use trans::consts;
use trans::datum::*;
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_front::hir;
-use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::errors;
use syntax::ptr::P;
assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
assert!(dest.is_some());
- let call_info = match debug_loc {
- DebugLoc::At(id, span) => NodeIdAndSpan { id: id, span: span },
- DebugLoc::None => {
- bcx.sess().bug("No call info for intrinsic call?")
- }
- };
-
- let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
- arg_cleanup_scope, args,
- dest.unwrap(),
- call_info);
+ args, dest.unwrap(),
+ debug_loc);
}
NamedTupleConstructor(disr) => {
assert!(dest.is_some());
use rustc::lint;
use rustc::session::Session;
-use syntax::codemap::Span;
+use syntax::codemap::{Span, DUMMY_SP};
use std::cmp::Ordering;
pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
callee_ty: Ty<'tcx>,
fn_ty: &FnType,
- cleanup_scope: cleanup::CustomScopeIndex,
args: callee::CallArgs<'a, 'tcx>,
dest: expr::Dest,
- call_info: NodeIdAndSpan)
+ call_debug_location: DebugLoc)
-> Result<'blk, 'tcx> {
let fcx = bcx.fcx;
let ccx = fcx.ccx;
let ret_ty = sig.output;
let name = tcx.item_name(def_id).as_str();
- let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
+ let span = match call_debug_location {
+ DebugLoc::At(_, span) => span,
+ DebugLoc::None => fcx.span.unwrap_or(DUMMY_SP)
+ };
+
+ let cleanup_scope = fcx.push_custom_cleanup_scope();
// For `transmute` we can just trans the input expr directly into dest
if name == "transmute" {
},
None => {
span_invalid_monomorphization_error(
- tcx.sess, call_info.span,
+ tcx.sess, span,
&format!("invalid monomorphization of `{}` intrinsic: \
expected basic integer type, found `{}`", name, sty));
C_null(llret_ty)
(_, "return_address") => {
if !fcx.fn_ty.ret.is_indirect() {
- span_err!(tcx.sess, call_info.span, E0510,
+ span_err!(tcx.sess, span, E0510,
"invalid use of `return_address` intrinsic: function \
does not use out pointer");
C_null(Type::i8p(ccx))
&llargs,
ret_ty, llret_ty,
call_debug_location,
- call_info)
+ span)
}
// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
ret_ty: Ty<'tcx>,
llret_ty: Type,
call_debug_location: DebugLoc,
- call_info: NodeIdAndSpan) -> ValueRef
+ span: Span) -> ValueRef
{
// macros for error handling:
macro_rules! emit_error {
};
($msg: tt, $($fmt: tt)*) => {
span_invalid_monomorphization_error(
- bcx.sess(), call_info.span,
+ bcx.sess(), span,
&format!(concat!("invalid monomorphization of `{}` intrinsic: ",
$msg),
name, $($fmt)*));
if name.starts_with("simd_shuffle") {
let n: usize = match name["simd_shuffle".len()..].parse() {
Ok(n) => n,
- Err(_) => tcx.sess.span_bug(call_info.span,
+ Err(_) => tcx.sess.span_bug(span,
"bad `simd_shuffle` instruction only caught in trans?")
};
let vector = match args {
Some(args) => &args[2],
- None => bcx.sess().span_bug(call_info.span,
+ None => bcx.sess().span_bug(span,
"intrinsic call with unexpected argument shape"),
};
let vector = match consts::const_expr(bcx.ccx(), vector, substs, None,
consts::TrueConst::Yes, // this should probably help simd error reporting
) {
Ok((vector, _)) => vector,
- Err(err) => bcx.sess().span_fatal(call_info.span, &err.description()),
+ Err(err) => bcx.sess().span_fatal(span, &err.description()),
};
let indices: Option<Vec<_>> = (0..n)
simd_or: TyUint, TyInt => Or;
simd_xor: TyUint, TyInt => Xor;
}
- bcx.sess().span_bug(call_info.span, "unknown SIMD intrinsic");
+ bcx.sess().span_bug(span, "unknown SIMD intrinsic");
}
// Returns the width of an int TypeVariant, and if it's signed or not
use trans::adt;
use trans::base;
use trans::build;
-use trans::callee::{Callee, CalleeData, Fn, Virtual};
+use trans::callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
use trans::common::{self, Block, BlockAndBuilder, C_undef};
use trans::debuginfo::DebugLoc;
use trans::Disr;
-use trans::machine::llalign_of_min;
+use trans::machine::{llalign_of_min, llbitsize_of_real};
use trans::meth;
use trans::type_of;
use trans::glue;
use super::{MirContext, drop};
use super::lvalue::LvalueRef;
+use super::operand::OperandRef;
use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => unreachable!("{} is not callable", callee.ty)
};
- // We do not translate intrinsics here (they shouldn’t be functions)
- assert!(abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic);
+ // Handle intrinsics old trans wants Expr's for, ourselves.
+ let intrinsic = match (&callee.ty.sty, &callee.data) {
+ (&ty::TyFnDef(def_id, _, _), &Intrinsic) => {
+ Some(bcx.tcx().item_name(def_id).as_str())
+ }
+ _ => None
+ };
+ let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
+
+ if intrinsic == Some("move_val_init") {
+ let &(_, target) = destination.as_ref().unwrap();
+ // The first argument is a thin destination pointer.
+ let llptr = self.trans_operand(&bcx, &args[0]).immediate();
+ let val = self.trans_operand(&bcx, &args[1]);
+ self.store_operand(&bcx, llptr, val);
+ self.set_operand_dropped(&bcx, &args[1]);
+ funclet_br(bcx, self.llblock(target));
+ return;
+ }
+
+ if intrinsic == Some("transmute") {
+ let &(ref dest, target) = destination.as_ref().unwrap();
+ let dst = self.trans_lvalue(&bcx, dest);
+ let mut val = self.trans_operand(&bcx, &args[0]);
+ if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
+ let llouttype = type_of::type_of(bcx.ccx(), dst.ty.to_ty(bcx.tcx()));
+ let out_type_size = llbitsize_of_real(bcx.ccx(), llouttype);
+ if out_type_size != 0 {
+ // FIXME #19925 Remove this hack after a release cycle.
+ let f = Callee::def(bcx.ccx(), def_id, substs);
+ let datum = f.reify(bcx.ccx());
+ val = OperandRef {
+ val: OperandValue::Immediate(datum.val),
+ ty: datum.ty
+ };
+ }
+ }
+
+ let llty = type_of::type_of(bcx.ccx(), val.ty);
+ let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
+ self.store_operand(&bcx, cast_ptr, val);
+ self.set_operand_dropped(&bcx, &args[0]);
+ funclet_br(bcx, self.llblock(target));
+ return;
+ }
let extra_args = &args[sig.0.inputs.len()..];
let extra_args = extra_args.iter().map(|op_arg| {
&mut idx, &mut callee.data)
}
- let fn_ptr = callee.reify(bcx.ccx()).val;
+ let fn_ptr = match callee.data {
+ NamedTupleConstructor(_) => {
+ // FIXME translate this like mir::Rvalue::Aggregate.
+ callee.reify(bcx.ccx()).val
+ }
+ Intrinsic => {
+ use trans::callee::ArgVals;
+ use trans::expr::{Ignore, SaveIn};
+ use trans::intrinsic::trans_intrinsic_call;
+
+ let (dest, llargs) = if fn_ty.ret.is_indirect() {
+ (SaveIn(llargs[0]), &llargs[1..])
+ } else if let Some(dest) = ret_dest {
+ (SaveIn(dest.llval), &llargs[..])
+ } else {
+ (Ignore, &llargs[..])
+ };
+
+ bcx.with_block(|bcx| {
+ let res = trans_intrinsic_call(bcx, callee.ty, &fn_ty,
+ ArgVals(llargs), dest,
+ DebugLoc::None);
+ let bcx = res.bcx.build();
+ if let Some((_, target)) = *destination {
+ for op in args {
+ self.set_operand_dropped(&bcx, op);
+ }
+ funclet_br(bcx, self.llblock(target));
+ } else {
+ // trans_intrinsic_call already used Unreachable.
+ // bcx.unreachable();
+ }
+ });
+ return;
+ }
+ Fn(f) => f,
+ Virtual(_) => unreachable!("Virtual fn ptr not extracted")
+ };
// Many different ways to call a function handled here
if let Some(cleanup) = cleanup.map(|bb| self.bcx(bb)) {