Add a constraint to trans::type_of

trans::type_of now has a constraint saying that its type argument
is statically sized. This eliminates the "impossible happened" case
in type_of. Yay!

I note that this change decreased translation time for stage2/rustc
from 16.1 s to 14.0 s. I also think many of the remaining checks
could be eliminated with some mildly clever use of constrained types
and further preconditions. Future work!
This commit is contained in:
Tim Chevalier 2011-09-02 18:59:22 -07:00
parent bdd0417cec
commit b5f9053423
6 changed files with 231 additions and 116 deletions

View file

@ -126,6 +126,11 @@ fn largest_variants(ccx: &@crate_ctxt, tag_id: &ast::def_id) -> [uint] {
// when in fact it has minimum size sizeof(int).
bounded = false;
} else {
// Could avoid this check: the constraint should
// follow from how elem_t doesn't contain params.
// (Could add a postcondition to type_contains_params,
// once we implement Issue #586.)
check trans_common::type_has_static_size(ccx, elem_t);
let llty = trans::type_of(ccx, dummy_sp(), elem_t);
min_size += trans::llsize_of_real(ccx, llty);
min_align += trans::llalign_of_real(ccx, llty);
@ -201,6 +206,10 @@ fn compute_static_tag_size(ccx: &@crate_ctxt, largest_variants: &[uint],
// We increment a "virtual data pointer" to compute the size.
let lltys = [];
for typ: ty::t in variants[vid].args {
// FIXME: there should really be a postcondition
// on tag_variants that would obviate the need for
// this check. (Issue #586)
check trans_common::type_has_static_size(ccx, typ);
lltys += [trans::type_of(ccx, dummy_sp(), typ)];
}

View file

@ -74,18 +74,8 @@ import trans_objects::trans_anon_obj;
import trans_objects::trans_obj;
import tvec = trans_vec;
// This function now fails if called on a type with dynamic size (as its
// return value was always meaningless in that case anyhow). Beware!
//
// TODO: Enforce via a predicate.
fn type_of(cx: &@crate_ctxt, sp: &span, t: ty::t) -> TypeRef {
if ty::type_has_dynamic_size(cx.tcx, t) {
cx.sess.span_fatal(sp,
~"type_of() called on a type with dynamic size: " +
ty_to_str(cx.tcx, t));
}
ret type_of_inner(cx, sp, t);
}
fn type_of(cx: &@crate_ctxt, sp: &span, t: ty::t)
: type_has_static_size(cx, t) -> TypeRef { type_of_inner(cx, sp, t) }
fn type_of_explicit_args(cx: &@crate_ctxt, sp: &span, inputs: &[ty::arg]) ->
[TypeRef] {
@ -171,6 +161,8 @@ fn type_of_native_fn(cx: &@crate_ctxt, sp: &span, abi: ast::native_abi,
ret T_fn(atys, type_of_inner(cx, sp, output));
}
/* FIXME: could add type_has_static_size as a constraint,
allowing us to get rid of some impossible cases. */
fn type_of_inner(cx: &@crate_ctxt, sp: &span, t: ty::t) -> TypeRef {
// Check the cache.
@ -263,23 +255,33 @@ fn type_of_tag(cx: &@crate_ctxt, sp: &span, did: &ast::def_id, t: ty::t) ->
fn type_of_ty_param_kinds_and_ty(lcx: @local_ctxt, sp: &span,
tpt: &ty::ty_param_kinds_and_ty) -> TypeRef {
alt ty::struct(lcx.ccx.tcx, tpt.ty) {
let cx = lcx.ccx;
let t = tpt.ty;
alt ty::struct(cx.tcx, t) {
ty::ty_fn(_, _, _, _, _) {
let llfnty =
type_of_fn_from_ty(lcx.ccx, sp, tpt.ty, std::vec::len(tpt.kinds));
ret T_fn_pair(*lcx.ccx, llfnty);
type_of_fn_from_ty(cx, sp, t, std::vec::len(tpt.kinds));
ret T_fn_pair(*cx, llfnty);
}
_ {
// fall through
}
}
ret type_of(lcx.ccx, sp, tpt.ty);
// FIXME: could have a precondition on tpt, but that
// doesn't work right now because one predicate can't imply
// another
check type_has_static_size(cx, t);
type_of(cx, sp, t)
}
fn type_of_or_i8(bcx: &@block_ctxt, typ: ty::t) -> TypeRef {
if ty::type_has_dynamic_size(bcx_tcx(bcx), typ) { ret T_i8(); }
ret type_of(bcx_ccx(bcx), bcx.sp, typ);
}
let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, typ) {
let sp = bcx.sp;
type_of(ccx, sp, typ)
}
else { T_i8() }
}
// Name sanitation. LLVM will happily accept identifiers with weird names, but
@ -452,17 +454,25 @@ fn llalign_of(t: TypeRef) -> ValueRef {
}
fn size_of(cx: &@block_ctxt, t: ty::t) -> result {
if !ty::type_has_dynamic_size(bcx_tcx(cx), t) {
ret rslt(cx, llsize_of(type_of(bcx_ccx(cx), cx.sp, t)));
let ccx = bcx_ccx(cx);
if check type_has_static_size(ccx, t) {
let sp = cx.sp;
rslt(cx, llsize_of(type_of(ccx, sp, t)))
}
else {
dynamic_size_of(cx, t)
}
ret dynamic_size_of(cx, t);
}
fn align_of(cx: &@block_ctxt, t: ty::t) -> result {
if !ty::type_has_dynamic_size(bcx_tcx(cx), t) {
ret rslt(cx, llalign_of(type_of(bcx_ccx(cx), cx.sp, t)));
let ccx = bcx_ccx(cx);
if check type_has_static_size(ccx, t) {
let sp = cx.sp;
rslt(cx, llalign_of(type_of(ccx, sp, t)))
}
else {
dynamic_align_of(cx, t)
}
ret dynamic_align_of(cx, t);
}
fn alloca(cx: &@block_ctxt, t: TypeRef) -> ValueRef {
@ -551,6 +561,10 @@ fn static_size_of_tag(cx: &@crate_ctxt, sp: &span, t: ty::t) -> uint {
tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
// Here we possibly do a recursive call.
// FIXME: Avoid this check. Since the parent has static
// size, any field must as well. There should be a way to
// express that with constrained types.
check type_has_static_size(cx, tup_ty);
let this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
if max_size < this_size { max_size = this_size; }
}
@ -682,9 +696,13 @@ fn bump_ptr(bcx: &@block_ctxt, t: ty::t, base: ValueRef, sz: ValueRef) ->
ValueRef {
let raw = PointerCast(bcx, base, T_ptr(T_i8()));
let bumped = GEP(bcx, raw, [sz]);
if ty::type_has_dynamic_size(bcx_tcx(bcx), t) { ret bumped; }
let typ = T_ptr(type_of(bcx_ccx(bcx), bcx.sp, t));
ret PointerCast(bcx, bumped, typ);
let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, t) {
let sp = bcx.sp;
let typ = T_ptr(type_of(ccx, sp, t));
PointerCast(bcx, bumped, typ)
}
else { bumped }
}
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
@ -800,20 +818,25 @@ fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: &ast::def_id,
// the blob pointer isn't dynamically sized).
let llunionptr: ValueRef;
if !ty::type_has_dynamic_size(bcx_tcx(cx), tup_ty) {
let llty = type_of(bcx_ccx(cx), cx.sp, tup_ty);
let sp = cx.sp;
let ccx = bcx_ccx(cx);
if check type_has_static_size(ccx, tup_ty) {
let llty = type_of(ccx, sp, tup_ty);
llunionptr = TruncOrBitCast(cx, llblobptr, T_ptr(llty));
} else { llunionptr = llblobptr; }
// Do the GEP_tup_like().
}
else { llunionptr = llblobptr; }
// Do the GEP_tup_like().
let rs = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix as int]);
// Cast the result to the appropriate type, if necessary.
let val;
if !ty::type_has_dynamic_size(bcx_tcx(cx), elem_ty) {
let llelemty = type_of(bcx_ccx(rs.bcx), cx.sp, elem_ty);
val = PointerCast(rs.bcx, rs.val, T_ptr(llelemty));
} else { val = rs.val; }
let rs_ccx = bcx_ccx(rs.bcx);
let val = if check type_has_static_size(rs_ccx, elem_ty) {
let llelemty = type_of(rs_ccx, sp, elem_ty);
PointerCast(rs.bcx, rs.val, T_ptr(llelemty))
}
else { rs.val };
ret rslt(rs.bcx, val);
}
@ -863,7 +886,12 @@ fn trans_malloc_boxed_raw(cx: &@block_ctxt, t: ty::t) -> result {
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
// wants.
let llty = type_of(bcx_ccx(cx), cx.sp, box_ptr);
// FIXME: Could avoid this check with a postcondition on mk_imm_box?
// (requires Issue #586)
let ccx = bcx_ccx(cx);
let sp = cx.sp;
check type_has_static_size(ccx, box_ptr);
let llty = type_of(ccx, sp, box_ptr);
ret trans_raw_malloc(sz.bcx, llty, sz.val);
}
@ -1123,7 +1151,7 @@ fn declare_tydesc(cx: &@local_ctxt, sp: &span, t: ty::t, ty_params: &[uint])
let ccx = cx.ccx;
let llsize;
let llalign;
if !ty::type_has_dynamic_size(ccx.tcx, t) {
if check type_has_static_size(ccx, t) {
let llty = type_of(ccx, sp, t);
llsize = llsize_of(llty);
llalign = llalign_of(llty);
@ -1187,10 +1215,11 @@ fn make_generic_glue_inner(cx: &@local_ctxt, sp: &span, t: ty::t,
// the caller has no idea if it's dealing with something that can be
// passed by value.
let llty;
if ty::type_has_dynamic_size(cx.ccx.tcx, t) {
llty = T_ptr(T_i8());
} else { llty = T_ptr(type_of(cx.ccx, sp, t)); }
let ccx = cx.ccx;
let llty = if check type_has_static_size(ccx, t) {
T_ptr(type_of(ccx, sp, t))
} else { T_ptr(T_i8()) };
let ty_param_count = std::vec::len::<uint>(ty_params);
let lltyparams = llvm::LLVMGetParam(llfn, 3u);
let copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
@ -1784,11 +1813,15 @@ fn iter_sequence_inner(cx: &@block_ctxt, src: ValueRef,
elt_ty: &ty::t, f: &val_and_ty_fn) -> @block_ctxt {
fn adaptor_fn(f: val_and_ty_fn, elt_ty: ty::t, cx: &@block_ctxt,
_dst: ValueRef, src: ValueRef) -> @block_ctxt {
let llptrty;
if !ty::type_has_dynamic_size(bcx_tcx(cx), elt_ty) {
let llty = type_of(bcx_ccx(cx), cx.sp, elt_ty);
llptrty = T_ptr(llty);
} else { llptrty = T_ptr(T_ptr(T_i8())); }
let ccx = bcx_ccx(cx);
let sp = cx.sp;
let llptrty =
if check type_has_static_size(ccx, elt_ty) {
let llty = type_of(ccx, sp, elt_ty);
T_ptr(llty)
}
else { T_ptr(T_ptr(T_i8())) };
let p = PointerCast(cx, src, llptrty);
ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
}
@ -2083,13 +2116,18 @@ fn call_bzero(cx: &@block_ctxt, dst: ValueRef, n_bytes: ValueRef,
fn memmove_ty(cx: &@block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) ->
result {
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
let ccx = bcx_ccx(cx);
if check type_has_static_size(ccx, t) {
if ty::type_is_structural(bcx_tcx(cx), t) {
let sp = cx.sp;
let llsz = llsize_of(type_of(ccx, sp, t));
ret call_memmove(cx, dst, src, llsz);
} else { ret rslt(cx, Store(cx, Load(cx, src), dst)); }
}
else {
let llsz = size_of(cx, t);
ret call_memmove(llsz.bcx, dst, src, llsz.val);
} else if ty::type_is_structural(bcx_tcx(cx), t) {
let llsz = llsize_of(type_of(bcx_ccx(cx), cx.sp, t));
ret call_memmove(cx, dst, src, llsz);
} else { ret rslt(cx, Store(cx, Load(cx, src), dst)); }
}
}
tag copy_action { INIT; DROP_EXISTING; }
@ -2259,7 +2297,12 @@ fn node_id_type(cx: &@crate_ctxt, id: ast::node_id) -> ty::t {
}
fn node_type(cx: &@crate_ctxt, sp: &span, id: ast::node_id) -> TypeRef {
ret type_of(cx, sp, node_id_type(cx, id));
let ty = node_id_type(cx, id);
// How to make this a precondition?
// FIXME (again, would require a predicate that implies
// another predicate)
check type_has_static_size(cx, ty);
type_of(cx, sp, ty)
}
fn trans_unary(cx: &@block_ctxt, op: ast::unop, e: &@ast::expr,
@ -2286,10 +2329,14 @@ fn trans_unary(cx: &@block_ctxt, op: ast::unop, e: &@ast::expr,
// Cast the body type to the type of the value. This is needed to
// make tags work, since tags have a different LLVM type depending
// on whether they're boxed or not.
if !ty::type_has_dynamic_size(bcx_tcx(cx), e_ty) {
let llety = T_ptr(type_of(bcx_ccx(sub.bcx), e.span, e_ty));
let sub_ccx = bcx_ccx(sub.bcx);
if check type_has_static_size(sub_ccx, e_ty) {
let e_sp = e.span;
let llety = T_ptr(type_of(sub_ccx, e_sp, e_ty));
body = PointerCast(sub.bcx, body, llety);
}
else {} // FIXME: can remove the else{} once we have
// a new snapshot
let bcx = move_val_if_temp(sub.bcx, INIT, body, lv, e_ty);
ret rslt(bcx, sub.box);
}
@ -2387,6 +2434,7 @@ fn autoderef(cx: &@block_ctxt, v: ValueRef, t: ty::t) -> result_t {
let v1: ValueRef = v;
let t1: ty::t = t;
let ccx = bcx_ccx(cx);
let sp = cx.sp;
while true {
alt ty::struct(ccx.tcx, t1) {
ty::ty_box(mt) {
@ -2398,8 +2446,8 @@ fn autoderef(cx: &@block_ctxt, v: ValueRef, t: ty::t) -> result_t {
// to cast this pointer, since statically-sized tag types have
// different types depending on whether they're behind a box
// or not.
if !ty::type_has_dynamic_size(ccx.tcx, mt.ty) {
let llty = type_of(ccx, cx.sp, mt.ty);
if check type_has_static_size(ccx, t1) {
let llty = type_of(ccx, sp, t1);
v1 = PointerCast(cx, body, T_ptr(llty));
} else { v1 = body; }
}
@ -2416,9 +2464,10 @@ fn autoderef(cx: &@block_ctxt, v: ValueRef, t: ty::t) -> result_t {
}
t1 =
ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]);
if !ty::type_has_dynamic_size(ccx.tcx, t1) {
v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, cx.sp, t1)));
if check type_has_static_size(ccx, t1) {
v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, sp, t1)));
}
else {} // FIXME: typestate hack
}
_ { break; }
}
@ -2756,7 +2805,13 @@ fn load_environment(enclosing_cx: &@block_ctxt, fcx: &@fn_ctxt, envty: ty::t,
let bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
let ty = ty::mk_imm_box(bcx_tcx(bcx), envty);
let llty = type_of(bcx_ccx(bcx), bcx.sp, ty);
let ccx = bcx_ccx(bcx);
let sp = bcx.sp;
// FIXME: should have postcondition on mk_imm_box,
// so this check won't be necessary
check type_has_static_size(ccx, ty);
let llty = type_of(ccx, sp, ty);
let llclosure = PointerCast(bcx, fcx.llenv, llty);
// Populate the type parameters from the environment. We need to
@ -3161,25 +3216,24 @@ fn trans_index(cx: &@block_ctxt, sp: &span, base: &@ast::expr,
let bounds_check = ICmp(bcx, lib::llvm::LLVMIntULT, scaled_ix, lim);
let fail_cx = new_sub_block_ctxt(bcx, ~"fail");
let next_cx = new_sub_block_ctxt(bcx, ~"next");
let ncx = bcx_ccx(next_cx);
CondBr(bcx, bounds_check, next_cx.llbb, fail_cx.llbb);
// fail: bad bounds check.
trans_fail(fail_cx, some::<span>(sp), ~"bounds check");
let elt;
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) {
body = PointerCast(next_cx, body, T_ptr(T_i8()));
elt = GEP(next_cx, body, [scaled_ix]);
} else {
elt = GEP(next_cx, body, [ix_val]);
// We're crossing a box boundary here, so we may need to pointer cast.
let elt = if check type_has_static_size(ncx, unit_ty) {
let elt_1 = GEP(next_cx, body, [ix_val]);
let llunitty = type_of(ncx, sp, unit_ty);
PointerCast(next_cx, elt_1, T_ptr(llunitty))
}
else {
body = PointerCast(next_cx, body, T_ptr(T_i8()));
GEP(next_cx, body, [scaled_ix])
};
let llunitty = type_of(bcx_ccx(next_cx), sp, unit_ty);
elt = PointerCast(next_cx, elt, T_ptr(llunitty));
}
ret lval_mem(next_cx, elt);
}
// The additional bool returned indicates whether it's mem (that is
// represented as an alloca or heap, hence needs a 'load' to be used as an
// immediate).
@ -3211,10 +3265,11 @@ fn trans_lval_gen(cx: &@block_ctxt, e: &@ast::expr) -> lval_result {
}
ty::ty_tag(_, _) {
let ety = ty::expr_ty(ccx.tcx, e);
let ellty;
if ty::type_has_dynamic_size(ccx.tcx, ety) {
ellty = T_typaram_ptr(ccx.tn);
} else { ellty = T_ptr(type_of(ccx, e.span, ety)); }
let sp = e.span;
let ellty = if check type_has_static_size(ccx, ety) {
T_ptr(type_of(ccx, sp, ety))
}
else { T_typaram_ptr(ccx.tn) };
PointerCast(sub.bcx, sub.val, ellty)
}
ty::ty_ptr(_) { sub.val }
@ -3291,6 +3346,9 @@ fn trans_cast(cx: &@block_ctxt, e: &@ast::expr, id: ast::node_id) -> result {
let ll_t_in = val_ty(e_res.val);
let t_in = ty::expr_ty(ccx.tcx, e);
let t_out = node_id_type(ccx, id);
// Check should be avoidable because it's a cast.
// FIXME: Constrain types so as to avoid this check.
check type_has_static_size(ccx, t_out);
let ll_t_out = type_of(ccx, e.span, t_out);
tag kind { native_; integral; float; other; }
@ -3343,7 +3401,12 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: ty::t,
outgoing_fty: ty::t, args: &[option::t<@ast::expr>],
env_ty: ty::t, ty_param_count: uint,
target_fn: &option::t<ValueRef>) ->
{val: ValueRef, ty: TypeRef} {
{val: ValueRef, ty: TypeRef} {
// FIXME
// This should be a precondition on trans_bind_thunk, but we would need
// to support record fields as constraint args
let ccx = cx.ccx;
check type_has_static_size(ccx, incoming_fty);
// Here we're not necessarily constructing a thunk in the sense of
// "function with no arguments". The result of compiling 'bind f(foo,
@ -3368,14 +3431,11 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: ty::t,
// Give the thunk a name, type, and value.
let s: istr =
mangle_internal_name_by_path_and_seq(cx.ccx,
cx.path,
~"thunk");
mangle_internal_name_by_path_and_seq(ccx, cx.path, ~"thunk");
let llthunk_ty: TypeRef =
get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty));
get_pair_fn_ty(type_of(ccx, sp, incoming_fty));
let llthunk: ValueRef =
decl_internal_fastcall_fn(cx.ccx.llmod,
s, llthunk_ty);
decl_internal_fastcall_fn(ccx.llmod, s, llthunk_ty);
// Create a new function context and block context for the thunk, and hold
// onto a pointer to the first block in the function for later use.
@ -3394,8 +3454,11 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: ty::t,
// The llenv pointer needs to be the correct size. That size is
// 'closure_ty', which was determined by trans_bind.
let closure_ty = ty::mk_imm_box(cx.ccx.tcx, env_ty);
let llclosure_ptr_ty = type_of(cx.ccx, sp, closure_ty);
let closure_ty = ty::mk_imm_box(ccx.tcx, env_ty);
// FIXME: would be nice to have a postcondition on mk_imm_box
// (Issue #586)
check type_has_static_size(ccx, closure_ty);
let llclosure_ptr_ty = type_of(ccx, sp, closure_ty);
let llclosure =
PointerCast(copy_args_bcx, fcx.llenv, llclosure_ptr_ty);
@ -3554,6 +3617,9 @@ fn trans_bind_1(cx: &@block_ctxt, f: &@ast::expr, f_res: &lval_result,
}
let bcx = f_res.res.bcx;
// FIXME: should follow from a precondition on trans_bind_1
let ccx = bcx_ccx(cx);
check type_has_static_size(ccx, outgoing_fty);
// Arrange for the bound function to live in the first binding spot
// if the function is not statically known.
@ -3562,8 +3628,8 @@ fn trans_bind_1(cx: &@block_ctxt, f: &@ast::expr, f_res: &lval_result,
// Cast the function we are binding to be the type that the
// closure will expect it to have. The type the closure knows
// about has the type parameters substituted with the real types.
let llclosurety =
T_ptr(type_of(bcx_ccx(cx), cx.sp, outgoing_fty));
let sp = cx.sp;
let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
let src_loc = PointerCast(bcx, f_res.res.val, llclosurety);
let bound_f = {res: {bcx: bcx, val: src_loc} with f_res};
([outgoing_fty], [bound_f], none)
@ -4545,14 +4611,17 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
fn zero_alloca(cx: &@block_ctxt, llptr: ValueRef, t: ty::t) -> result {
let bcx = cx;
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
let ccx = bcx_ccx(cx);
if check type_has_static_size(ccx, t) {
let sp = cx.sp;
let llty = type_of(ccx, sp, t);
Store(bcx, C_null(llty), llptr);
}
else {
let llsz = size_of(bcx, t);
// FIXME passing in the align here is correct, but causes issue #843
// let llalign = align_of(llsz.bcx, t);
bcx = call_bzero(llsz.bcx, llptr, llsz.val, C_int(0)).bcx;
} else {
let llty = type_of(bcx_ccx(bcx), cx.sp, t);
Store(bcx, C_null(llty), llptr);
}
ret rslt(bcx, llptr);
}
@ -4713,8 +4782,12 @@ fn llderivedtydescs_block_ctxt(fcx: &@fn_ctxt) -> @block_ctxt {
fn alloc_ty(cx: &@block_ctxt, t: ty::t) -> result {
let bcx = cx;
let val = C_int(0);
if ty::type_has_dynamic_size(bcx_tcx(bcx), t) {
let ccx = bcx_ccx(cx);
let val = if check type_has_static_size(ccx, t) {
let sp = cx.sp;
alloca(bcx, type_of(ccx, sp, t))
}
else {
// NB: we have to run this particular 'size_of' in a
// block_ctxt built on the llderivedtydescs block for the fn,
// so that the size dominates the array_alloca that
@ -4722,10 +4795,9 @@ fn alloc_ty(cx: &@block_ctxt, t: ty::t) -> result {
let n = size_of(llderivedtydescs_block_ctxt(bcx.fcx), t);
bcx.fcx.llderivedtydescs = n.bcx.llbb;
val = dynastack_alloca(bcx, T_i8(), n.val, t);
} else {
val = alloca(bcx, type_of(bcx_ccx(cx), cx.sp, t));
}
dynastack_alloca(bcx, T_i8(), n.val, t)
};
// NB: since we've pushed all size calculations in this
// function up to the alloca block, we actually return the
// block passed into us unmodified; it doesn't really
@ -5035,10 +5107,14 @@ fn populate_fn_ctxt_from_llself(fcx: @fn_ctxt, llself: val_self_pair) {
// fields pointer to the appropriate LLVM type. If not, just leave it as
// i8 *.
if !ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty) {
let llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty);
let ccx = fcx.lcx.ccx;
if check type_has_static_size(ccx, fields_tup_ty) {
let sp = fcx.sp;
let llfields_ty = type_of(ccx, sp, fields_tup_ty);
obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
} else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
}
else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
let i: int = 0;
for p: ast::ty_param in fcx.lcx.obj_typarams {
let lltyparam: ValueRef =
@ -5644,8 +5720,13 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[istr],
mode: ty::mode) -> ValueRef {
if mode == ty::mo_val {
if ty::type_is_integral(bcx_tcx(cx), t) {
// FIXME: would be nice to have a postcondition that says
// if a type is integral, then it has static size (#586)
let lldsttype = T_int();
let llsrctype = type_of(bcx_ccx(cx), cx.sp, t);
let ccx = bcx_ccx(cx);
let sp = cx.sp;
check type_has_static_size(ccx, t);
let llsrctype = type_of(ccx, sp, t);
if llvm::LLVMGetIntTypeWidth(lldsttype) >
llvm::LLVMGetIntTypeWidth(llsrctype) {
ret ZExtOrBitCast(cx, v, T_int());
@ -5665,20 +5746,20 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[istr],
{val: ValueRef, rptr: ValueRef} {
let call_arg_tys: [TypeRef] = [];
for arg: ValueRef in call_args { call_arg_tys += [val_ty(arg)]; }
let ccx = bcx_ccx(bcx);
let llnativefnty;
if uses_retptr {
llnativefnty = T_fn(call_arg_tys, T_void());
} else {
llnativefnty =
T_fn(call_arg_tys,
type_of(bcx_ccx(bcx), bcx.sp,
ty::ty_fn_ret(bcx_tcx(bcx), fn_type)));
}
let llnativefnty =
if uses_retptr { T_fn(call_arg_tys, T_void()) }
else {
let fn_ret_ty = ty::ty_fn_ret(bcx_tcx(bcx), fn_type);
// FIXME: Could follow from a constraint on fn_type...
check type_has_static_size(ccx, fn_ret_ty);
let sp = bcx.sp;
T_fn(call_arg_tys, type_of(ccx, sp, fn_ret_ty))
};
let llnativefn =
get_extern_fn(bcx_ccx(bcx).externs, bcx_ccx(bcx).llmod, name, cc,
llnativefnty);
get_extern_fn(ccx.externs, ccx.llmod, name, cc, llnativefnty);
let r =
if cc == lib::llvm::LLVMCCallConv {
Call(bcx, llnativefn, call_args)
@ -5767,6 +5848,9 @@ fn collect_item_1(ccx: @crate_ctxt, i: &@ast::item, pt: &[istr],
mangle_exported_name(ccx, pt + [i.ident],
node_id_type(ccx, i.id));
let g = str::as_buf(s, { |buf|
// FIXME: Could follow from a constraint on types of const
// items
check type_has_static_size(ccx, typ);
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ), buf)
});
ccx.item_symbols.insert(i.id, s);

View file

@ -563,6 +563,9 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
ast::pat_bind(_) {
if make_copy {
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
// FIXME: Could constrain pat_bind to make this
// check unnecessary.
check type_has_static_size(ccx, ty);
let llty = trans::type_of(ccx, pat.span, ty);
let alloc = trans::alloca(bcx, llty);
bcx = trans::copy_val(bcx, trans::INIT, alloc,

View file

@ -858,6 +858,10 @@ pure fn valid_variant_index(ix:uint, cx:@block_ctxt, tag_id: &ast::def_id,
}
}
pure fn type_has_static_size(cx: &@crate_ctxt, t: ty::t) -> bool {
!ty::type_has_dynamic_size(cx.tcx, t)
}
//
// Local Variables:
// mode: rust

View file

@ -791,9 +791,14 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
create_object_body_type(cx.ccx.tcx, additional_field_tys, [],
some(inner_obj_ty));
// And cast to that type.
// create_object_body_type maybe should have a postcondition...
let cx_ccx = cx.ccx;
check type_has_static_size(cx_ccx, body_ty);
llself_obj_body =
PointerCast(bcx, llself_obj_body,
T_ptr(type_of(cx.ccx, sp, body_ty)));
T_ptr(type_of(cx_ccx, sp, body_ty)));
// Now, reach into the body and grab the inner_obj.
let llinner_obj =

View file

@ -1132,13 +1132,23 @@ fn type_structurally_contains(cx: &ctxt, ty: t,
}
}
fn type_has_dynamic_size(cx: &ctxt, ty: t) -> bool {
ret type_structurally_contains(cx, ty, fn(sty: &sty) -> bool {
pure fn type_has_dynamic_size(cx: &ctxt, ty: t) -> bool {
/* type_structurally_contains can't be declared pure
because it takes a function argument. But it should be
referentially transparent, since a given type's size should
never change once it's created.
(It would be interesting to think about how to make such properties
actually checkable. It seems to me like a lot of properties
that the type context tracks about types should be immutable.)
*/
unchecked {
type_structurally_contains(cx, ty, fn(sty: &sty) -> bool {
ret alt sty {
ty_param(_, _) { true }
_ { false }
};
});
})
}
}
fn type_is_integral(cx: &ctxt, ty: t) -> bool {