None,
&format!("comparison of `{}`", rhs_t),
StrEqFnLangItem);
- let t = ty::mk_str_slice(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ast::MutImmutable);
- // The comparison function gets the slices by value, so we have to make copies here. Even
- // if the function doesn't write through the pointer, things like lifetime intrinsics
- // require that we do this properly
- let lhs_arg = alloc_ty(cx, t, "lhs");
- let rhs_arg = alloc_ty(cx, t, "rhs");
- memcpy_ty(cx, lhs_arg, lhs, t);
- memcpy_ty(cx, rhs_arg, rhs, t);
- let res = callee::trans_lang_call(cx, did, &[lhs_arg, rhs_arg], None, debug_loc);
- call_lifetime_end(res.bcx, lhs_arg);
- call_lifetime_end(res.bcx, rhs_arg);
-
- res
+ let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
+ let lhs_len = Load(cx, expr::get_len(cx, lhs));
+ let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
+ let rhs_len = Load(cx, expr::get_len(cx, rhs));
+ callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc)
}
let _icx = push_ctxt("compare_values");
};
// Index 0 is the return value of the llvm func, so we start at 1
- let mut first_arg_offset = 1;
+ let mut idx = 1;
if let ty::FnConverging(ret_ty) = ret_ty {
// A function pointer is called without the declaration
// available, so we have to apply any attributes with ABI
.arg(1, llvm::DereferenceableAttribute(llret_sz));
// Add one more since there's an outptr
- first_arg_offset += 1;
+ idx += 1;
} else {
// The `noalias` attribute on the return value is useful to a
// function ptr caller.
}
}
- for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) {
+ for &t in input_tys.iter() {
match t.sty {
- // this needs to be first to prevent fat pointers from falling through
- _ if !common::type_is_immediate(ccx, t) => {
+ _ if type_of::arg_is_indirect(ccx, t) => {
let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t));
// For non-immediate arguments the callee gets its own copy of
// `Box` pointer parameters never alias because ownership is transferred
ty::TyBox(inner) => {
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
-
- attrs.arg(idx, llvm::Attribute::NoAlias)
- .arg(idx, llvm::DereferenceableAttribute(llsz));
+ attrs.arg(idx, llvm::Attribute::NoAlias);
+
+ if common::type_is_sized(ccx.tcx(), inner) {
+ let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
+ attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
+ } else {
+ attrs.arg(idx, llvm::NonNullAttribute);
+ if ty::type_is_trait(inner) {
+ attrs.arg(idx + 1, llvm::NonNullAttribute);
+ }
+ }
}
ty::TyRef(b, mt) => {
attrs.arg(idx, llvm::Attribute::ReadOnly);
}
- // & pointer parameters are also never null and we know exactly
- // how many bytes we can dereference
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
- attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
+ // & pointer parameters are also never null and for sized types we also know
+ // exactly how many bytes we can dereference
+ if common::type_is_sized(ccx.tcx(), mt.ty) {
+ let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
+ attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
+ } else {
+ attrs.arg(idx, llvm::NonNullAttribute);
+ if ty::type_is_trait(mt.ty) {
+ attrs.arg(idx + 1, llvm::NonNullAttribute);
+ }
+ }
// When a reference in an argument has no named lifetime, it's
// impossible for that reference to escape this function
_ => ()
}
+
+ if common::type_is_fat_ptr(ccx.tcx(), t) {
+ idx += 2;
+ } else {
+ idx += 1;
+ }
}
attrs
// create_datums_for_fn_args: creates rvalue datums for each of the
// incoming function arguments. These will later be stored into
// appropriate lvalue datums.
-pub fn create_datums_for_fn_args<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+pub fn create_datums_for_fn_args<'a, 'tcx>(bcx: Block<'a, 'tcx>,
arg_tys: &[Ty<'tcx>])
-> Vec<RvalueDatum<'tcx>> {
let _icx = push_ctxt("create_datums_for_fn_args");
+ let fcx = bcx.fcx;
// Return an array wrapping the ValueRefs that we get from `get_param` for
// each argument into datums.
- arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
- let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint);
- datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ let mut i = fcx.arg_offset() as c_uint;
+ arg_tys.iter().map(|&arg_ty| {
+ if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
+ let llty = type_of::type_of(bcx.ccx(), arg_ty);
+ let data = get_param(fcx.llfn, i);
+ let extra = get_param(fcx.llfn, i + 1);
+ let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra);
+ i += 2;
+ datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue })
+ } else {
+ let llarg = get_param(fcx.llfn, i);
+ i += 1;
+ datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ }
}).collect()
}
arg_tys: &[Ty<'tcx>])
-> Vec<RvalueDatum<'tcx>> {
let mut result = Vec::new();
+ let mut idx = bcx.fcx.arg_offset() as c_uint;
for (i, &arg_ty) in arg_tys.iter().enumerate() {
if i < arg_tys.len() - 1 {
// Regular argument.
- let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint);
- result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx,
- arg_ty)));
+ result.push(if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
+ let llty = type_of::type_of(bcx.ccx(), arg_ty);
+ let data = get_param(bcx.fcx.llfn, idx);
+ let extra = get_param(bcx.fcx.llfn, idx + 1);
+ idx += 2;
+ let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra);
+ datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue })
+ } else {
+ let val = get_param(bcx.fcx.llfn, idx);
+ idx += 1;
+ datum::Datum::new(val, arg_ty, arg_kind(bcx.fcx, arg_ty))
+ });
+
continue
}
llval| {
for (j, &tupled_arg_ty) in
tupled_arg_tys.iter().enumerate() {
- let llarg =
- get_param(bcx.fcx.llfn,
- bcx.fcx.arg_pos(i + j) as c_uint);
let lldest = GEPi(bcx, llval, &[0, j]);
- let datum = datum::Datum::new(
- llarg,
- tupled_arg_ty,
- arg_kind(bcx.fcx, tupled_arg_ty));
- bcx = datum.store_to(bcx, lldest);
+ if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) {
+ let data = get_param(bcx.fcx.llfn, idx);
+ let extra = get_param(bcx.fcx.llfn, idx + 1);
+ Store(bcx, data, expr::get_dataptr(bcx, lldest));
+ Store(bcx, extra, expr::get_len(bcx, lldest));
+ idx += 2;
+ } else {
+ let datum = datum::Datum::new(
+ get_param(bcx.fcx.llfn, idx),
+ tupled_arg_ty,
+ arg_kind(bcx.fcx, tupled_arg_ty));
+ idx += 1;
+ bcx = datum.store_to(bcx, lldest);
+ };
}
bcx
}));
}
_ => {
let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi);
- create_datums_for_fn_args(&fcx, &arg_tys)
+ create_datums_for_fn_args(bcx, &arg_tys)
}
};
ty::erase_late_bound_regions(
ccx.tcx(), &ty::ty_fn_args(ctor_ty));
- let arg_datums = create_datums_for_fn_args(&fcx, &arg_tys[..]);
+ let arg_datums = create_datums_for_fn_args(bcx, &arg_tys[..]);
if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) {
let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot");
let llargs = get_params(fcx.llfn);
+ let self_idx = fcx.arg_offset();
// the first argument (`self`) will be ptr to the the fn pointer
let llfnpointer = if is_by_ref {
- Load(bcx, llargs[fcx.arg_pos(0)])
+ Load(bcx, llargs[self_idx])
} else {
- llargs[fcx.arg_pos(0)]
+ llargs[self_idx]
};
assert!(!fcx.needs_ret_allocas);
DebugLoc::None,
bare_fn_ty,
|bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
- ArgVals(&llargs[fcx.arg_pos(1)..]),
+ ArgVals(&llargs[(self_idx + 1)..]),
dest).bcx;
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
val = arg_datum.val;
}
+ DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
+ !bcx.fcx.type_needs_drop(arg_datum_ty) => {
+ val = arg_datum.val
+ }
DontAutorefArg => {
// Make this an rvalue, since we are going to be
// passing ownership.
}
}
- if formal_arg_ty != arg_datum_ty {
+ if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
// this could happen due to e.g. subtyping
let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
debug!("casting actual type ({}) to match formal ({})",
debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
- llargs.push(val);
+ if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
+ llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
+ llargs.push(Load(bcx, expr::get_len(bcx, val)));
+ } else {
+ llargs.push(val);
+ }
bcx
}
let self_scope = fcx.push_custom_cleanup_scope();
let self_scope_id = CustomScope(self_scope);
let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty);
- let llself = llargs[fcx.arg_pos(0)];
+ let self_idx = fcx.arg_offset();
+ let llself = llargs[self_idx];
let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode));
let env_datum = unpack_datum!(bcx,
env_datum.to_lvalue_datum_in_scope(bcx, "self",
DebugLoc::None,
llref_fn_ty,
|bcx, _| Callee { bcx: bcx, data: callee_data },
- ArgVals(&llargs[fcx.arg_pos(1)..]),
+ ArgVals(&llargs[(self_idx + 1)..]),
dest).bcx;
fcx.pop_custom_cleanup_scope(self_scope);
}
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
- pub fn arg_pos(&self, arg: usize) -> usize {
- let arg = self.env_arg_pos() + arg;
- if self.llenv.is_some() {
- arg + 1
- } else {
- arg
- }
+ pub fn arg_offset(&self) -> usize {
+ self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 }
}
pub fn env_arg_pos(&self) -> usize {
GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
}
+pub fn make_fat_ptr(bcx: Block, ty: Type, data: ValueRef, extra: ValueRef) -> ValueRef {
+ InsertValue(bcx, InsertValue(bcx, C_undef(ty), data, 0), extra, 1)
+}
pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
// except according to those terms.
-use back::link;
+use back::{abi, link};
use llvm::{ValueRef, CallConv, get_param};
use llvm;
use middle::weak_lang_items;
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
+use trans::expr;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
}
}
- for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
- let mut llarg_rust = llarg_rust;
+ let mut offset = 0;
+ for (i, arg_ty) in arg_tys.iter().enumerate() {
+ let mut llarg_rust = llargs_rust[i + offset];
- if arg_tys[i].is_ignore() {
+ if arg_ty.is_ignore() {
continue;
}
i,
ccx.tn().val_to_string(llarg_rust),
rust_indirect,
- ccx.tn().type_to_string(arg_tys[i].ty));
+ ccx.tn().type_to_string(arg_ty.ty));
// Ensure that we always have the Rust value indirectly,
// because it makes bitcasting easier.
base::alloca(bcx,
type_of::type_of(ccx, passed_arg_tys[i]),
"__arg");
- base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
+ if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
+ Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
+ Store(bcx, llargs_rust[i + offset + 1], expr::get_len(bcx, scratch));
+ offset += 1;
+ } else {
+ base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
+ }
llarg_rust = scratch;
}
ccx.tn().val_to_string(llarg_rust));
// Check whether we need to do any casting
- match arg_tys[i].cast {
+ match arg_ty.cast {
Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
None => ()
}
ccx.tn().val_to_string(llarg_rust));
// Finally, load the value if needed for the foreign ABI
- let foreign_indirect = arg_tys[i].is_indirect();
+ let foreign_indirect = arg_ty.is_indirect();
let llarg_foreign = if foreign_indirect {
llarg_rust
} else {
i, ccx.tn().val_to_string(llarg_foreign));
// fill padding with undef value
- match arg_tys[i].pad {
+ match arg_ty.pad {
Some(ty) => llargs_foreign.push(C_undef(ty)),
None => ()
}
// If the types in the ABI and the Rust types don't match,
// bitcast the llforeign_arg pointer so it matches the types
// Rust expects.
- if llforeign_arg_ty.cast.is_some() {
+ if llforeign_arg_ty.cast.is_some() && !type_is_fat_ptr(ccx.tcx(), rust_ty){
assert!(!foreign_indirect);
llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
}
- let llrust_arg = if rust_indirect {
+ let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) {
llforeign_arg
} else {
if ty::type_is_bool(rust_ty) {
debug!("llrust_arg {}{}: {}", "#",
i, ccx.tn().val_to_string(llrust_arg));
- llrust_args.push(llrust_arg);
+ if type_is_fat_ptr(ccx.tcx(), rust_ty) {
+ let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
+ llrust_args.push(builder.load(builder.bitcast(builder.gepi(
+ llrust_arg, &[0, abi::FAT_PTR_ADDR]), llrust_ty.ptr_to())));
+ llrust_args.push(builder.load(builder.bitcast(builder.gepi(
+ llrust_arg, &[0, abi::FAT_PTR_EXTRA]), next_llrust_ty.ptr_to())));
+ } else {
+ llrust_args.push(llrust_arg);
+ }
}
// Perform the call itself
// llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter.
- let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
+ let llrawptr0 = get_param(llfn, fcx.arg_offset() as c_uint);
let bcx = make_drop_glue(bcx, llrawptr0, g);
finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None);
} else {
(&exprs[0], &exprs[1])
};
- let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(callee_ty));
// evaluate destination address
- let lldest_addr = unpack_result!(bcx, {
- let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr));
- callee::trans_arg_datum(bcx,
- arg_tys[0],
- dest_datum,
- cleanup::CustomScope(cleanup_scope),
- callee::DontAutorefArg)
- });
+ let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr));
+ let dest_datum = unpack_datum!(
+ bcx, dest_datum.to_rvalue_datum(bcx, "arg"));
+ let dest_datum = unpack_datum!(
+ bcx, dest_datum.to_appropriate_datum(bcx));
// `expr::trans_into(bcx, expr, dest)` is equiv to
//
// which for `dest == expr::SaveIn(addr)`, is equivalent to:
//
// `trans(bcx, expr).store_to(bcx, addr)`.
- let lldest = expr::Dest::SaveIn(lldest_addr);
+ let lldest = expr::Dest::SaveIn(dest_datum.val);
bcx = expr::trans_into(bcx, source_expr, lldest);
let llresult = C_nil(ccx);
(_, "size_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if !type_is_sized(tcx, tp_ty) {
- let info = Load(bcx, expr::get_len(bcx, llargs[0]));
- let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info);
+ let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llsize
} else {
let lltp_ty = type_of::type_of(ccx, tp_ty);
(_, "min_align_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if !type_is_sized(tcx, tp_ty) {
- let info = Load(bcx, expr::get_len(bcx, llargs[0]));
- let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info);
+ let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llalign
} else {
C_uint(ccx, type_of::align_of(ccx, tp_ty))
}
(_, "drop_in_place") => {
let tp_ty = *substs.types.get(FnSpace, 0);
- glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location);
+ let ptr = if type_is_sized(tcx, tp_ty) {
+ llargs[0]
+ } else {
+ let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp");
+ Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val));
+ Store(bcx, llargs[1], expr::get_len(bcx, scratch.val));
+ fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val);
+ scratch.val
+ };
+ glue::drop_ty(bcx, ptr, tp_ty, call_debug_location);
C_nil(ccx)
}
(_, "type_name") => {
let ret = C_undef(type_of::type_of(bcx.ccx(), t));
let ret = InsertValue(bcx, ret, result, 0);
let ret = InsertValue(bcx, ret, overflow, 1);
- if type_is_immediate(bcx.ccx(), t) {
+ if !arg_is_indirect(bcx.ccx(), t) {
let tmp = alloc_ty(bcx, t, "tmp");
Store(bcx, ret, tmp);
load_ty(bcx, tmp, t)
self_datum.val
};
- trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llval)
+ let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR]));
+ let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA]));
+ trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable)
}
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
callee_ty: Ty<'tcx>,
vtable_index: usize,
- llpair: ValueRef)
+ llself: ValueRef,
+ llvtable: ValueRef)
-> Callee<'blk, 'tcx> {
let _icx = push_ctxt("meth::trans_trait_callee");
let ccx = bcx.ccx();
// Load the data pointer from the object.
- debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})",
+ debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
callee_ty,
vtable_index,
- bcx.val_to_string(llpair));
- let llboxptr = GEPi(bcx, llpair, &[0, abi::FAT_PTR_ADDR]);
- let llbox = Load(bcx, llboxptr);
- let llself = PointerCast(bcx, llbox, Type::i8p(ccx));
+ bcx.val_to_string(llself),
+ bcx.val_to_string(llvtable));
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
let llcallee_ty = match callee_ty.sty {
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
}
};
- let llvtable = Load(bcx,
- PointerCast(bcx,
- GEPi(bcx, llpair,
- &[0, abi::FAT_PTR_EXTRA]),
- Type::vtable(ccx).ptr_to().ptr_to()));
- let mptr = Load(bcx, GEPi(bcx, llvtable, &[0, vtable_index + VTABLE_OFFSET]));
- let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
+ let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
return Callee {
bcx: bcx,
data: TraitItem(MethodData {
- llfn: mptr,
- llself: llself,
+ llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()),
+ llself: PointerCast(bcx, llself, Type::i8p(ccx)),
})
};
}
let llargs = get_params(fcx.llfn);
- // the first argument (`self`) will be a trait object
- let llobject = llargs[fcx.arg_pos(0)];
+ let self_idx = fcx.arg_offset();
+ let llself = llargs[self_idx];
+ let llvtable = llargs[self_idx + 1];
- debug!("trans_object_shim: llobject={}",
- bcx.val_to_string(llobject));
+ debug!("trans_object_shim: llself={}, llvtable={}",
+ bcx.val_to_string(llself), bcx.val_to_string(llvtable));
assert!(!fcx.needs_ret_allocas);
|bcx, _| trans_trait_callee_from_llval(bcx,
method_bare_fn_ty,
method_offset_in_vtable,
- llobject),
- ArgVals(&llargs[fcx.arg_pos(1)..]),
+ llself, llvtable),
+ ArgVals(&llargs[(self_idx + 2)..]),
dest).bcx;
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
Type::struct_(ccx, &[], false)
}
- pub fn vtable(ccx: &CrateContext) -> Type {
- Type::array(&Type::i8p(ccx).ptr_to(), 1)
- }
-
pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
Type::func(&[t], &Type::void(ccx))
}
pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
arg_ty: Ty<'tcx>) -> bool {
- !type_is_immediate(ccx, arg_ty)
+ !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty)
}
pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> bool {
- !type_is_immediate(ccx, ty)
+ arg_is_indirect(ccx, ty)
}
pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
// ... then explicit args.
- let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
- atys.extend(input_tys);
+ for input in &inputs {
+ let arg_ty = type_of_explicit_arg(cx, input);
+
+ if type_is_fat_ptr(cx.tcx(), input) {
+ atys.extend(arg_ty.field_types());
+ } else {
+ atys.push(arg_ty);
+ }
+ }
Type::func(&atys[..], &lloutputtype)
}
}
}
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]])
+#[no_mangle]
+fn helper(_: usize) {
+}
+
+// CHECK: @slice(i8* noalias nonnull readonly, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn slice(_: &[u8]) {
+}
+
+// CHECK: @mutable_slice(i8* noalias nonnull, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn mutable_slice(_: &mut [u8]) {
+}
+
+// CHECK: @unsafe_slice(%UnsafeInner* nonnull, [[USIZE]])
+// unsafe interior means this isn't actually readonly and there may be aliases ...
+#[no_mangle]
+pub fn unsafe_slice(_: &[UnsafeInner]) {
+}
+
+// CHECK: @str(i8* noalias nonnull readonly, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn str(_: &[u8]) {
+}
+
+// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn trait_borrow(_: &Drop) {
+}
+
+// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
+#[no_mangle]
+fn trait_box(_: Box<Drop>) {
+}
+
+// CHECK: { i16*, [[USIZE]] } @return_slice(i16* noalias nonnull readonly, [[USIZE]])
+#[no_mangle]
+fn return_slice(x: &[u16]) -> &[u16] {
+ x
+}
+
// CHECK: noalias i8* @allocator()
#[no_mangle]
#[allocator]
let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
check!(counter; main_pos, outer_pos, inner_pos, aux_pos);
});
-
- // this tests a distinction between two independent calls to the inlined function.
- // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
- inner_further_inlined(counter, main_pos, outer_pos, pos!());
}
#[inline(never)]