From b5f905342337a3dc12bdc5dc6d98d3ecdf60439d Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 2 Sep 2011 18:59:22 -0700 Subject: [PATCH] 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! --- src/comp/middle/shape.rs | 9 + src/comp/middle/trans.rs | 308 ++++++++++++++++++++----------- src/comp/middle/trans_alt.rs | 3 + src/comp/middle/trans_common.rs | 4 + src/comp/middle/trans_objects.rs | 7 +- src/comp/middle/ty.rs | 16 +- 6 files changed, 231 insertions(+), 116 deletions(-) diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index ea6c6d7f987..73627cfc67a 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -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)]; } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 47a63c0d660..315b11340ba 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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::(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::(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) -> - {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); diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index 37327437af0..e81f6b5b97f 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -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, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index a86e077028b..b18f81bb45c 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -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 diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs index 6c70e8aab9f..cb48ef95d6d 100644 --- a/src/comp/middle/trans_objects.rs +++ b/src/comp/middle/trans_objects.rs @@ -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 = diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 7a9d3221539..5b3197b1bd8 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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 {