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). // when in fact it has minimum size sizeof(int).
bounded = false; bounded = false;
} else { } 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); let llty = trans::type_of(ccx, dummy_sp(), elem_t);
min_size += trans::llsize_of_real(ccx, llty); min_size += trans::llsize_of_real(ccx, llty);
min_align += trans::llalign_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. // We increment a "virtual data pointer" to compute the size.
let lltys = []; let lltys = [];
for typ: ty::t in variants[vid].args { 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)]; 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 trans_objects::trans_obj;
import tvec = trans_vec; import tvec = trans_vec;
// This function now fails if called on a type with dynamic size (as its fn type_of(cx: &@crate_ctxt, sp: &span, t: ty::t)
// return value was always meaningless in that case anyhow). Beware! : type_has_static_size(cx, t) -> TypeRef { type_of_inner(cx, sp, t) }
//
// 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_explicit_args(cx: &@crate_ctxt, sp: &span, inputs: &[ty::arg]) -> fn type_of_explicit_args(cx: &@crate_ctxt, sp: &span, inputs: &[ty::arg]) ->
[TypeRef] { [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)); 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 { fn type_of_inner(cx: &@crate_ctxt, sp: &span, t: ty::t) -> TypeRef {
// Check the cache. // 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, fn type_of_ty_param_kinds_and_ty(lcx: @local_ctxt, sp: &span,
tpt: &ty::ty_param_kinds_and_ty) -> TypeRef { 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(_, _, _, _, _) { ty::ty_fn(_, _, _, _, _) {
let llfnty = let llfnty =
type_of_fn_from_ty(lcx.ccx, sp, tpt.ty, std::vec::len(tpt.kinds)); type_of_fn_from_ty(cx, sp, t, std::vec::len(tpt.kinds));
ret T_fn_pair(*lcx.ccx, llfnty); ret T_fn_pair(*cx, llfnty);
} }
_ { _ {
// fall through // 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 { 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(); } let ccx = bcx_ccx(bcx);
ret type_of(bcx_ccx(bcx), bcx.sp, typ); 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 // 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 { fn size_of(cx: &@block_ctxt, t: ty::t) -> result {
if !ty::type_has_dynamic_size(bcx_tcx(cx), t) { let ccx = bcx_ccx(cx);
ret rslt(cx, llsize_of(type_of(bcx_ccx(cx), cx.sp, t))); 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 { fn align_of(cx: &@block_ctxt, t: ty::t) -> result {
if !ty::type_has_dynamic_size(bcx_tcx(cx), t) { let ccx = bcx_ccx(cx);
ret rslt(cx, llalign_of(type_of(bcx_ccx(cx), cx.sp, t))); 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 { 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); tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
// Here we possibly do a recursive call. // 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)); let this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
if max_size < this_size { max_size = this_size; } 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 { ValueRef {
let raw = PointerCast(bcx, base, T_ptr(T_i8())); let raw = PointerCast(bcx, base, T_ptr(T_i8()));
let bumped = GEP(bcx, raw, [sz]); let bumped = GEP(bcx, raw, [sz]);
if ty::type_has_dynamic_size(bcx_tcx(bcx), t) { ret bumped; } let ccx = bcx_ccx(bcx);
let typ = T_ptr(type_of(bcx_ccx(bcx), bcx.sp, t)); if check type_has_static_size(ccx, t) {
ret PointerCast(bcx, bumped, typ); 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 // 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). // the blob pointer isn't dynamically sized).
let llunionptr: ValueRef; let llunionptr: ValueRef;
if !ty::type_has_dynamic_size(bcx_tcx(cx), tup_ty) { let sp = cx.sp;
let llty = type_of(bcx_ccx(cx), cx.sp, tup_ty); 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)); 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]); let rs = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix as int]);
// Cast the result to the appropriate type, if necessary. // Cast the result to the appropriate type, if necessary.
let val; let rs_ccx = bcx_ccx(rs.bcx);
if !ty::type_has_dynamic_size(bcx_tcx(cx), elem_ty) { let val = if check type_has_static_size(rs_ccx, elem_ty) {
let llelemty = type_of(bcx_ccx(rs.bcx), cx.sp, elem_ty); let llelemty = type_of(rs_ccx, sp, elem_ty);
val = PointerCast(rs.bcx, rs.val, T_ptr(llelemty)); PointerCast(rs.bcx, rs.val, T_ptr(llelemty))
} else { val = rs.val; } }
else { rs.val };
ret rslt(rs.bcx, 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 // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
// wants. // 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); 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 ccx = cx.ccx;
let llsize; let llsize;
let llalign; 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); let llty = type_of(ccx, sp, t);
llsize = llsize_of(llty); llsize = llsize_of(llty);
llalign = llalign_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 // the caller has no idea if it's dealing with something that can be
// passed by value. // passed by value.
let llty; let ccx = cx.ccx;
if ty::type_has_dynamic_size(cx.ccx.tcx, t) { let llty = if check type_has_static_size(ccx, t) {
llty = T_ptr(T_i8()); T_ptr(type_of(ccx, sp, t))
} else { llty = T_ptr(type_of(cx.ccx, sp, t)); } } else { T_ptr(T_i8()) };
let ty_param_count = std::vec::len::<uint>(ty_params); let ty_param_count = std::vec::len::<uint>(ty_params);
let lltyparams = llvm::LLVMGetParam(llfn, 3u); let lltyparams = llvm::LLVMGetParam(llfn, 3u);
let copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs); 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 { 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, fn adaptor_fn(f: val_and_ty_fn, elt_ty: ty::t, cx: &@block_ctxt,
_dst: ValueRef, src: ValueRef) -> @block_ctxt { _dst: ValueRef, src: ValueRef) -> @block_ctxt {
let llptrty; let ccx = bcx_ccx(cx);
if !ty::type_has_dynamic_size(bcx_tcx(cx), elt_ty) { let sp = cx.sp;
let llty = type_of(bcx_ccx(cx), cx.sp, elt_ty); let llptrty =
llptrty = T_ptr(llty); if check type_has_static_size(ccx, elt_ty) {
} else { llptrty = T_ptr(T_ptr(T_i8())); } let llty = type_of(ccx, sp, elt_ty);
T_ptr(llty)
}
else { T_ptr(T_ptr(T_i8())) };
let p = PointerCast(cx, src, llptrty); let p = PointerCast(cx, src, llptrty);
ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty); 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) -> fn memmove_ty(cx: &@block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) ->
result { result {
if ty::type_has_dynamic_size(bcx_tcx(cx), t) { let ccx = bcx_ccx(cx);
let llsz = size_of(cx, t); if check type_has_static_size(ccx, t) {
ret call_memmove(llsz.bcx, dst, src, llsz.val); if ty::type_is_structural(bcx_tcx(cx), t) {
} else if ty::type_is_structural(bcx_tcx(cx), t) { let sp = cx.sp;
let llsz = llsize_of(type_of(bcx_ccx(cx), cx.sp, t)); let llsz = llsize_of(type_of(ccx, sp, t));
ret call_memmove(cx, dst, src, llsz); ret call_memmove(cx, dst, src, llsz);
} else { ret rslt(cx, Store(cx, Load(cx, src), dst)); } } 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);
}
} }
tag copy_action { INIT; DROP_EXISTING; } 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 { 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, 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 // 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 // make tags work, since tags have a different LLVM type depending
// on whether they're boxed or not. // on whether they're boxed or not.
if !ty::type_has_dynamic_size(bcx_tcx(cx), e_ty) { let sub_ccx = bcx_ccx(sub.bcx);
let llety = T_ptr(type_of(bcx_ccx(sub.bcx), e.span, e_ty)); 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); 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); let bcx = move_val_if_temp(sub.bcx, INIT, body, lv, e_ty);
ret rslt(bcx, sub.box); 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 v1: ValueRef = v;
let t1: ty::t = t; let t1: ty::t = t;
let ccx = bcx_ccx(cx); let ccx = bcx_ccx(cx);
let sp = cx.sp;
while true { while true {
alt ty::struct(ccx.tcx, t1) { alt ty::struct(ccx.tcx, t1) {
ty::ty_box(mt) { 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 // to cast this pointer, since statically-sized tag types have
// different types depending on whether they're behind a box // different types depending on whether they're behind a box
// or not. // or not.
if !ty::type_has_dynamic_size(ccx.tcx, mt.ty) { if check type_has_static_size(ccx, t1) {
let llty = type_of(ccx, cx.sp, mt.ty); let llty = type_of(ccx, sp, t1);
v1 = PointerCast(cx, body, T_ptr(llty)); v1 = PointerCast(cx, body, T_ptr(llty));
} else { v1 = body; } } else { v1 = body; }
} }
@ -2416,9 +2464,10 @@ fn autoderef(cx: &@block_ctxt, v: ValueRef, t: ty::t) -> result_t {
} }
t1 = t1 =
ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]); ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]);
if !ty::type_has_dynamic_size(ccx.tcx, t1) { if check type_has_static_size(ccx, t1) {
v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, cx.sp, t1))); v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, sp, t1)));
} }
else {} // FIXME: typestate hack
} }
_ { break; } _ { 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 bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
let ty = ty::mk_imm_box(bcx_tcx(bcx), envty); 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); let llclosure = PointerCast(bcx, fcx.llenv, llty);
// Populate the type parameters from the environment. We need to // 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 bounds_check = ICmp(bcx, lib::llvm::LLVMIntULT, scaled_ix, lim);
let fail_cx = new_sub_block_ctxt(bcx, ~"fail"); let fail_cx = new_sub_block_ctxt(bcx, ~"fail");
let next_cx = new_sub_block_ctxt(bcx, ~"next"); 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); CondBr(bcx, bounds_check, next_cx.llbb, fail_cx.llbb);
// fail: bad bounds check. // fail: bad bounds check.
trans_fail(fail_cx, some::<span>(sp), ~"bounds check"); trans_fail(fail_cx, some::<span>(sp), ~"bounds check");
let elt; let elt = if check type_has_static_size(ncx, unit_ty) {
if ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty) { let elt_1 = GEP(next_cx, body, [ix_val]);
body = PointerCast(next_cx, body, T_ptr(T_i8())); let llunitty = type_of(ncx, sp, unit_ty);
elt = GEP(next_cx, body, [scaled_ix]); PointerCast(next_cx, elt_1, T_ptr(llunitty))
} else {
elt = GEP(next_cx, body, [ix_val]);
// We're crossing a box boundary here, so we may need to pointer cast.
let llunitty = type_of(bcx_ccx(next_cx), sp, unit_ty);
elt = PointerCast(next_cx, elt, T_ptr(llunitty));
} }
else {
body = PointerCast(next_cx, body, T_ptr(T_i8()));
GEP(next_cx, body, [scaled_ix])
};
ret lval_mem(next_cx, elt); ret lval_mem(next_cx, elt);
} }
// The additional bool returned indicates whether it's mem (that is // 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 // represented as an alloca or heap, hence needs a 'load' to be used as an
// immediate). // immediate).
@ -3211,10 +3265,11 @@ fn trans_lval_gen(cx: &@block_ctxt, e: &@ast::expr) -> lval_result {
} }
ty::ty_tag(_, _) { ty::ty_tag(_, _) {
let ety = ty::expr_ty(ccx.tcx, e); let ety = ty::expr_ty(ccx.tcx, e);
let ellty; let sp = e.span;
if ty::type_has_dynamic_size(ccx.tcx, ety) { let ellty = if check type_has_static_size(ccx, ety) {
ellty = T_typaram_ptr(ccx.tn); T_ptr(type_of(ccx, sp, ety))
} else { ellty = T_ptr(type_of(ccx, e.span, ety)); } }
else { T_typaram_ptr(ccx.tn) };
PointerCast(sub.bcx, sub.val, ellty) PointerCast(sub.bcx, sub.val, ellty)
} }
ty::ty_ptr(_) { sub.val } 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 ll_t_in = val_ty(e_res.val);
let t_in = ty::expr_ty(ccx.tcx, e); let t_in = ty::expr_ty(ccx.tcx, e);
let t_out = node_id_type(ccx, id); 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); let ll_t_out = type_of(ccx, e.span, t_out);
tag kind { native_; integral; float; other; } tag kind { native_; integral; float; other; }
@ -3344,6 +3402,11 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: ty::t,
env_ty: ty::t, ty_param_count: uint, env_ty: ty::t, ty_param_count: uint,
target_fn: &option::t<ValueRef>) -> 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 // Here we're not necessarily constructing a thunk in the sense of
// "function with no arguments". The result of compiling 'bind f(foo, // "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. // Give the thunk a name, type, and value.
let s: istr = let s: istr =
mangle_internal_name_by_path_and_seq(cx.ccx, mangle_internal_name_by_path_and_seq(ccx, cx.path, ~"thunk");
cx.path,
~"thunk");
let llthunk_ty: TypeRef = 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 = let llthunk: ValueRef =
decl_internal_fastcall_fn(cx.ccx.llmod, decl_internal_fastcall_fn(ccx.llmod, s, llthunk_ty);
s, llthunk_ty);
// Create a new function context and block context for the thunk, and hold // 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. // 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 // The llenv pointer needs to be the correct size. That size is
// 'closure_ty', which was determined by trans_bind. // 'closure_ty', which was determined by trans_bind.
let closure_ty = ty::mk_imm_box(cx.ccx.tcx, env_ty); let closure_ty = ty::mk_imm_box(ccx.tcx, env_ty);
let llclosure_ptr_ty = type_of(cx.ccx, sp, closure_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 = let llclosure =
PointerCast(copy_args_bcx, fcx.llenv, llclosure_ptr_ty); 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; 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 // Arrange for the bound function to live in the first binding spot
// if the function is not statically known. // 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 // Cast the function we are binding to be the type that the
// closure will expect it to have. The type the closure knows // closure will expect it to have. The type the closure knows
// about has the type parameters substituted with the real types. // about has the type parameters substituted with the real types.
let llclosurety = let sp = cx.sp;
T_ptr(type_of(bcx_ccx(cx), cx.sp, outgoing_fty)); let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
let src_loc = PointerCast(bcx, f_res.res.val, llclosurety); let src_loc = PointerCast(bcx, f_res.res.val, llclosurety);
let bound_f = {res: {bcx: bcx, val: src_loc} with f_res}; let bound_f = {res: {bcx: bcx, val: src_loc} with f_res};
([outgoing_fty], [bound_f], none) ([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 { fn zero_alloca(cx: &@block_ctxt, llptr: ValueRef, t: ty::t) -> result {
let bcx = cx; 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); let llsz = size_of(bcx, t);
// FIXME passing in the align here is correct, but causes issue #843 // FIXME passing in the align here is correct, but causes issue #843
// let llalign = align_of(llsz.bcx, t); // let llalign = align_of(llsz.bcx, t);
bcx = call_bzero(llsz.bcx, llptr, llsz.val, C_int(0)).bcx; 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); 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 { fn alloc_ty(cx: &@block_ctxt, t: ty::t) -> result {
let bcx = cx; let bcx = cx;
let val = C_int(0); let ccx = bcx_ccx(cx);
if ty::type_has_dynamic_size(bcx_tcx(bcx), t) { 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 // NB: we have to run this particular 'size_of' in a
// block_ctxt built on the llderivedtydescs block for the fn, // block_ctxt built on the llderivedtydescs block for the fn,
// so that the size dominates the array_alloca that // 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); let n = size_of(llderivedtydescs_block_ctxt(bcx.fcx), t);
bcx.fcx.llderivedtydescs = n.bcx.llbb; bcx.fcx.llderivedtydescs = n.bcx.llbb;
val = dynastack_alloca(bcx, T_i8(), n.val, t); dynastack_alloca(bcx, T_i8(), n.val, t)
} else { };
val = alloca(bcx, type_of(bcx_ccx(cx), cx.sp, t));
}
// NB: since we've pushed all size calculations in this // NB: since we've pushed all size calculations in this
// function up to the alloca block, we actually return the // function up to the alloca block, we actually return the
// block passed into us unmodified; it doesn't really // 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 // fields pointer to the appropriate LLVM type. If not, just leave it as
// i8 *. // i8 *.
if !ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty) { let ccx = fcx.lcx.ccx;
let llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty); 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)); 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; let i: int = 0;
for p: ast::ty_param in fcx.lcx.obj_typarams { for p: ast::ty_param in fcx.lcx.obj_typarams {
let lltyparam: ValueRef = let lltyparam: ValueRef =
@ -5644,8 +5720,13 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[istr],
mode: ty::mode) -> ValueRef { mode: ty::mode) -> ValueRef {
if mode == ty::mo_val { if mode == ty::mo_val {
if ty::type_is_integral(bcx_tcx(cx), t) { 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 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) > if llvm::LLVMGetIntTypeWidth(lldsttype) >
llvm::LLVMGetIntTypeWidth(llsrctype) { llvm::LLVMGetIntTypeWidth(llsrctype) {
ret ZExtOrBitCast(cx, v, T_int()); 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} { {val: ValueRef, rptr: ValueRef} {
let call_arg_tys: [TypeRef] = []; let call_arg_tys: [TypeRef] = [];
for arg: ValueRef in call_args { call_arg_tys += [val_ty(arg)]; } for arg: ValueRef in call_args { call_arg_tys += [val_ty(arg)]; }
let ccx = bcx_ccx(bcx);
let llnativefnty; let llnativefnty =
if uses_retptr { if uses_retptr { T_fn(call_arg_tys, T_void()) }
llnativefnty = T_fn(call_arg_tys, T_void()); else {
} else { let fn_ret_ty = ty::ty_fn_ret(bcx_tcx(bcx), fn_type);
llnativefnty = // FIXME: Could follow from a constraint on fn_type...
T_fn(call_arg_tys, check type_has_static_size(ccx, fn_ret_ty);
type_of(bcx_ccx(bcx), bcx.sp, let sp = bcx.sp;
ty::ty_fn_ret(bcx_tcx(bcx), fn_type))); T_fn(call_arg_tys, type_of(ccx, sp, fn_ret_ty))
} };
let llnativefn = let llnativefn =
get_extern_fn(bcx_ccx(bcx).externs, bcx_ccx(bcx).llmod, name, cc, get_extern_fn(ccx.externs, ccx.llmod, name, cc, llnativefnty);
llnativefnty);
let r = let r =
if cc == lib::llvm::LLVMCCallConv { if cc == lib::llvm::LLVMCCallConv {
Call(bcx, llnativefn, call_args) 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], mangle_exported_name(ccx, pt + [i.ident],
node_id_type(ccx, i.id)); node_id_type(ccx, i.id));
let g = str::as_buf(s, { |buf| 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) llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ), buf)
}); });
ccx.item_symbols.insert(i.id, s); 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(_) { ast::pat_bind(_) {
if make_copy { if make_copy {
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id); 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 llty = trans::type_of(ccx, pat.span, ty);
let alloc = trans::alloca(bcx, llty); let alloc = trans::alloca(bcx, llty);
bcx = trans::copy_val(bcx, trans::INIT, alloc, 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: // Local Variables:
// mode: rust // 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, [], create_object_body_type(cx.ccx.tcx, additional_field_tys, [],
some(inner_obj_ty)); some(inner_obj_ty));
// And cast to that type. // 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 = llself_obj_body =
PointerCast(bcx, 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. // Now, reach into the body and grab the inner_obj.
let llinner_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 { pure fn type_has_dynamic_size(cx: &ctxt, ty: t) -> bool {
ret type_structurally_contains(cx, ty, fn(sty: &sty) -> 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 { ret alt sty {
ty_param(_, _) { true } ty_param(_, _) { true }
_ { false } _ { false }
}; };
}); })
}
} }
fn type_is_integral(cx: &ctxt, ty: t) -> bool { fn type_is_integral(cx: &ctxt, ty: t) -> bool {