From 626ad484fecc5703f46812c7916fce6fec03ace9 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Mon, 18 Feb 2013 14:16:21 -0800 Subject: [PATCH 01/37] Unified algebraic datatype representation implementation, initial version. Later changes on this branch adapt the rest of rustc::middle::trans to use this module instead of scattered hard-coded knowledge of representations; a few of them also have improvements or cleanup for adt.rs (and many added comments) that weren't drastic enough to justify changing history to move them into this commit. --- src/librustc/middle/trans/adt.rs | 326 ++++++++++++++++++++++++++++ src/librustc/middle/trans/common.rs | 40 +++- src/librustc/middle/trans/consts.rs | 14 -- src/librustc/rustc.rc | 1 + 4 files changed, 366 insertions(+), 15 deletions(-) create mode 100644 src/librustc/middle/trans/adt.rs diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs new file mode 100644 index 0000000000000..21f113a08aa77 --- /dev/null +++ b/src/librustc/middle/trans/adt.rs @@ -0,0 +1,326 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::option::{Option, Some, None}; +use core::vec; +use lib::llvm::{ValueRef, TypeRef}; +use middle::trans::_match; +use middle::trans::build::*; +use middle::trans::common::*; +use middle::trans::machine; +use middle::trans::type_of; +use middle::ty; +use syntax::ast; +use util::ppaux::ty_to_str; + + +// XXX: should this be done with boxed traits instead of ML-style? +pub enum Repr { + CEnum, + Univariant(Struct, Destructor), + General(~[Struct]) +} + +enum Destructor { + DtorPresent, + DtorAbsent, + NoDtor +} + +struct Struct { + size: u64, + align: u64, + fields: ~[ty::t] +} + + +pub fn represent_node(bcx: block, node: ast::node_id) + -> Repr { + represent_type(bcx.ccx(), node_id_type(bcx, node)) +} + +pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { + debug!("Representing: %s", ty_to_str(cx.tcx, t)); + // XXX: cache this + match ty::get(t).sty { + ty::ty_tup(ref elems) => { + Univariant(mk_struct(cx, *elems), NoDtor) + } + ty::ty_rec(ref fields) => { + // XXX: Are these in the right order? + Univariant(mk_struct(cx, fields.map(|f| f.mt.ty)), DtorAbsent) + } + ty::ty_struct(def_id, ref substs) => { + let fields = ty::lookup_struct_fields(cx.tcx, def_id); + let dt = ty::ty_dtor(cx.tcx, def_id).is_present(); + Univariant(mk_struct(cx, fields.map(|field| { + ty::lookup_field_type(cx.tcx, def_id, field.id, substs) + })), if dt { DtorPresent } else { DtorAbsent }) + } + ty::ty_enum(def_id, ref substs) => { + struct Case { discr: i64, tys: ~[ty::t] }; + + let cases = do ty::enum_variants(cx.tcx, def_id).map |vi| { + let arg_tys = do vi.args.map |&raw_ty| { + ty::subst(cx.tcx, substs, raw_ty) + }; + Case { discr: vi.disr_val /*bad*/as i64, tys: arg_tys } + }; + if cases.len() == 0 { + // Uninhabitable; represent as unit + Univariant(mk_struct(cx, ~[]), NoDtor) + } else if cases.len() == 1 && cases[0].discr == 0 { + // struct, tuple, newtype, etc. + Univariant(mk_struct(cx, cases[0].tys), NoDtor) + } else if cases.all(|c| c.tys.len() == 0) { + CEnum + } else { + if !cases.alli(|i,c| c.discr == (i as i64)) { + cx.sess.bug(fmt!("non-C-like enum %s with specified \ + discriminants", + ty::item_path_str(cx.tcx, def_id))) + } + General(cases.map(|c| mk_struct(cx, c.tys))) + } + } + _ => cx.sess.bug(~"adt::represent_type called on non-ADT type") + } +} + +fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct { + let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty)); + let llty_rec = T_struct(lltys); + Struct { + size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, + align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, + fields: vec::from_slice(tys) + } +} + + +pub fn sizing_fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { + generic_fields_of(cx, r, true) +} +pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { + generic_fields_of(cx, r, false) +} +fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) + -> ~[TypeRef] { + match *r { + CEnum => ~[T_enum_discrim(cx)], + Univariant(ref st, dt) => { + let f = if sizing { + st.fields.map(|&ty| type_of::sizing_type_of(cx, ty)) + } else { + st.fields.map(|&ty| type_of::type_of(cx, ty)) + }; + match dt { + NoDtor => f, + DtorAbsent => ~[T_struct(f)], + DtorPresent => ~[T_struct(f), T_i8()] + } + } + General(ref sts) => { + ~[T_enum_discrim(cx), + T_array(T_i8(), sts.map(|st| st.size).max() /*bad*/as uint)] + } + } +} + +pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> + (_match::branch_kind, Option) { + // XXX: LoadRangeAssert + match *r { + CEnum => { + (_match::switch, Some(Load(bcx, GEPi(bcx, scrutinee, [0, 0])))) + } + Univariant(*) => { + (_match::single, None) + } + General(*) => { + (_match::switch, Some(Load(bcx, GEPi(bcx, scrutinee, [0, 0])))) + } + } +} + +pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { + match *r { + CEnum => { + _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) + } + Univariant(*) => { + bcx.ccx().sess.bug(~"no cases for univariants or structs") + } + General(*) => { + _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) + } + } +} + +pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { + match *r { + CEnum => { + Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) + } + Univariant(_, DtorPresent) => { + assert discr == 0; + Store(bcx, C_u8(1), GEPi(bcx, val, [0, 1])) + } + Univariant(*) => { + assert discr == 0; + } + General(*) => { + Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) + } + } +} + +pub fn num_args(r: &Repr, discr: int) -> uint { + match *r { + CEnum => 0, + Univariant(ref st, _dt) => { assert discr == 0; st.fields.len() } + General(ref cases) => cases[discr as uint].fields.len() + } +} + +pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) + -> ValueRef { + // Note: if this ever needs to generate conditionals (e.g., if we + // decide to do some kind of cdr-coding-like non-unique repr + // someday), it'll need to return a possibly-new bcx as well. + match *r { + CEnum => { + bcx.ccx().sess.bug(~"element access in C-like enum") + } + Univariant(ref st, dt) => { + assert discr == 0; + let val = match dt { + NoDtor => val, + DtorPresent | DtorAbsent => GEPi(bcx, val, [0, 0]) + }; + struct_GEP(bcx, st, val, ix) + } + General(ref cases) => { + struct_GEP(bcx, &cases[discr as uint], + GEPi(bcx, val, [0, 1]), ix) + } + } +} + +fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint) + -> ValueRef { + let ccx = bcx.ccx(); + + let real_llty = T_struct(st.fields.map( + |&ty| type_of::type_of(ccx, ty))); + let cast_val = PointerCast(bcx, val, T_ptr(real_llty)); + + GEPi(bcx, cast_val, [0, ix]) +} + +pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, + vals: &[ValueRef]) -> ValueRef { + match *r { + CEnum => { + assert vals.len() == 0; + C_int(ccx, discr) + } + Univariant(ref st, _dt) => { + assert discr == 0; + // consts are never destroyed, so the dtor flag is not needed + C_struct(build_const_struct(ccx, st, vals)) + } + General(ref cases) => { + let case = &cases[discr as uint]; + let max_sz = cases.map(|s| s.size).max(); + let body = build_const_struct(ccx, case, vals); + + C_struct([C_int(ccx, discr), + C_packed_struct([C_struct(body)]), + padding(max_sz - case.size)]) + } + } +} + +fn padding(size: u64) -> ValueRef { + C_undef(T_array(T_i8(), size /*bad*/as uint)) +} + +fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef]) + -> ~[ValueRef] { + assert vals.len() == st.fields.len(); + + let mut offset = 0; + let mut cfields = ~[]; + for st.fields.eachi |i, &ty| { + let llty = type_of::sizing_type_of(ccx, ty); + let type_align = machine::llalign_of_min(ccx, llty) + /*bad*/as u64; + let val_align = machine::llalign_of_min(ccx, val_ty(vals[i])) + /*bad*/as u64; + let target_offset = roundup(offset, type_align); + offset = roundup(offset, val_align); + if (offset != target_offset) { + cfields.push(padding(target_offset - offset)); + offset = target_offset; + } + assert !is_undef(vals[i]); + // If that assert fails, could change it to wrap in a struct? + cfields.push(vals[i]); + } + + return cfields; +} + +#[always_inline] +fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } + + +pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef) + -> int { + match *r { + CEnum(*) => const_to_int(val) as int, + Univariant(*) => 0, + General(*) => const_to_int(const_get_elt(ccx, val, [0])) as int, + } +} + +pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, + _discr: int, ix: uint) -> ValueRef { + // Not to be confused with common::const_get_elt. + match *r { + CEnum(*) => ccx.sess.bug(~"element access in C-like enum const"), + Univariant(*) => const_struct_field(ccx, val, ix), + General(*) => const_struct_field(ccx, const_get_elt(ccx, val, + [1, 0]), ix) + } +} + +fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint) + -> ValueRef { + // Get the ix-th non-undef element of the struct. + let mut real_ix = 0; // actual position in the struct + let mut ix = ix; // logical index relative to real_ix + let mut field; + loop { + loop { + field = const_get_elt(ccx, val, [real_ix]); + if !is_undef(field) { + break; + } + real_ix = real_ix + 1; + } + if ix == 0 { + return field; + } + ix = ix - 1; + real_ix = real_ix + 1; + } +} diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 2d7149fdfb2bb..2d06a5a5e8788 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -44,7 +44,7 @@ use util::ppaux::{expr_repr, ty_to_str}; use core::cast; use core::hash; -use core::libc::c_uint; +use core::libc::{c_uint, c_longlong, c_ulonglong}; use core::ptr; use core::str; use core::to_bytes; @@ -1087,6 +1087,12 @@ pub fn C_null(t: TypeRef) -> ValueRef { } } +pub fn C_undef(t: TypeRef) -> ValueRef { + unsafe { + return llvm::LLVMGetUndef(t); + } +} + pub fn C_integral(t: TypeRef, u: u64, sign_extend: Bool) -> ValueRef { unsafe { return llvm::LLVMConstInt(t, u, sign_extend); @@ -1254,6 +1260,38 @@ pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef { } } +pub fn const_get_elt(cx: @CrateContext, v: ValueRef, us: &[c_uint]) + -> ValueRef { + unsafe { + let r = do vec::as_imm_buf(us) |p, len| { + llvm::LLVMConstExtractValue(v, p, len as c_uint) + }; + + debug!("const_get_elt(v=%s, us=%?, r=%s)", + val_str(cx.tn, v), us, val_str(cx.tn, r)); + + return r; + } +} + +pub fn const_to_int(v: ValueRef) -> c_longlong { + unsafe { + llvm::LLVMConstIntGetSExtValue(v) + } +} + +pub fn const_to_uint(v: ValueRef) -> c_ulonglong { + unsafe { + llvm::LLVMConstIntGetZExtValue(v) + } +} + +pub fn is_undef(val: ValueRef) -> bool { + unsafe { + llvm::LLVMIsUndef(val) != False + } +} + // Used to identify cached monomorphized functions and vtables #[deriving_eq] pub enum mono_param_id { diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index e585e433ef239..6d37c4393ab9f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -103,20 +103,6 @@ pub fn const_deref(cx: @CrateContext, v: ValueRef) -> ValueRef { } } -pub fn const_get_elt(cx: @CrateContext, v: ValueRef, us: &[c_uint]) - -> ValueRef { - unsafe { - let r = do vec::as_imm_buf(us) |p, len| { - llvm::LLVMConstExtractValue(v, p, len as c_uint) - }; - - debug!("const_get_elt(v=%s, us=%?, r=%s)", - val_str(cx.tn, v), us, val_str(cx.tn, r)); - - return r; - } -} - pub fn const_autoderef(cx: @CrateContext, ty: ty::t, v: ValueRef) -> (ty::t, ValueRef) { let mut t1 = ty; diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index b204c458d659e..355ecaed7d7e0 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -65,6 +65,7 @@ pub mod middle { pub mod type_use; pub mod reachable; pub mod machine; + pub mod adt; } pub mod ty; pub mod resolve; From c4682dcabedaa5451d377aedfb9167f4f299e5e5 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Thu, 28 Feb 2013 11:30:27 -0800 Subject: [PATCH 02/37] Convert match on enums to use trans::adt. --- src/librustc/middle/trans/_match.rs | 134 +++++++++++----------------- 1 file changed, 51 insertions(+), 83 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 2db3cae74e33b..e3f719229aff2 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -151,6 +151,7 @@ use middle::const_eval; use middle::borrowck::root_map_key; use middle::pat_util::*; use middle::resolve::DefMap; +use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee; @@ -191,15 +192,15 @@ pub enum Lit { // range) pub enum Opt { lit(Lit), - var(/* disr val */int, /* variant dids (enm, var) */(def_id, def_id)), + var(/* disr val */int, adt::Repr), range(@ast::expr, @ast::expr), vec_len_eq(uint), vec_len_ge(uint) } pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { - match (*a, *b) { - (lit(a), lit(b)) => { + match (a, b) { + (&lit(a), &lit(b)) => { match (a, b) { (UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b, _ => { @@ -233,13 +234,13 @@ pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { } } } - (range(a1, a2), range(b1, b2)) => { + (&range(a1, a2), &range(b1, b2)) => { const_eval::compare_lit_exprs(tcx, a1, b1) == 0 && const_eval::compare_lit_exprs(tcx, a2, b2) == 0 } - (var(a, _), var(b, _)) => a == b, - (vec_len_eq(a), vec_len_eq(b)) => a == b, - (vec_len_ge(a), vec_len_ge(b)) => a == b, + (&var(a, _), &var(b, _)) => a == b, + (&vec_len_eq(a), &vec_len_eq(b)) => a == b, + (&vec_len_ge(a), &vec_len_ge(b)) => a == b, _ => false } } @@ -267,8 +268,8 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { let llval = consts::get_const_val(bcx.ccx(), lit_id); return single_result(rslt(bcx, llval)); } - var(disr_val, _) => { - return single_result(rslt(bcx, C_int(ccx, disr_val))); + var(disr_val, ref repr) => { + return adt::trans_case(bcx, repr, disr_val); } range(l1, l2) => { return range_result(rslt(bcx, consts::const_expr(ccx, l1)), @@ -283,13 +284,16 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { } } -pub fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> Opt { - match tcx.def_map.get(&pat_id) { +pub fn variant_opt(bcx: block, pat_id: ast::node_id) + -> Opt { + let ccx = bcx.ccx(); + match ccx.tcx.def_map.get(&pat_id) { ast::def_variant(enum_id, var_id) => { - let variants = ty::enum_variants(tcx, enum_id); + let variants = ty::enum_variants(ccx.tcx, enum_id); for vec::each(*variants) |v| { if var_id == v.id { - return var(v.disr_val, (enum_id, var_id)); + return var(v.disr_val, + adt::represent_node(bcx, pat_id)) } } ::core::util::unreachable(); @@ -298,7 +302,7 @@ pub fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> Opt { return lit(UnitLikeStructLit(pat_id)); } _ => { - tcx.sess.bug(~"non-variant or struct in variant_opt()"); + ccx.sess.bug(~"non-variant or struct in variant_opt()"); } } } @@ -505,7 +509,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, do enter_match(bcx, tcx.def_map, m, col, val) |p| { match /*bad*/copy p.node { ast::pat_enum(_, subpats) => { - if opt_eq(tcx, &variant_opt(tcx, p.id), opt) { + if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { Some(option::get_or_default(subpats, vec::from_elem(variant_size, dummy))) @@ -515,7 +519,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, } ast::pat_ident(_, _, None) if pat_is_variant_or_struct(tcx.def_map, p) => { - if opt_eq(tcx, &variant_opt(tcx, p.id), opt) { + if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { Some(~[]) } else { None @@ -537,7 +541,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, if opt_eq(tcx, &range(l1, l2), opt) {Some(~[])} else {None} } ast::pat_struct(_, field_pats, _) => { - if opt_eq(tcx, &variant_opt(tcx, p.id), opt) { + if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { // Look up the struct variant ID. let struct_id; match tcx.def_map.get(&p.id) { @@ -762,8 +766,9 @@ pub fn enter_region(bcx: block, // Returns the options in one column of matches. An option is something that // needs to be conditionally matched at runtime; for example, the discriminant // on a set of enum variants or a literal. -pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] { - fn add_to_set(tcx: ty::ctxt, set: &DVec, val: Opt) { +pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] { + let ccx = bcx.ccx(); + fn add_to_set(tcx: ty::ctxt, set: &DVec, +val: Opt) { if set.any(|l| opt_eq(tcx, l, &val)) {return;} set.push(val); } @@ -781,7 +786,7 @@ pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] { match ccx.tcx.def_map.find(&cur.id) { Some(ast::def_variant(*)) => { add_to_set(ccx.tcx, &found, - variant_opt(ccx.tcx, cur.id)); + variant_opt(bcx, cur.id)); } Some(ast::def_struct(*)) => { add_to_set(ccx.tcx, &found, @@ -800,7 +805,7 @@ pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] { match ccx.tcx.def_map.find(&cur.id) { Some(ast::def_variant(*)) => { add_to_set(ccx.tcx, &found, - variant_opt(ccx.tcx, cur.id)); + variant_opt(bcx, cur.id)); } _ => {} } @@ -827,34 +832,13 @@ pub struct ExtractedBlock { } pub fn extract_variant_args(bcx: block, - pat_id: ast::node_id, - vdefs: (def_id, def_id), + repr: &adt::Repr, + disr_val: int, val: ValueRef) - -> ExtractedBlock { - let (enm, evar) = vdefs; + -> ExtractedBlock { let _icx = bcx.insn_ctxt("match::extract_variant_args"); - let ccx = *bcx.fcx.ccx; - let enum_ty_substs = match ty::get(node_id_type(bcx, pat_id)).sty { - ty::ty_enum(id, ref substs) => { - assert id == enm; - /*bad*/copy (*substs).tps - } - _ => bcx.sess().bug(~"extract_variant_args: pattern has non-enum type") - }; - let mut blobptr = val; - let variants = ty::enum_variants(ccx.tcx, enm); - let size = ty::enum_variant_with_id(ccx.tcx, enm, - evar).args.len(); - if size > 0u && (*variants).len() != 1u { - let enumptr = - PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); - blobptr = GEPi(bcx, enumptr, [0u, 1u]); - } - let vdefs_tg = enm; - let vdefs_var = evar; - let args = do vec::from_fn(size) |i| { - GEP_enum(bcx, blobptr, vdefs_tg, vdefs_var, - /*bad*/copy enum_ty_substs, i) + let args = do vec::from_fn(adt::num_args(repr, disr_val)) |i| { + adt::trans_GEP(bcx, repr, val, disr_val, i) }; ExtractedBlock { vals: args, bcx: bcx } @@ -1365,37 +1349,15 @@ pub fn compile_submatch(bcx: block, } // Decide what kind of branch we need - let opts = get_options(ccx, m, col); + let opts = get_options(bcx, m, col); let mut kind = no_branch; let mut test_val = val; if opts.len() > 0u { match opts[0] { - var(_, (enm, _)) => { - let variants = ty::enum_variants(tcx, enm); - if variants.len() == 1 { - kind = single; - } else { - let enumptr = - PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); - let discrimptr = GEPi(bcx, enumptr, [0u, 0u]); - - - assert variants.len() > 1; - let min_discrim = do variants.foldr(0) |&x, y| { - int::min(x.disr_val, y) - }; - let max_discrim = do variants.foldr(0) |&x, y| { - int::max(x.disr_val, y) - }; - - test_val = LoadRangeAssert(bcx, discrimptr, - min_discrim as c_ulonglong, - (max_discrim + 1) - as c_ulonglong, - lib::llvm::True); - - kind = switch; - } + var(_, ref repr) => { + let (the_kind, val_opt) = adt::trans_switch(bcx, repr, val); + kind = the_kind; + for val_opt.each |&tval| { test_val = tval; } } lit(_) => { let pty = node_id_type(bcx, pat_id); @@ -1544,11 +1506,12 @@ pub fn compile_submatch(bcx: block, let mut size = 0u; let mut unpacked = ~[]; match *opt { - var(_, vdef) => { - let args = extract_variant_args(opt_cx, pat_id, vdef, val); - size = args.vals.len(); - unpacked = /*bad*/copy args.vals; - opt_cx = args.bcx; + var(disr_val, ref repr) => { + let ExtractedBlock {vals: argvals, bcx: new_bcx} = + extract_variant_args(opt_cx, repr, disr_val, val); + size = argvals.len(); + unpacked = argvals; + opt_cx = new_bcx; } vec_len_eq(n) | vec_len_ge(n) => { let tail = match *opt { @@ -1757,10 +1720,15 @@ pub fn bind_irrefutable_pat(bcx: block, } ast::pat_enum(_, sub_pats) => { match bcx.tcx().def_map.find(&pat.id) { - Some(ast::def_variant(*)) => { - let pat_def = ccx.tcx.def_map.get(&pat.id); - let vdefs = ast_util::variant_def_ids(pat_def); - let args = extract_variant_args(bcx, pat.id, vdefs, val); + Some(ast::def_variant(enum_id, var_id)) => { + let repr = adt::represent_node(bcx, pat.id); + let vinfo = ty::enum_variant_with_id(ccx.tcx, + enum_id, + var_id); + let args = extract_variant_args(bcx, + &repr, + vinfo.disr_val, + val); for sub_pats.each |sub_pat| { for vec::eachi(args.vals) |i, argval| { bcx = bind_irrefutable_pat(bcx, From 5e2302a56f7615b73e42daaa242da4bd64b25d93 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Fri, 22 Feb 2013 21:45:49 -0800 Subject: [PATCH 03/37] Convert type_of to use trans::adt. --- src/librustc/middle/trans/type_of.rs | 99 ++++------------------------ 1 file changed, 11 insertions(+), 88 deletions(-) diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 26cf91b03e145..1f14a24b0ae3a 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -11,6 +11,7 @@ use lib::llvm::llvm; use lib::llvm::{TypeRef}; +use middle::trans::adt; use middle::trans::base; use middle::trans::common::*; use middle::trans::common; @@ -143,32 +144,12 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_unboxed_vec(mt) => T_vec(cx, sizing_type_of(cx, mt.ty)), - ty::ty_tup(ref elems) => { - T_struct(elems.map(|&t| sizing_type_of(cx, t))) + ty::ty_tup(*) | ty::ty_rec(*) | ty::ty_struct(*) + | ty::ty_enum(*) => { + let repr = adt::represent_type(cx, t); + T_struct(adt::sizing_fields_of(cx, &repr)) } - ty::ty_rec(ref fields) => { - T_struct(fields.map(|f| sizing_type_of(cx, f.mt.ty))) - } - - ty::ty_struct(def_id, ref substs) => { - let fields = ty::lookup_struct_fields(cx.tcx, def_id); - let lltype = T_struct(fields.map(|field| { - let field_type = ty::lookup_field_type(cx.tcx, - def_id, - field.id, - substs); - sizing_type_of(cx, field_type) - })); - if ty::ty_dtor(cx.tcx, def_id).is_present() { - T_struct(~[lltype, T_i8()]) - } else { - lltype - } - } - - ty::ty_enum(def_id, _) => T_struct(enum_body_types(cx, def_id, t)), - ty::ty_self | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { cx.tcx.sess.bug( fmt!("fictitious type %? in sizing_type_of()", @@ -257,28 +238,13 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { T_array(type_of(cx, mt.ty), n) } - ty::ty_rec(fields) => { - let mut tys: ~[TypeRef] = ~[]; - for vec::each(fields) |f| { - let mt_ty = f.mt.ty; - tys.push(type_of(cx, mt_ty)); - } - - // n.b.: introduce an extra layer of indirection to match - // structs - T_struct(~[T_struct(tys)]) - } - ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)), ty::ty_closure(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)), ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore), ty::ty_type => T_ptr(cx.tydesc_type), - ty::ty_tup(elts) => { - let mut tys = ~[]; - for vec::each(elts) |elt| { - tys.push(type_of(cx, *elt)); - } - T_struct(tys) + ty::ty_tup(*) | ty::ty_rec(*) => { + let repr = adt::represent_type(cx, t); + T_struct(adt::fields_of(cx, &repr)) } ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx), ty::ty_struct(did, ref substs) => { @@ -301,24 +267,9 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { // If this was an enum or struct, fill in the type now. match ty::get(t).sty { - ty::ty_enum(did, _) => { - fill_type_of_enum(cx, did, t, llty); - } - ty::ty_struct(did, ref substs) => { - // Only instance vars are record fields at runtime. - let fields = ty::lookup_struct_fields(cx.tcx, did); - let mut tys = do vec::map(fields) |f| { - let t = ty::lookup_field_type(cx.tcx, did, f.id, substs); - type_of(cx, t) - }; - - // include a byte flag if there is a dtor so that we know when we've - // been dropped - if ty::ty_dtor(cx.tcx, did).is_present() { - common::set_struct_body(llty, ~[T_struct(tys), T_i8()]); - } else { - common::set_struct_body(llty, ~[T_struct(tys)]); - } + ty::ty_enum(*) | ty::ty_struct(*) => { + let repr = adt::represent_type(cx, t); + common::set_struct_body(llty, adt::fields_of(cx, &repr)); } _ => () } @@ -326,34 +277,6 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { return llty; } -pub fn enum_body_types(cx: @CrateContext, did: ast::def_id, t: ty::t) - -> ~[TypeRef] { - let univar = ty::enum_is_univariant(cx.tcx, did); - if !univar { - let size = machine::static_size_of_enum(cx, t); - ~[T_enum_discrim(cx), T_array(T_i8(), size)] - } - else { - // Use the actual fields, so we get the alignment right. - match ty::get(t).sty { - ty::ty_enum(_, ref substs) => { - do ty::enum_variants(cx.tcx, did)[0].args.map |&field_ty| { - sizing_type_of(cx, ty::subst(cx.tcx, substs, field_ty)) - } - } - _ => cx.sess.bug(~"enum is not an enum") - } - } -} - -pub fn fill_type_of_enum(cx: @CrateContext, - did: ast::def_id, - t: ty::t, - llty: TypeRef) { - debug!("type_of_enum %?: %?", t, ty::get(t)); - common::set_struct_body(llty, enum_body_types(cx, did, t)); -} - // Want refinements! (Or case classes, I guess pub enum named_ty { a_struct, an_enum } From 8a1706610b2cf458fe6e5ed12e227e3ca9dcaa6d Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Fri, 22 Feb 2013 22:03:59 -0800 Subject: [PATCH 04/37] Avoid unnecessary casts in struct_GEP --- src/librustc/middle/trans/adt.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 21f113a08aa77..37129dce90c7d 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -205,24 +205,28 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) NoDtor => val, DtorPresent | DtorAbsent => GEPi(bcx, val, [0, 0]) }; - struct_GEP(bcx, st, val, ix) + struct_GEP(bcx, st, val, ix, false) } General(ref cases) => { struct_GEP(bcx, &cases[discr as uint], - GEPi(bcx, val, [0, 1]), ix) + GEPi(bcx, val, [0, 1]), ix, true) } } } -fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint) - -> ValueRef { +fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, + needs_cast: bool) -> ValueRef { let ccx = bcx.ccx(); - let real_llty = T_struct(st.fields.map( - |&ty| type_of::type_of(ccx, ty))); - let cast_val = PointerCast(bcx, val, T_ptr(real_llty)); + let val = if needs_cast { + let real_llty = T_struct(st.fields.map( + |&ty| type_of::type_of(ccx, ty))); + PointerCast(bcx, val, T_ptr(real_llty)) + } else { + val + }; - GEPi(bcx, cast_val, [0, ix]) + GEPi(bcx, val, [0, ix]) } pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, From 04ecab909a38a8c19405ea577e826facfe4d7da8 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 23 Feb 2013 00:59:24 -0800 Subject: [PATCH 05/37] Re-add discriminant range annotations --- src/librustc/middle/trans/adt.rs | 57 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 37129dce90c7d..b4d2be8382751 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::libc::c_ulonglong; use core::option::{Option, Some, None}; use core::vec; -use lib::llvm::{ValueRef, TypeRef}; +use lib::llvm::{ValueRef, TypeRef, True, False}; use middle::trans::_match; use middle::trans::build::*; use middle::trans::common::*; @@ -23,7 +24,7 @@ use util::ppaux::ty_to_str; // XXX: should this be done with boxed traits instead of ML-style? pub enum Repr { - CEnum, + CEnum(int, int), /* discriminant range */ Univariant(Struct, Destructor), General(~[Struct]) } @@ -65,13 +66,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { })), if dt { DtorPresent } else { DtorAbsent }) } ty::ty_enum(def_id, ref substs) => { - struct Case { discr: i64, tys: ~[ty::t] }; + struct Case { discr: int, tys: ~[ty::t] }; let cases = do ty::enum_variants(cx.tcx, def_id).map |vi| { let arg_tys = do vi.args.map |&raw_ty| { ty::subst(cx.tcx, substs, raw_ty) }; - Case { discr: vi.disr_val /*bad*/as i64, tys: arg_tys } + Case { discr: vi.disr_val, tys: arg_tys } }; if cases.len() == 0 { // Uninhabitable; represent as unit @@ -80,9 +81,10 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { // struct, tuple, newtype, etc. Univariant(mk_struct(cx, cases[0].tys), NoDtor) } else if cases.all(|c| c.tys.len() == 0) { - CEnum + let discrs = cases.map(|c| c.discr); + CEnum(discrs.min(), discrs.max()) } else { - if !cases.alli(|i,c| c.discr == (i as i64)) { + if !cases.alli(|i,c| c.discr == (i as int)) { cx.sess.bug(fmt!("non-C-like enum %s with specified \ discriminants", ty::item_path_str(cx.tcx, def_id))) @@ -114,7 +116,7 @@ pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) -> ~[TypeRef] { match *r { - CEnum => ~[T_enum_discrim(cx)], + CEnum(*) => ~[T_enum_discrim(cx)], Univariant(ref st, dt) => { let f = if sizing { st.fields.map(|&ty| type_of::sizing_type_of(cx, ty)) @@ -134,25 +136,44 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) } } +fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) + -> ValueRef { + let ptr = GEPi(bcx, scrutinee, [0, 0]); + // XXX: write tests for the edge cases here + if max + 1 == min { + // i.e., if the range is everything. The lo==hi case would be + // rejected by the LLVM verifier (it would mean either an + // empty set, which is impossible, or the entire range of the + // type, which is pointless). + Load(bcx, ptr) + } else { + // llvm::ConstantRange can deal with ranges that wrap around, + // so an overflow on (max + 1) is fine. + LoadRangeAssert(bcx, ptr, min as c_ulonglong, + (max + 1) as c_ulonglong, + /* signed: */ True) + } +} + pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> (_match::branch_kind, Option) { - // XXX: LoadRangeAssert match *r { - CEnum => { - (_match::switch, Some(Load(bcx, GEPi(bcx, scrutinee, [0, 0])))) + CEnum(min, max) => { + (_match::switch, Some(load_discr(bcx, scrutinee, min, max))) } Univariant(*) => { (_match::single, None) } - General(*) => { - (_match::switch, Some(Load(bcx, GEPi(bcx, scrutinee, [0, 0])))) + General(ref cases) => { + (_match::switch, Some(load_discr(bcx, scrutinee, 0, + (cases.len() - 1) as int))) } } } pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { match *r { - CEnum => { + CEnum(*) => { _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) } Univariant(*) => { @@ -166,7 +187,8 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { match *r { - CEnum => { + CEnum(min, max) => { + assert min <= discr && discr <= max; Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) } Univariant(_, DtorPresent) => { @@ -184,7 +206,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { pub fn num_args(r: &Repr, discr: int) -> uint { match *r { - CEnum => 0, + CEnum(*) => 0, Univariant(ref st, _dt) => { assert discr == 0; st.fields.len() } General(ref cases) => cases[discr as uint].fields.len() } @@ -196,7 +218,7 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) // decide to do some kind of cdr-coding-like non-unique repr // someday), it'll need to return a possibly-new bcx as well. match *r { - CEnum => { + CEnum(*) => { bcx.ccx().sess.bug(~"element access in C-like enum") } Univariant(ref st, dt) => { @@ -232,8 +254,9 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, vals: &[ValueRef]) -> ValueRef { match *r { - CEnum => { + CEnum(min, max) => { assert vals.len() == 0; + assert min <= discr && discr <= max; C_int(ccx, discr) } Univariant(ref st, _dt) => { From 7b2b4faba84c1d43af35397d0103747fe085ee45 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 23 Feb 2013 12:15:30 -0800 Subject: [PATCH 06/37] Add a test for enum discriminant range overflow. It causes an LLVM assertion for every host/target word-size combination on incoming at the time of this writing. --- src/librustc/middle/trans/adt.rs | 1 - .../run-pass/enum-discrim-range-overflow.rs | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/enum-discrim-range-overflow.rs diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index b4d2be8382751..858479eaa64b4 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -139,7 +139,6 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) -> ValueRef { let ptr = GEPi(bcx, scrutinee, [0, 0]); - // XXX: write tests for the edge cases here if max + 1 == min { // i.e., if the range is everything. The lo==hi case would be // rejected by the LLVM verifier (it would mean either an diff --git a/src/test/run-pass/enum-discrim-range-overflow.rs b/src/test/run-pass/enum-discrim-range-overflow.rs new file mode 100644 index 0000000000000..a6806fba14269 --- /dev/null +++ b/src/test/run-pass/enum-discrim-range-overflow.rs @@ -0,0 +1,31 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub enum E64 { + H64 = 0x7FFF_FFFF_FFFF_FFFF, + L64 = 0x8000_0000_0000_0000 +} +pub enum E32 { + H32 = 0x7FFF_FFFF, + L32 = 0x8000_0000 +} + +pub fn f(e64: E64, e32: E32) -> (bool,bool) { + (match e64 { + H64 => true, + L64 => false + }, + match e32 { + H32 => true, + L32 => false + }) +} + +pub fn main() { } From e09a843973f8dfc5766c0d36bb68ee1136cbf54c Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 16:24:07 -0800 Subject: [PATCH 07/37] Handle unit-like types specially. This change remains separate from the addition of adt.rs, even though it's necessary for compatibility with pre-trans::adt representation, to serve as an example of a change to the representation logic. --- src/librustc/middle/trans/adt.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 858479eaa64b4..b32111f6bf475 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -24,6 +24,7 @@ use util::ppaux::ty_to_str; // XXX: should this be done with boxed traits instead of ML-style? pub enum Repr { + Unit(int), CEnum(int, int), /* discriminant range */ Univariant(Struct, Destructor), General(~[Struct]) @@ -77,8 +78,11 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { if cases.len() == 0 { // Uninhabitable; represent as unit Univariant(mk_struct(cx, ~[]), NoDtor) - } else if cases.len() == 1 && cases[0].discr == 0 { + } else if cases.len() == 1 && cases[0].tys.len() == 0 { + Unit(cases[0].discr) + } else if cases.len() == 1 { // struct, tuple, newtype, etc. + assert cases[0].discr == 0; Univariant(mk_struct(cx, cases[0].tys), NoDtor) } else if cases.all(|c| c.tys.len() == 0) { let discrs = cases.map(|c| c.discr); @@ -116,6 +120,7 @@ pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) -> ~[TypeRef] { match *r { + Unit(*) => ~[], CEnum(*) => ~[T_enum_discrim(cx)], Univariant(ref st, dt) => { let f = if sizing { @@ -160,7 +165,7 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> CEnum(min, max) => { (_match::switch, Some(load_discr(bcx, scrutinee, min, max))) } - Univariant(*) => { + Unit(*) | Univariant(*) => { (_match::single, None) } General(ref cases) => { @@ -175,7 +180,7 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { CEnum(*) => { _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) } - Univariant(*) => { + Unit(*) | Univariant(*)=> { bcx.ccx().sess.bug(~"no cases for univariants or structs") } General(*) => { @@ -186,6 +191,9 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { match *r { + Unit(the_discr) => { + assert discr == the_discr; + } CEnum(min, max) => { assert min <= discr && discr <= max; Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) @@ -205,7 +213,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { pub fn num_args(r: &Repr, discr: int) -> uint { match *r { - CEnum(*) => 0, + Unit(*) | CEnum(*) => 0, Univariant(ref st, _dt) => { assert discr == 0; st.fields.len() } General(ref cases) => cases[discr as uint].fields.len() } @@ -217,7 +225,7 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) // decide to do some kind of cdr-coding-like non-unique repr // someday), it'll need to return a possibly-new bcx as well. match *r { - CEnum(*) => { + Unit(*) | CEnum(*) => { bcx.ccx().sess.bug(~"element access in C-like enum") } Univariant(ref st, dt) => { @@ -253,6 +261,9 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, vals: &[ValueRef]) -> ValueRef { match *r { + Unit(*) => { + C_struct(~[]) + } CEnum(min, max) => { assert vals.len() == 0; assert min <= discr && discr <= max; @@ -312,6 +323,7 @@ fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef) -> int { match *r { + Unit(discr) => discr, CEnum(*) => const_to_int(val) as int, Univariant(*) => 0, General(*) => const_to_int(const_get_elt(ccx, val, [0])) as int, @@ -322,7 +334,8 @@ pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, _discr: int, ix: uint) -> ValueRef { // Not to be confused with common::const_get_elt. match *r { - CEnum(*) => ccx.sess.bug(~"element access in C-like enum const"), + Unit(*) | CEnum(*) => ccx.sess.bug(~"element access in C-like enum \ + const"), Univariant(*) => const_struct_field(ccx, val, ix), General(*) => const_struct_field(ccx, const_get_elt(ccx, val, [1, 0]), ix) From a5030e7615f7d37acaee69b13f97b9ffa23159a5 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 6 Mar 2013 20:17:22 -0800 Subject: [PATCH 08/37] Wrap const structs in as many LLVM structs as the non-const case. This, like the previous change for unit-like enums, is only necessary until everything is fully converted to use trans::adt. --- src/librustc/middle/trans/adt.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index b32111f6bf475..c6ba0a7d81f7a 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -269,10 +269,15 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, assert min <= discr && discr <= max; C_int(ccx, discr) } - Univariant(ref st, _dt) => { + Univariant(ref st, dt) => { assert discr == 0; - // consts are never destroyed, so the dtor flag is not needed - C_struct(build_const_struct(ccx, st, vals)) + let s = C_struct(build_const_struct(ccx, st, vals)); + match dt { + NoDtor => s, + // The actual destructor flag doesn't need to be present. + // But add an extra struct layer for compatibility. + DtorPresent | DtorAbsent => C_struct(~[s]) + } } General(ref cases) => { let case = &cases[discr as uint]; @@ -336,7 +341,9 @@ pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, match *r { Unit(*) | CEnum(*) => ccx.sess.bug(~"element access in C-like enum \ const"), - Univariant(*) => const_struct_field(ccx, val, ix), + Univariant(_, NoDtor) => const_struct_field(ccx, val, ix), + Univariant(*) => const_struct_field(ccx, const_get_elt(ccx, val, + [0]), ix), General(*) => const_struct_field(ccx, const_get_elt(ccx, val, [1, 0]), ix) } From b673b26f03043f974682efceffbf40df9cf4bc84 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Thu, 28 Feb 2013 11:43:20 -0800 Subject: [PATCH 09/37] Factor out discriminant loading more, for use in casts. --- src/librustc/middle/trans/adt.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index c6ba0a7d81f7a..6aab2af567fb9 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -159,19 +159,27 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) } } -pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> - (_match::branch_kind, Option) { +pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) + -> (_match::branch_kind, Option) { match *r { - CEnum(min, max) => { - (_match::switch, Some(load_discr(bcx, scrutinee, min, max))) + CEnum(*) | General(*) => { + (_match::switch, Some(trans_cast_to_int(bcx, r, scrutinee))) } Unit(*) | Univariant(*) => { (_match::single, None) } - General(ref cases) => { - (_match::switch, Some(load_discr(bcx, scrutinee, 0, - (cases.len() - 1) as int))) - } + } +} + +pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef) + -> ValueRef { + match *r { + Unit(the_disc) => C_int(bcx.ccx(), the_disc), + CEnum(min, max) => load_discr(bcx, scrutinee, min, max), + Univariant(*) => bcx.ccx().sess.bug(~"type has no explicit \ + discriminant"), + General(ref cases) => load_discr(bcx, scrutinee, 0, + (cases.len() - 1) as int) } } From 5cbc2571c1a4df75750fcb726120db06eb61c1f9 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 23 Feb 2013 13:36:01 -0800 Subject: [PATCH 10/37] Renovate expr_tup translation --- src/librustc/middle/trans/expr.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index d41bf3571938e..9685bb49f1b6a 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -126,6 +126,7 @@ use lib; use lib::llvm::{ValueRef, TypeRef, llvm, True}; use middle::borrowck::root_map_key; use middle::trans::_match; +use middle::trans::adt; use middle::trans::base; use middle::trans::base::*; use middle::trans::build::*; @@ -602,7 +603,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, return trans_rec_or_struct(bcx, (*fields), base, expr.id, dest); } ast::expr_tup(ref args) => { - return trans_tup(bcx, *args, dest); + let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr)); + return trans_adt(bcx, &repr, 0, *args, dest); } ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => { return tvec::trans_lit_str(bcx, expr, s, dest); @@ -1249,7 +1251,8 @@ fn trans_rec_or_struct(bcx: block, } } -fn trans_tup(bcx: block, elts: &[@ast::expr], dest: Dest) -> block { +fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, elts: &[@ast::expr], + dest: Dest) -> block { let _icx = bcx.insn_ctxt("trans_tup"); let mut bcx = bcx; let addr = match dest { @@ -1262,8 +1265,9 @@ fn trans_tup(bcx: block, elts: &[@ast::expr], dest: Dest) -> block { SaveIn(pos) => pos, }; let mut temp_cleanups = ~[]; + adt::trans_set_discr(bcx, repr, addr, discr); for vec::eachi(elts) |i, e| { - let dest = GEPi(bcx, addr, [0u, i]); + let dest = adt::trans_GEP(bcx, repr, addr, discr, i); let e_ty = expr_ty(bcx, *e); bcx = trans_into(bcx, *e, SaveIn(dest)); add_clean_temp_mem(bcx, dest, e_ty); From fdd28451f68a14916c57c50baa045132316cedc6 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 23 Feb 2013 22:53:40 -0800 Subject: [PATCH 11/37] Convert expr_struct to use adt, and try to share code with tuples. --- src/librustc/middle/trans/expr.rs | 179 ++++++++++++------------------ 1 file changed, 73 insertions(+), 106 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 9685bb49f1b6a..978ee641a7151 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -604,7 +604,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_tup(ref args) => { let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr)); - return trans_adt(bcx, &repr, 0, *args, dest); + return trans_adt(bcx, &repr, 0, args.mapi(|i, arg| (i, *arg)), + None, dest); } ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => { return tvec::trans_lit_str(bcx, expr, s, dest); @@ -885,7 +886,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let _icx = bcx.insn_ctxt("trans_rec_field"); let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base)); - do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| { + do with_field_tys(bcx.tcx(), base_datum.ty, None) |_disr, field_tys| { let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys); DatumBlock { datum: base_datum.GEPi(bcx, @@ -1098,15 +1099,14 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { pub fn with_field_tys(tcx: ty::ctxt, ty: ty::t, node_id_opt: Option, - op: fn(bool, (&[ty::field])) -> R) -> R { + op: fn(int, (&[ty::field])) -> R) -> R { match ty::get(ty).sty { ty::ty_rec(ref fields) => { - op(false, *fields) + op(0, *fields) } ty::ty_struct(did, ref substs) => { - let has_dtor = ty::ty_dtor(tcx, did).is_present(); - op(has_dtor, struct_mutable_fields(tcx, did, substs)) + op(0, struct_mutable_fields(tcx, did, substs)) } ty::ty_enum(_, ref substs) => { @@ -1120,8 +1120,10 @@ pub fn with_field_tys(tcx: ty::ctxt, } Some(node_id) => { match tcx.def_map.get(&node_id) { - ast::def_variant(_, variant_id) => { - op(false, struct_mutable_fields( + ast::def_variant(enum_id, variant_id) => { + let variant_info = ty::enum_variant_with_id( + tcx, enum_id, variant_id); + op(variant_info.disr_val, struct_mutable_fields( tcx, variant_id, substs)) } _ => { @@ -1150,135 +1152,100 @@ fn trans_rec_or_struct(bcx: block, let _icx = bcx.insn_ctxt("trans_rec"); let mut bcx = bcx; - // Handle the case where the result is ignored. - let addr; - match dest { - SaveIn(p) => { - addr = p; - } - Ignore => { - // just evaluate the values for each field and drop them - // on the floor - for vec::each(fields) |fld| { - bcx = trans_into(bcx, fld.node.expr, Ignore); - } - return bcx; - } - } - - // If this is a struct-like variant, write in the discriminant if - // necessary, position the address at the right location, and cast the - // address. let ty = node_id_type(bcx, id); let tcx = bcx.tcx(); - let addr = match ty::get(ty).sty { - ty::ty_enum(_, ref substs) => { - match tcx.def_map.get(&id) { - ast::def_variant(enum_id, variant_id) => { - let variant_info = ty::enum_variant_with_id( - tcx, enum_id, variant_id); - let addr = if ty::enum_is_univariant(tcx, enum_id) { - addr - } else { - Store(bcx, - C_int(bcx.ccx(), variant_info.disr_val), - GEPi(bcx, addr, [0, 0])); - GEPi(bcx, addr, [0, 1]) - }; - let fields = ty::struct_mutable_fields( - tcx, variant_id, substs); - let field_lltys = do fields.map |field| { - type_of::type_of(bcx.ccx(), - ty::subst_tps( - tcx, substs.tps, None, field.mt.ty)) - }; - PointerCast(bcx, addr, - T_ptr(T_struct(~[T_struct(field_lltys)]))) + do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| { + let mut need_base = vec::from_elem(field_tys.len(), true); + + let numbered_fields = do fields.map |field| { + match do vec::position(field_tys) |field_ty| { + field_ty.ident == field.node.ident + } { + Some(i) => { + need_base[i] = false; + (i, field.node.expr) } - _ => { - tcx.sess.bug(~"resolve didn't write the right def in for \ - this struct-like variant") + None => { + tcx.sess.span_bug(field.span, + ~"Couldn't find field in struct type") } } - } - _ => addr - }; - - do with_field_tys(tcx, ty, Some(id)) |has_dtor, field_tys| { - // evaluate each of the fields and store them into their - // correct locations - let mut temp_cleanups = ~[]; - for fields.each |field| { - let ix = ty::field_idx_strict(tcx, field.node.ident, field_tys); - let dest = GEPi(bcx, addr, struct_field(ix)); - bcx = trans_into(bcx, field.node.expr, SaveIn(dest)); - add_clean_temp_mem(bcx, dest, field_tys[ix].mt.ty); - temp_cleanups.push(dest); - } - - // copy over any remaining fields from the base (for - // functional record update) - for base.each |base_expr| { - let base_datum = unpack_datum!( - bcx, trans_to_datum(bcx, *base_expr)); - - // Copy/move over inherited fields - for field_tys.eachi |i, field_ty| { - if !fields.any(|f| f.node.ident == field_ty.ident) { - let dest = GEPi(bcx, addr, struct_field(i)); - let base_field = - base_datum.GEPi(bcx, - struct_field(i), - field_ty.mt.ty, - ZeroMem); - bcx = base_field.store_to(bcx, base_expr.id, INIT, dest); + }; + let optbase = match base { + Some(base_expr) => { + let mut leftovers = ~[]; + for need_base.eachi |i, b| { + if *b { + leftovers.push((i, field_tys[i].mt.ty)) + } } + Some(StructBaseInfo {expr: base_expr, + fields: leftovers }) } - } - - // Add the drop flag if necessary. - if has_dtor { - let dest = GEPi(bcx, addr, struct_dtor()); - Store(bcx, C_u8(1), dest); - } + None => { + if need_base.any(|b| *b) { + // XXX should be span bug + tcx.sess.bug(~"missing fields and no base expr") + } + None + } + }; - // Now revoke the cleanups as we pass responsibility for the data - // structure on to the caller - for temp_cleanups.each |cleanup| { - revoke_clean(bcx, *cleanup); - } - bcx + let repr = adt::represent_type(bcx.ccx(), ty); + trans_adt(bcx, &repr, discr, numbered_fields, optbase, dest) } } -fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, elts: &[@ast::expr], +struct StructBaseInfo { + expr: @ast::expr, + fields: ~[(uint, ty::t)] +} + +fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, + fields: &[(uint, @ast::expr)], + optbase: Option, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("trans_tup"); + let _icx = bcx.insn_ctxt("trans_adt"); let mut bcx = bcx; let addr = match dest { Ignore => { - for vec::each(elts) |ex| { - bcx = trans_into(bcx, *ex, Ignore); + for fields.each |&(_i, e)| { + bcx = trans_into(bcx, e, Ignore); + } + for optbase.each |sbi| { + bcx = trans_into(bcx, sbi.expr, Ignore); } return bcx; } - SaveIn(pos) => pos, + SaveIn(pos) => pos }; let mut temp_cleanups = ~[]; adt::trans_set_discr(bcx, repr, addr, discr); - for vec::eachi(elts) |i, e| { + for fields.each |&(i, e)| { let dest = adt::trans_GEP(bcx, repr, addr, discr, i); - let e_ty = expr_ty(bcx, *e); - bcx = trans_into(bcx, *e, SaveIn(dest)); + let e_ty = expr_ty(bcx, e); + bcx = trans_into(bcx, e, SaveIn(dest)); add_clean_temp_mem(bcx, dest, e_ty); temp_cleanups.push(dest); } + for optbase.each |base| { + let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr)); + for base.fields.each |&(i, t)| { + let datum = + // XXX convert this to adt + base_datum.GEPi(bcx, struct_field(i), t, ZeroMem); + let dest = adt::trans_GEP(bcx, repr, addr, discr, i); + bcx = datum.store_to(bcx, base.expr.id, INIT, dest); + } + } + for vec::each(temp_cleanups) |cleanup| { revoke_clean(bcx, *cleanup); } return bcx; } + fn trans_immediate_lit(bcx: block, expr: @ast::expr, lit: ast::lit) -> DatumBlock { // must not be a string constant, that is a RvalueDpsExpr From 40313fb6b0104f703c06b2dd46198ad1f15d267b Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 11:08:30 -0800 Subject: [PATCH 12/37] Renovate nullary variant construction --- src/librustc/middle/trans/expr.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 978ee641a7151..9a69acd4987e8 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -722,14 +722,12 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id); Store(bcx, fn_data.llfn, lldest); return bcx; - } else if !ty::enum_is_univariant(ccx.tcx, tid) { - // Nullary variant. - let lldiscrimptr = GEPi(bcx, lldest, [0u, 0u]); - let lldiscrim = C_int(bcx.ccx(), variant_info.disr_val); - Store(bcx, lldiscrim, lldiscrimptr); - return bcx; } else { - // Nullary univariant. + // Nullary variant. + let ty = expr_ty(bcx, ref_expr); + let repr = adt::represent_type(ccx, ty); + adt::trans_set_discr(bcx, &repr, lldest, + variant_info.disr_val); return bcx; } } From 3a4714d92e49564c1cfc86fae5573510de7c2e31 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 12:42:39 -0800 Subject: [PATCH 13/37] Renovate field projection expressions --- src/librustc/middle/trans/datum.rs | 11 +++++------ src/librustc/middle/trans/expr.rs | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index ce472fd9f1fdb..6f27a190b170e 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -511,14 +511,13 @@ pub impl Datum { } } - fn GEPi(&self, bcx: block, - ixs: &[uint], - ty: ty::t, - source: DatumCleanup) - -> Datum { + fn get_element(&self, bcx: block, + ty: ty::t, + source: DatumCleanup, + gep: fn(ValueRef) -> ValueRef) -> Datum { let base_val = self.to_ref_llval(bcx); Datum { - val: GEPi(bcx, base_val, ixs), + val: gep(base_val), mode: ByRef, ty: ty, source: source diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 9a69acd4987e8..cd6d1e42b8c54 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -884,13 +884,15 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let _icx = bcx.insn_ctxt("trans_rec_field"); let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base)); - do with_field_tys(bcx.tcx(), base_datum.ty, None) |_disr, field_tys| { + let repr = adt::represent_type(bcx.ccx(), base_datum.ty); + do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| { let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys); DatumBlock { - datum: base_datum.GEPi(bcx, - [0u, 0u, ix], - field_tys[ix].mt.ty, - ZeroMem), + datum: do base_datum.get_element(bcx, + field_tys[ix].mt.ty, + ZeroMem) |srcval| { + adt::trans_GEP(bcx, &repr, srcval, discr, ix) + }, bcx: bcx } } @@ -1227,11 +1229,13 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, temp_cleanups.push(dest); } for optbase.each |base| { + // XXX is it sound to use the destination's repr on the base? + // XXX would it ever be reasonable to be here with discr != 0? let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr)); for base.fields.each |&(i, t)| { - let datum = - // XXX convert this to adt - base_datum.GEPi(bcx, struct_field(i), t, ZeroMem); + let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| { + adt::trans_GEP(bcx, repr, srcval, discr, i) + }; let dest = adt::trans_GEP(bcx, repr, addr, discr, i); bcx = datum.store_to(bcx, base.expr.id, INIT, dest); } From c7325c417257646afdd93fd3cc10ef891d167643 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 13:14:12 -0800 Subject: [PATCH 14/37] Convert the rest of the adt GEPi's in _match --- src/librustc/middle/trans/_match.rs | 32 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index e3f719229aff2..5a9d6c3b6c662 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1267,14 +1267,14 @@ pub fn compile_submatch(bcx: block, } bcx = root_pats_as_necessary(bcx, m, col, val); - let rec_fields = collect_record_or_struct_fields(bcx, m, col); if rec_fields.len() > 0 { let pat_ty = node_id_type(bcx, pat_id); - do expr::with_field_tys(tcx, pat_ty, None) |_has_dtor, field_tys| { + let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); + do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { let rec_vals = rec_fields.map(|field_name| { let ix = ty::field_idx_strict(tcx, *field_name, field_tys); - GEPi(bcx, val, struct_field(ix)) + adt::trans_GEP(bcx, &pat_repr, val, discr, ix) }); compile_submatch( bcx, @@ -1287,11 +1287,14 @@ pub fn compile_submatch(bcx: block, if any_tup_pat(m, col) { let tup_ty = node_id_type(bcx, pat_id); + let tup_repr = adt::represent_type(bcx.ccx(), tup_ty); let n_tup_elts = match /*bad*/copy ty::get(tup_ty).sty { ty::ty_tup(elts) => elts.len(), _ => ccx.sess.bug(~"non-tuple type in tuple pattern") }; - let tup_vals = vec::from_fn(n_tup_elts, |i| GEPi(bcx, val, [0u, i])); + let tup_vals = do vec::from_fn(n_tup_elts) |i| { + adt::trans_GEP(bcx, &tup_repr, val, 0, i) + }; compile_submatch(bcx, enter_tup(bcx, dm, m, col, val, n_tup_elts), vec::append(tup_vals, vals_left), chk); return; @@ -1310,8 +1313,10 @@ pub fn compile_submatch(bcx: block, } } - let llstructvals = vec::from_fn( - struct_element_count, |i| GEPi(bcx, val, struct_field(i))); + let struct_repr = adt::represent_type(bcx.ccx(), struct_ty); + let llstructvals = do vec::from_fn(struct_element_count) |i| { + adt::trans_GEP(bcx, &struct_repr, val, 0, i) + }; compile_submatch(bcx, enter_tuple_struct(bcx, dm, m, col, val, struct_element_count), @@ -1745,9 +1750,11 @@ pub fn bind_irrefutable_pat(bcx: block, // This is a unit-like struct. Nothing to do here. } Some(elems) => { - // This is the tuple variant case. + // This is the tuple struct case. + let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = GEPi(bcx, val, struct_field(i)); + let fldptr = adt::trans_GEP(bcx, &repr, + val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, fldptr, @@ -1765,10 +1772,12 @@ pub fn bind_irrefutable_pat(bcx: block, ast::pat_rec(fields, _) | ast::pat_struct(_, fields, _) => { let tcx = bcx.tcx(); let pat_ty = node_id_type(bcx, pat.id); - do expr::with_field_tys(tcx, pat_ty, None) |_hd, field_tys| { + let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); + do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { for vec::each(fields) |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); - let fldptr = GEPi(bcx, val, struct_field(ix)); + let fldptr = adt::trans_GEP(bcx, &pat_repr, val, + discr, ix); bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, @@ -1778,8 +1787,9 @@ pub fn bind_irrefutable_pat(bcx: block, } } ast::pat_tup(elems) => { + let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = GEPi(bcx, val, [0u, i]); + let fldptr = adt::trans_GEP(bcx, &repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, fldptr, From 80844f993d8964ca89630115c5c0f7e8beb315cb Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 13:15:05 -0800 Subject: [PATCH 15/37] Add regression tests for a subtle aspect of expr_struct translation. The first is reduced from a case in rustdoc (originally involving an ARC); the other is related. No committed version has gotten these wrong, but when I broke them it showed up only in rustdoc; there was nothing in the test suite (or the compiler!) that failed. The general issue is that the statics and trans have to agree on order of evaluation, or else you get use-after-move-out-of errors at runtime. --- src/test/run-pass/struct-order-of-eval-1.rs | 16 ++++++++++++++++ src/test/run-pass/struct-order-of-eval-2.rs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/run-pass/struct-order-of-eval-1.rs create mode 100644 src/test/run-pass/struct-order-of-eval-2.rs diff --git a/src/test/run-pass/struct-order-of-eval-1.rs b/src/test/run-pass/struct-order-of-eval-1.rs new file mode 100644 index 0000000000000..db7c73cbfc5ea --- /dev/null +++ b/src/test/run-pass/struct-order-of-eval-1.rs @@ -0,0 +1,16 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S { f0: ~str, f1: int } + +pub fn main() { + let s = ~"Hello, world!"; + let _s = S { f0: str::from_slice(s), ..S { f0: s, f1: 23 } }; +} diff --git a/src/test/run-pass/struct-order-of-eval-2.rs b/src/test/run-pass/struct-order-of-eval-2.rs new file mode 100644 index 0000000000000..413f185659a6f --- /dev/null +++ b/src/test/run-pass/struct-order-of-eval-2.rs @@ -0,0 +1,16 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S { f0: ~str, f1: ~str } + +pub fn main() { + let s = ~"Hello, world!"; + let _s = S { f1: str::from_slice(s), f0: s }; +} From 2a028c5ab8363d9263d0cda09d6ab884c5b73978 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 14:01:43 -0800 Subject: [PATCH 16/37] Convert newtype "dereference" to trans::adt. Note that in the ByValue case (which can't happen? yet?) we're still effectively bitcasting, I think. So this change adds a way to assert that that's safe. Note also, for future reference, that LLVM's instcombine pass will turn a bitcast into a GEP(0, 0, ...) if possible. --- src/librustc/middle/trans/adt.rs | 9 +++++++++ src/librustc/middle/trans/datum.rs | 12 +++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 6aab2af567fb9..7e457fffd597b 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -378,3 +378,12 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint) real_ix = real_ix + 1; } } + +/// Is it safe to bitcast a value to the one field of its one variant? +pub fn is_newtypeish(r: &Repr) -> bool { + match *r { + Univariant(ref st, DtorAbsent) + | Univariant(ref st, NoDtor) => st.fields.len() == 1, + _ => false + } +} diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 6f27a190b170e..79fd1dde5411c 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -90,6 +90,7 @@ use core::prelude::*; use lib; use lib::llvm::ValueRef; use middle::borrowck::{RootInfo, root_map_key}; +use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee; @@ -677,15 +678,17 @@ pub impl Datum { return (None, bcx); } + let repr = adt::represent_type(ccx, self.ty); + assert adt::is_newtypeish(&repr); let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]); return match self.mode { ByRef => { // Recast lv.val as a pointer to the newtype // rather than a ptr to the enum type. - let llty = T_ptr(type_of::type_of(ccx, ty)); ( Some(Datum { - val: PointerCast(bcx, self.val, llty), + val: adt::trans_GEP(bcx, &repr, self.val, + 0, 0), ty: ty, mode: ByRef, source: ZeroMem @@ -715,6 +718,8 @@ pub impl Datum { return (None, bcx); } + let repr = adt::represent_type(ccx, self.ty); + assert adt::is_newtypeish(&repr); let ty = fields[0].mt.ty; return match self.mode { ByRef => { @@ -724,7 +729,8 @@ pub impl Datum { // destructors. ( Some(Datum { - val: GEPi(bcx, self.val, [0, 0, 0]), + val: adt::trans_GEP(bcx, &repr, self.val, + 0, 0), ty: ty, mode: ByRef, source: ZeroMem From bb689c09f5ea185e082254c514bae1f8940e04a4 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 14:38:59 -0800 Subject: [PATCH 17/37] Convert const ADT construction to trans::adt. Also converts const cast-from-enum, because it used the same routine to get the discriminant as what's renovated to construct the enums. Also fixes ICE on struct-like variants as consts, and provides a slightly less bad ICE for functional-update-like struct expressions in consts. --- src/librustc/middle/trans/base.rs | 24 ----- src/librustc/middle/trans/consts.rs | 133 +++++++++------------------- 2 files changed, 44 insertions(+), 113 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index b6701c6c3df1f..d5656b9002be1 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -828,30 +828,6 @@ pub fn trans_external_path(ccx: @CrateContext, did: ast::def_id, t: ty::t) }; } -pub fn get_discrim_val(cx: @CrateContext, span: span, enum_did: ast::def_id, - variant_did: ast::def_id) -> ValueRef { - // Can't use `discrims` from the crate context here because - // those discriminants have an extra level of indirection, - // and there's no LLVM constant load instruction. - let mut lldiscrim_opt = None; - for ty::enum_variants(cx.tcx, enum_did).each |variant_info| { - if variant_info.id == variant_did { - lldiscrim_opt = Some(C_int(cx, - variant_info.disr_val)); - break; - } - } - - match lldiscrim_opt { - None => { - cx.tcx.sess.span_bug(span, ~"didn't find discriminant?!"); - } - Some(found_lldiscrim) => { - found_lldiscrim - } - } -} - pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block { let _icx = bcx.insn_ctxt("invoke_"); if bcx.unreachable { return bcx; } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 6d37c4393ab9f..19d5bb4dbf55b 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -12,6 +12,7 @@ use core::prelude::*; use lib::llvm::{llvm, ValueRef, TypeRef, Bool, True, False}; use middle::const_eval; +use middle::trans::adt; use middle::trans::base; use middle::trans::base::get_insn_ctxt; use middle::trans::common::*; @@ -328,24 +329,8 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { } (expr::cast_enum, expr::cast_integral) | (expr::cast_enum, expr::cast_float) => { - let def = ty::resolve_expr(cx.tcx, base); - let (enum_did, variant_did) = match def { - ast::def_variant(enum_did, variant_did) => { - (enum_did, variant_did) - } - _ => cx.sess.bug(~"enum cast source is not enum") - }; - // Note that we know this is a C-like (nullary) enum - // variant or we wouldn't have gotten here - let variants = ty::enum_variants(cx.tcx, enum_did); - let iv = if variants.len() == 1 { - // Univariants don't have a discriminant field, - // because there's only one value it could have: - C_integral(T_i64(), - variants[0].disr_val as u64, True) - } else { - base::get_discrim_val(cx, e.span, enum_did, variant_did) - }; + let repr = adt::represent_type(cx, basety); + let iv = C_int(cx, adt::const_get_discrim(cx, &repr, v)); let ety_cast = expr::cast_type_kind(ety); match ety_cast { expr::cast_integral => { @@ -373,18 +358,22 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { gv } ast::expr_tup(es) => { - C_struct(es.map(|e| const_expr(cx, *e))) + let ety = ty::expr_ty(cx.tcx, e); + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &repr, 0, es.map(|e| const_expr(cx, *e))) } ast::expr_rec(ref fs, None) => { - C_struct([C_struct( - (*fs).map(|f| const_expr(cx, f.node.expr)))]) + let ety = ty::expr_ty(cx.tcx, e); + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &repr, 0, + fs.map(|f| const_expr(cx, f.node.expr))) } - ast::expr_struct(_, ref fs, _) => { + ast::expr_struct(_, ref fs, None) => { let ety = ty::expr_ty(cx.tcx, e); - let cs = do expr::with_field_tys(cx.tcx, - ety, - None) |_hd, field_tys| { - field_tys.map(|field_ty| { + let repr = adt::represent_type(cx, ety); + do expr::with_field_tys(cx.tcx, ety, Some(e.id)) + |discr, field_tys| { + let cs = field_tys.map(|field_ty| { match fs.find(|f| field_ty.ident == f.node.ident) { Some(ref f) => const_expr(cx, (*f).node.expr), None => { @@ -392,9 +381,9 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { e.span, ~"missing struct field"); } } - }) - }; - C_struct([C_struct(cs)]) + }); + adt::trans_const(cx, &repr, discr, cs) + } } ast::expr_vec(es, ast::m_imm) => { let (v, _, _) = const_vec(cx, e, es); @@ -452,25 +441,12 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { get_const_val(cx, def_id) } Some(ast::def_variant(enum_did, variant_did)) => { - // Note that we know this is a C-like (nullary) enum - // variant or we wouldn't have gotten here -- the constant - // checker forbids paths that don't map to C-like enum - // variants. - if ty::enum_is_univariant(cx.tcx, enum_did) { - // Univariants have no discriminant field. - C_struct(~[]) - } else { - let lldiscrim = base::get_discrim_val(cx, e.span, - enum_did, - variant_did); - // However, we still have to pad it out to the - // size of the full enum; see the expr_call case, - // below. let ety = ty::expr_ty(cx.tcx, e); - let size = machine::static_size_of_enum(cx, ety); - let padding = C_null(T_array(T_i8(), size)); - C_struct(~[lldiscrim, padding]) - } + let repr = adt::represent_type(cx, ety); + let vinfo = ty::enum_variant_with_id(cx.tcx, + enum_did, + variant_did); + adt::trans_const(cx, &repr, vinfo.disr_val, []) } Some(ast::def_struct(_)) => { let ety = ty::expr_ty(cx.tcx, e); @@ -478,52 +454,31 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { C_null(llty) } _ => { - cx.sess.span_bug(e.span, - ~"expected a const, fn, or variant def") + cx.sess.span_bug(e.span, ~"expected a const, fn, \ + struct, or variant def") } } } ast::expr_call(callee, args, _) => { - match cx.tcx.def_map.find(&callee.id) { - Some(ast::def_struct(def_id)) => { - let llstructbody = - C_struct(args.map(|a| const_expr(cx, *a))); - if ty::ty_dtor(cx.tcx, def_id).is_present() { - C_struct(~[ llstructbody, C_u8(0) ]) - } else { - C_struct(~[ llstructbody ]) - } - } - Some(ast::def_variant(tid, vid)) => { - let ety = ty::expr_ty(cx.tcx, e); - let univar = ty::enum_is_univariant(cx.tcx, tid); - let size = machine::static_size_of_enum(cx, ety); - - let discrim = base::get_discrim_val(cx, e.span, tid, vid); - let c_args = C_struct(args.map(|a| const_expr(cx, *a))); - - // FIXME (#1645): enum body alignment is generaly wrong. - if !univar { - // Pad out the data to the size of its type_of; - // this is necessary if the enum is contained - // within an aggregate (tuple, struct, vector) so - // that the next element is at the right offset. - let actual_size = - machine::llsize_of_real(cx, llvm::LLVMTypeOf(c_args)); - let padding = - C_null(T_array(T_i8(), size - actual_size)); - // A packed_struct has an alignment of 1; thus, - // wrapping one around c_args will misalign it the - // same way we normally misalign enum bodies - // without affecting its internal alignment or - // changing the alignment of the enum. - C_struct(~[discrim, C_packed_struct(~[c_args]), padding]) - } else { - C_struct(~[c_args]) - } - } - _ => cx.sess.span_bug(e.span, ~"expected a struct def") - } + match cx.tcx.def_map.find(&callee.id) { + Some(ast::def_struct(_)) => { + let ety = ty::expr_ty(cx.tcx, e); + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &repr, 0, + args.map(|a| const_expr(cx, *a))) + } + Some(ast::def_variant(enum_did, variant_did)) => { + let ety = ty::expr_ty(cx.tcx, e); + let repr = adt::represent_type(cx, ety); + let vinfo = ty::enum_variant_with_id(cx.tcx, + enum_did, + variant_did); + adt::trans_const(cx, &repr, vinfo.disr_val, + args.map(|a| const_expr(cx, *a))) + } + _ => cx.sess.span_bug(e.span, ~"expected a struct or \ + variant def") + } } ast::expr_paren(e) => { return const_expr(cx, e); } _ => cx.sess.span_bug(e.span, From f0c6a8ebe9091bcc03807060ea7c7394c67a734c Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 14:48:34 -0800 Subject: [PATCH 18/37] Test for struct-like variants in consts --- src/test/run-pass/const-enum-structlike.rs | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/const-enum-structlike.rs diff --git a/src/test/run-pass/const-enum-structlike.rs b/src/test/run-pass/const-enum-structlike.rs new file mode 100644 index 0000000000000..83d8174075938 --- /dev/null +++ b/src/test/run-pass/const-enum-structlike.rs @@ -0,0 +1,23 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { + S0 { s: ~str }, + S1 { u: uint } +} + +const C: E = S1 { u: 23 }; + +fn main() { + match C { + S0 { _ } => fail!(), + S1 { u } => assert u == 23 + } +} From 59daf76a8db88ec2ea4640f0fbf598402d1a10cb Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 14:49:01 -0800 Subject: [PATCH 19/37] Make functional-update struct consts not an ICE --- src/librustc/middle/check_const.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6eb698d34d207..c00856a0a98bd 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -168,8 +168,8 @@ pub fn check_expr(sess: Session, expr_field(*) | expr_index(*) | expr_tup(*) | - expr_struct(*) | - expr_rec(*) => { } + expr_struct(_, _, None) | + expr_rec(_, None) => { } expr_addr_of(*) => { sess.span_err( e.span, From 075affa50d04c585a53d0c8e7b66bae372a72648 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 15:03:47 -0800 Subject: [PATCH 20/37] Convert const field extraction to trans::adt --- src/librustc/middle/trans/consts.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 19d5bb4dbf55b..c42db4a90a18f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -240,16 +240,12 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { } ast::expr_field(base, field, _) => { let bt = ty::expr_ty(cx.tcx, base); + let brepr = adt::represent_type(cx, bt); let bv = const_expr(cx, base); let (bt, bv) = const_autoderef(cx, bt, bv); - do expr::with_field_tys(cx.tcx, bt, None) |_, field_tys| { + do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx, field, field_tys); - - // Note: ideally, we'd use `struct_field()` here instead - // of hardcoding [0, ix], but we can't because it yields - // the wrong type and also inserts an extra 0 that is - // not needed in the constant variety: - const_get_elt(cx, bv, [0, ix as c_uint]) + adt::const_get_element(cx, &brepr, bv, discr, ix) } } From 6bb6baba2cbcd885b53709bdd907e7053867a71e Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 16:24:54 -0800 Subject: [PATCH 21/37] Renovate cast-to-int --- src/librustc/middle/trans/expr.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index cd6d1e42b8c54..72926f91af52c 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1644,22 +1644,8 @@ fn trans_imm_cast(bcx: block, expr: @ast::expr, (cast_enum, cast_integral) | (cast_enum, cast_float) => { let bcx = bcx; - let in_tid = match ty::get(t_in).sty { - ty::ty_enum(did, _) => did, - _ => ccx.sess.bug(~"enum cast source is not enum") - }; - let variants = ty::enum_variants(ccx.tcx, in_tid); - let lldiscrim_a = if variants.len() == 1 { - // Univariants don't have a discriminant field, - // because there's only one value it could have: - C_integral(T_enum_discrim(ccx), - variants[0].disr_val as u64, True) - } else { - let llenumty = T_opaque_enum_ptr(ccx); - let av_enum = PointerCast(bcx, llexpr, llenumty); - let lldiscrim_a_ptr = GEPi(bcx, av_enum, [0u, 0u]); - Load(bcx, lldiscrim_a_ptr) - }; + let repr = adt::represent_type(ccx, t_in); + let lldiscrim_a = adt::trans_cast_to_int(bcx, &repr, llexpr); match k_out { cast_integral => int_cast(bcx, ll_t_out, val_ty(lldiscrim_a), From ca450e345f57f277c1cb0406b8366280c8d41f48 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 17:19:16 -0800 Subject: [PATCH 22/37] Move trans_enum_variant to trans::adt. As a result, trans_enum_variant no longer cares what kind of enum it's dealing with, so the "degen" parameter goes away in a bunch of places. --- src/librustc/middle/trans/base.rs | 32 +++++++++-------------- src/librustc/middle/trans/monomorphize.rs | 3 +-- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d5656b9002be1..26d2e02cb9631 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -39,6 +39,7 @@ use middle::astencode; use middle::borrowck::RootInfo; use middle::resolve; use middle::trans::_match; +use middle::trans::adt; use middle::trans::base; use middle::trans::build::*; use middle::trans::callee; @@ -1861,7 +1862,6 @@ pub fn trans_enum_variant(ccx: @CrateContext, variant: ast::variant, args: &[ast::variant_arg], disr: int, - is_degen: bool, param_substs: Option<@param_substs>, llfndecl: ValueRef) { let _icx = ccx.insn_ctxt("trans_enum_variant"); @@ -1890,21 +1890,15 @@ pub fn trans_enum_variant(ccx: @CrateContext, let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id)); let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); - // Cast the enum to a type we can GEP into. - let llblobptr = if is_degen { - fcx.llretptr - } else { - let llenumptr = - PointerCast(bcx, fcx.llretptr, T_opaque_enum_ptr(ccx)); - let lldiscrimptr = GEPi(bcx, llenumptr, [0u, 0u]); - Store(bcx, C_int(ccx, disr), lldiscrimptr); - GEPi(bcx, llenumptr, [0u, 1u]) - }; - let t_id = local_def(enum_id); - let v_id = local_def(variant.node.id); + // XXX is there a better way to reconstruct the ty::t? + let enum_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None, + ty::node_id_to_type(ccx.tcx, enum_id)); + let repr = adt::represent_type(ccx, enum_ty); + + adt::trans_set_discr(bcx, &repr, fcx.llretptr, disr); for vec::eachi(args) |i, va| { - let lldestptr = GEP_enum(bcx, llblobptr, t_id, v_id, - /*bad*/copy ty_param_substs, i); + let lldestptr = adt::trans_GEP(bcx, &repr, fcx.llretptr, disr, i); + // If this argument to this function is a enum, it'll have come in to // this function as an opaque blob due to the way that type_of() // works. So we have to cast to the destination's view of the type. @@ -2014,7 +2008,7 @@ pub fn trans_struct_dtor(ccx: @CrateContext, } pub fn trans_enum_def(ccx: @CrateContext, enum_definition: ast::enum_def, - id: ast::node_id, degen: bool, + id: ast::node_id, path: @ast_map::path, vi: @~[ty::VariantInfo], i: &mut uint) { for vec::each(enum_definition.variants) |variant| { @@ -2025,7 +2019,7 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: ast::enum_def, ast::tuple_variant_kind(ref args) if args.len() > 0 => { let llfn = get_item_val(ccx, variant.node.id); trans_enum_variant(ccx, id, *variant, /*bad*/copy *args, - disr_val, degen, None, llfn); + disr_val, None, llfn); } ast::tuple_variant_kind(_) => { // Nothing to do. @@ -2038,7 +2032,6 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: ast::enum_def, trans_enum_def(ccx, *enum_definition, id, - degen, path, vi, &mut *i); @@ -2089,11 +2082,10 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) { } ast::item_enum(ref enum_definition, ref generics) => { if !generics.is_type_parameterized() { - let degen = (*enum_definition).variants.len() == 1u; let vi = ty::enum_variants(ccx.tcx, local_def(item.id)); let mut i = 0; trans_enum_def(ccx, (*enum_definition), item.id, - degen, path, vi, &mut i); + path, vi, &mut i); } } ast::item_const(_, expr) => consts::trans_const(ccx, expr, item.id), diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index c0af1f4fad2a7..ffc5d132c9fd8 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -196,8 +196,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, match (*v).node.kind { ast::tuple_variant_kind(ref args) => { trans_enum_variant(ccx, enum_item.id, *v, /*bad*/copy *args, - this_tv.disr_val, tvs.len() == 1u, - psubsts, d); + this_tv.disr_val, psubsts, d); } ast::struct_variant_kind(_) => ccx.tcx.sess.bug(~"can't monomorphize struct variants"), From 68b3f0d8a419c94eaead13517cd87aaf5fc74b86 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 17:32:09 -0800 Subject: [PATCH 23/37] base::iter_structural_ty: tuples --- src/librustc/middle/trans/base.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 26d2e02cb9631..ca934d755b426 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -689,10 +689,11 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, cx = tvec::iter_vec_raw(cx, base, t, len, f); } ty::ty_tup(args) => { - for vec::eachi(args) |i, arg| { - let llfld_a = GEPi(cx, av, [0u, i]); - cx = f(cx, llfld_a, *arg); - } + let repr = adt::represent_type(cx.ccx(), t); + for vec::eachi(args) |i, arg| { + let llfld_a = adt::trans_GEP(cx, &repr, av, 0, i); + cx = f(cx, llfld_a, *arg); + } } ty::ty_enum(tid, ref substs) => { let variants = ty::enum_variants(cx.tcx(), tid); From c0f6909f7ecee906ea21c9bbba903e105bb7e711 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 17:34:32 -0800 Subject: [PATCH 24/37] base::iter_structural_ty: structs and records --- src/librustc/middle/trans/base.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ca934d755b426..ec4dd12498ac6 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -676,9 +676,10 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let mut cx = cx; match /*bad*/copy ty::get(t).sty { ty::ty_rec(*) | ty::ty_struct(*) => { - do expr::with_field_tys(cx.tcx(), t, None) |_has_dtor, field_tys| { + let repr = adt::represent_type(cx.ccx(), t); + do expr::with_field_tys(cx.tcx(), t, None) |discr, field_tys| { for vec::eachi(field_tys) |i, field_ty| { - let llfld_a = GEPi(cx, av, struct_field(i)); + let llfld_a = adt::trans_GEP(cx, &repr, av, discr, i); cx = f(cx, llfld_a, field_ty.mt.ty); } } From 29d0430c56276da7371a845008bef3d1361b842e Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 18:41:39 -0800 Subject: [PATCH 25/37] Convert iter_structural_ty to trans::adt --- src/librustc/middle/trans/base.rs | 113 +++++++++++++----------------- 1 file changed, 49 insertions(+), 64 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ec4dd12498ac6..342da3fadf709 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -640,35 +640,16 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, f: val_and_ty_fn) -> block { let _icx = cx.insn_ctxt("iter_structural_ty"); - fn iter_variant(cx: block, a_tup: ValueRef, + fn iter_variant(cx: block, repr: &adt::Repr, av: ValueRef, variant: ty::VariantInfo, - tps: &[ty::t], tid: ast::def_id, - f: val_and_ty_fn) -> block { + tps: &[ty::t], f: val_and_ty_fn) -> block { let _icx = cx.insn_ctxt("iter_variant"); - if variant.args.len() == 0u { return cx; } - let fn_ty = variant.ctor_ty; - let ccx = cx.ccx(); + let tcx = cx.tcx(); let mut cx = cx; - match ty::get(fn_ty).sty { - ty::ty_bare_fn(ref fn_ty) => { - let mut j = 0u; - let v_id = variant.id; - for vec::each(fn_ty.sig.inputs) |a| { - let llfldp_a = GEP_enum(cx, a_tup, tid, v_id, - /*bad*/copy tps, j); - // This assumes the self type is absent (it passes - // None for the self_ty_opt arg of substs_tps). - // I think that's ok since you can't have an enum - // inside a trait. - let ty_subst = ty::subst_tps(ccx.tcx, tps, None, a.ty); - cx = f(cx, llfldp_a, ty_subst); - j += 1u; - } - } - _ => cx.tcx().sess.bug(fmt!("iter_variant: not a function type: \ - %s (variant name = %s)", - cx.ty_to_str(fn_ty), - *cx.sess().str_of(variant.name))) + + for variant.args.eachi |i, &arg| { + cx = f(cx, adt::trans_GEP(cx, repr, av, variant.disr_val, i), + ty::subst_tps(tcx, tps, None, arg)); } return cx; } @@ -697,45 +678,49 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, } } ty::ty_enum(tid, ref substs) => { - let variants = ty::enum_variants(cx.tcx(), tid); - let n_variants = (*variants).len(); - - // Cast the enums to types we can GEP into. - if n_variants == 1u { - return iter_variant(cx, - av, - variants[0], - /*bad*/copy substs.tps, - tid, - f); - } + let ccx = cx.ccx(); - let ccx = cx.ccx(); - let llenumty = T_opaque_enum_ptr(ccx); - let av_enum = PointerCast(cx, av, llenumty); - let lldiscrim_a_ptr = GEPi(cx, av_enum, [0u, 0u]); - let llunion_a_ptr = GEPi(cx, av_enum, [0u, 1u]); - let lldiscrim_a = Load(cx, lldiscrim_a_ptr); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - cx = f(cx, lldiscrim_a_ptr, ty::mk_int(cx.tcx())); - let unr_cx = sub_block(cx, ~"enum-iter-unr"); - Unreachable(unr_cx); - let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants); - let next_cx = sub_block(cx, ~"enum-iter-next"); - for vec::each(*variants) |variant| { - let variant_cx = - sub_block(cx, - ~"enum-iter-variant-" + - int::to_str(variant.disr_val)); - AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb); - let variant_cx = - iter_variant(variant_cx, llunion_a_ptr, *variant, - /*bad*/copy (*substs).tps, tid, f); - Br(variant_cx, next_cx.llbb); - } - return next_cx; + let repr = adt::represent_type(ccx, t); + let variants = ty::enum_variants(ccx.tcx, tid); + let n_variants = (*variants).len(); + + // NB: we must hit the discriminant first so that structural + // comparison know not to proceed when the discriminants differ. + + match adt::trans_switch(cx, &repr, av) { + (_match::single, None) => { + cx = iter_variant(cx, &repr, av, variants[0], + substs.tps, f); + } + (_match::switch, Some(lldiscrim_a)) => { + cx = f(cx, lldiscrim_a, ty::mk_int(cx.tcx())); + let unr_cx = sub_block(cx, ~"enum-iter-unr"); + Unreachable(unr_cx); + let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, + n_variants); + let next_cx = sub_block(cx, ~"enum-iter-next"); + + for vec::each(*variants) |variant| { + let variant_cx = + sub_block(cx, ~"enum-iter-variant-" + + int::to_str(variant.disr_val)); + let variant_cx = + iter_variant(variant_cx, &repr, av, *variant, + substs.tps, f); + match adt::trans_case(cx, &repr, variant.disr_val) { + _match::single_result(r) => { + AddCase(llswitch, r.val, variant_cx.llbb) + } + _ => ccx.sess.unimpl(~"value from adt::trans_case \ + in iter_structural_ty") + } + Br(variant_cx, next_cx.llbb); + } + cx = next_cx; + } + _ => ccx.sess.unimpl(~"value from adt::trans_switch \ + in iter_structural_ty") + } } _ => cx.sess().unimpl(~"type in iter_structural_ty") } From 5ca4fdfc981a9c0c7ecf3e23c4b26c05a6a7d2fe Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 21:26:34 -0800 Subject: [PATCH 26/37] Convert trans_tuple_struct to trans::adt. Surely this cannot be the best way to get the type. --- src/librustc/middle/trans/base.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 342da3fadf709..9120ac3083a02 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1938,8 +1938,23 @@ pub fn trans_tuple_struct(ccx: @CrateContext, let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id)); let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); + // XXX is there a better way to reconstruct the ty::t? + let ty_param_substs = match param_substs { + Some(ref substs) => /*bad*/copy substs.tys, + None => ~[] + }; + let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None, + ty::node_id_to_type(ccx.tcx, ctor_id)); + let tup_ty = match ty::get(ctor_ty).sty { + ty::ty_bare_fn(ref bft) => bft.sig.output, + _ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \ + return type %s", + ty_to_str(ccx.tcx, ctor_ty))) + }; + let repr = adt::represent_type(ccx, tup_ty); + for fields.eachi |i, field| { - let lldestptr = GEPi(bcx, fcx.llretptr, [0, 0, i]); + let lldestptr = adt::trans_GEP(bcx, &repr, fcx.llretptr, 0, i); let llarg = match fcx.llargs.get(&field.node.id) { local_mem(x) => x, _ => { From 71b6e945c11a3a0f44e5e45bcad4e7bddf35ba8a Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 22:46:33 -0800 Subject: [PATCH 27/37] glue::trans_struct_drop -> adt --- src/librustc/middle/trans/glue.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 7bed3e86190a2..d38a04785b99b 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -19,6 +19,7 @@ use back::link::*; use driver::session; use lib; use lib::llvm::{llvm, ValueRef, TypeRef, True}; +use middle::trans::adt; use middle::trans::base::*; use middle::trans::callee; use middle::trans::closure; @@ -447,10 +448,10 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { match ty::ty_dtor(bcx.tcx(), did) { ty::NoDtor => bcx, ty::LegacyDtor(ref dt_id) => { - trans_struct_drop(bcx, v, *dt_id, did, substs, false) + trans_struct_drop(bcx, t, v, *dt_id, did, substs, false) } ty::TraitDtor(ref dt_id) => { - trans_struct_drop(bcx, v, *dt_id, did, substs, true) + trans_struct_drop(bcx, t, v, *dt_id, did, substs, true) } } } @@ -460,6 +461,7 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { } pub fn trans_struct_drop(bcx: block, + t: ty::t, v0: ValueRef, dtor_did: ast::def_id, class_did: ast::def_id, @@ -500,11 +502,12 @@ pub fn trans_struct_drop(bcx: block, Call(bcx, dtor_addr, args); // Drop the fields + let repr = adt::represent_type(bcx.ccx(), t); let field_tys = ty::struct_mutable_fields(bcx.tcx(), class_did, substs); for vec::eachi(field_tys) |i, fld| { - let llfld_a = GEPi(bcx, v0, struct_field(i)); + let llfld_a = adt::trans_GEP(bcx, &repr, v0, 0, i); bcx = drop_ty(bcx, llfld_a, fld.mt.ty); } @@ -534,10 +537,10 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { ty::TraitDtor(dtor) => { - trans_struct_drop(bcx, v0, dtor, did, substs, true) + trans_struct_drop(bcx, t, v0, dtor, did, substs, true) } ty::LegacyDtor(dtor) => { - trans_struct_drop(bcx, v0, dtor, did, substs, false) + trans_struct_drop(bcx, t, v0, dtor, did, substs, false) } ty::NoDtor => { // No dtor? Just the default case From b6bcf1a81f14223b9108c724794d388db1233905 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 23:20:08 -0800 Subject: [PATCH 28/37] Finish removing struct layout dependencies from glue. --- src/librustc/middle/trans/adt.rs | 8 ++++++++ src/librustc/middle/trans/glue.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 7e457fffd597b..971a8db215aaa 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -266,6 +266,14 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, GEPi(bcx, val, [0, ix]) } +pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef { + match *r { + Univariant(_, DtorPresent) => GEPi(bcx, val, [0, 1]), + _ => bcx.ccx().sess.bug(~"tried to get drop flag of non-droppable \ + type") + } +} + pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, vals: &[ValueRef]) -> ValueRef { match *r { diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index d38a04785b99b..f2ad0465e5b5b 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -468,7 +468,8 @@ pub fn trans_struct_drop(bcx: block, substs: &ty::substs, take_ref: bool) -> block { - let drop_flag = GEPi(bcx, v0, struct_dtor()); + let repr = adt::represent_type(bcx.ccx(), t); + let drop_flag = adt::trans_drop_flag_ptr(bcx, &repr, v0); do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| { let mut bcx = cx; @@ -502,7 +503,6 @@ pub fn trans_struct_drop(bcx: block, Call(bcx, dtor_addr, args); // Drop the fields - let repr = adt::represent_type(bcx.ccx(), t); let field_tys = ty::struct_mutable_fields(bcx.tcx(), class_did, substs); From 8105da80676a9ff85199a2bbcd9d9fd4ca019086 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 23:21:22 -0800 Subject: [PATCH 29/37] GC the now-unused old layout helpers --- src/librustc/middle/trans/base.rs | 19 ------------------- src/librustc/middle/trans/common.rs | 27 --------------------------- 2 files changed, 46 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 9120ac3083a02..fb7d5bba1e564 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -239,25 +239,6 @@ pub fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) -> PointerCast(bcx, bumped, typ) } -// Replacement for the LLVM 'GEP' instruction when field indexing into a enum. -// @llblobptr is the data part of a enum value; its actual type -// is meaningless, as it will be cast away. -pub fn GEP_enum(bcx: block, llblobptr: ValueRef, enum_id: ast::def_id, - variant_id: ast::def_id, ty_substs: &[ty::t], - ix: uint) -> ValueRef { - let _icx = bcx.insn_ctxt("GEP_enum"); - let ccx = bcx.ccx(); - let variant = ty::enum_variant_with_id(ccx.tcx, enum_id, variant_id); - assert ix < variant.args.len(); - - let arg_lltys = vec::map(variant.args, |aty| { - type_of(ccx, ty::subst_tps(ccx.tcx, ty_substs, None, *aty)) - }); - let typed_blobptr = PointerCast(bcx, llblobptr, - T_ptr(T_struct(arg_lltys))); - GEPi(bcx, typed_blobptr, [0u, ix]) -} - // Returns a pointer to the body for the box. The box may be an opaque // box. The result will be casted to the type of body_t, if it is statically // known. diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 2d06a5a5e8788..70b63f7952e1a 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1042,21 +1042,6 @@ pub fn T_enum_discrim(cx: @CrateContext) -> TypeRef { return cx.int_type; } -pub fn T_opaque_enum(cx: @CrateContext) -> TypeRef { - let s = @"opaque_enum"; - match name_has_type(cx.tn, s) { - Some(t) => return t, - _ => () - } - let t = T_struct(~[T_enum_discrim(cx), T_i8()]); - associate_type(cx.tn, s, t); - return t; -} - -pub fn T_opaque_enum_ptr(cx: @CrateContext) -> TypeRef { - return T_ptr(T_opaque_enum(cx)); -} - pub fn T_captured_tydescs(cx: @CrateContext, n: uint) -> TypeRef { return T_struct(vec::from_elem::(n, T_ptr(cx.tydesc_type))); } @@ -1468,18 +1453,6 @@ pub fn dummy_substs(+tps: ~[ty::t]) -> ty::substs { } } -pub fn struct_field(index: uint) -> [uint * 3] { - //! The GEPi sequence to access a field of a record/struct. - - [0, 0, index] -} - -pub fn struct_dtor() -> [uint * 2] { - //! The GEPi sequence to access the dtor of a struct. - - [0, 1] -} - // Casts a Rust bool value to an i1. pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef { build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false)) From a8237a46f134fa00d24ef1874abc0a4b45640cbf Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sun, 24 Feb 2013 23:21:58 -0800 Subject: [PATCH 30/37] Bonus Fix: typarams are no longer inhabited --- src/librustc/middle/trans/common.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 70b63f7952e1a..109a4985d3cb6 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1016,22 +1016,6 @@ pub fn T_chan(cx: @CrateContext, _t: TypeRef) -> TypeRef { pub fn T_taskptr(cx: @CrateContext) -> TypeRef { return T_ptr(cx.task_type); } -// This type must never be used directly; it must always be cast away. -pub fn T_typaram(tn: @TypeNames) -> TypeRef { - let s = @"typaram"; - match name_has_type(tn, s) { - Some(t) => return t, - _ => () - } - let t = T_i8(); - associate_type(tn, s, t); - return t; -} - -pub fn T_typaram_ptr(tn: @TypeNames) -> TypeRef { - return T_ptr(T_typaram(tn)); -} - pub fn T_opaque_cbox_ptr(cx: @CrateContext) -> TypeRef { // closures look like boxes (even when they are ~fn or &fn) // see trans_closure.rs From a9026c7f19d0418c8c0d4d401640bdd15b2e1d7e Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Mon, 25 Feb 2013 01:49:21 -0800 Subject: [PATCH 31/37] Memoize trans::adt::represent_type --- src/librustc/middle/trans/_match.rs | 22 +++++++++++----------- src/librustc/middle/trans/adt.rs | 17 +++++++++++------ src/librustc/middle/trans/base.rs | 20 +++++++++++--------- src/librustc/middle/trans/common.rs | 3 +++ src/librustc/middle/trans/consts.rs | 16 ++++++++-------- src/librustc/middle/trans/datum.rs | 8 ++++---- src/librustc/middle/trans/expr.rs | 10 +++++----- src/librustc/middle/trans/glue.rs | 4 ++-- src/librustc/middle/trans/type_of.rs | 6 +++--- 9 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 5a9d6c3b6c662..96afc83904d44 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -192,7 +192,7 @@ pub enum Lit { // range) pub enum Opt { lit(Lit), - var(/* disr val */int, adt::Repr), + var(/* disr val */int, @adt::Repr), range(@ast::expr, @ast::expr), vec_len_eq(uint), vec_len_ge(uint) @@ -268,7 +268,7 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { let llval = consts::get_const_val(bcx.ccx(), lit_id); return single_result(rslt(bcx, llval)); } - var(disr_val, ref repr) => { + var(disr_val, repr) => { return adt::trans_case(bcx, repr, disr_val); } range(l1, l2) => { @@ -1274,7 +1274,7 @@ pub fn compile_submatch(bcx: block, do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { let rec_vals = rec_fields.map(|field_name| { let ix = ty::field_idx_strict(tcx, *field_name, field_tys); - adt::trans_GEP(bcx, &pat_repr, val, discr, ix) + adt::trans_GEP(bcx, pat_repr, val, discr, ix) }); compile_submatch( bcx, @@ -1293,7 +1293,7 @@ pub fn compile_submatch(bcx: block, _ => ccx.sess.bug(~"non-tuple type in tuple pattern") }; let tup_vals = do vec::from_fn(n_tup_elts) |i| { - adt::trans_GEP(bcx, &tup_repr, val, 0, i) + adt::trans_GEP(bcx, tup_repr, val, 0, i) }; compile_submatch(bcx, enter_tup(bcx, dm, m, col, val, n_tup_elts), vec::append(tup_vals, vals_left), chk); @@ -1315,7 +1315,7 @@ pub fn compile_submatch(bcx: block, let struct_repr = adt::represent_type(bcx.ccx(), struct_ty); let llstructvals = do vec::from_fn(struct_element_count) |i| { - adt::trans_GEP(bcx, &struct_repr, val, 0, i) + adt::trans_GEP(bcx, struct_repr, val, 0, i) }; compile_submatch(bcx, enter_tuple_struct(bcx, dm, m, col, val, @@ -1359,7 +1359,7 @@ pub fn compile_submatch(bcx: block, let mut test_val = val; if opts.len() > 0u { match opts[0] { - var(_, ref repr) => { + var(_, repr) => { let (the_kind, val_opt) = adt::trans_switch(bcx, repr, val); kind = the_kind; for val_opt.each |&tval| { test_val = tval; } @@ -1511,7 +1511,7 @@ pub fn compile_submatch(bcx: block, let mut size = 0u; let mut unpacked = ~[]; match *opt { - var(disr_val, ref repr) => { + var(disr_val, repr) => { let ExtractedBlock {vals: argvals, bcx: new_bcx} = extract_variant_args(opt_cx, repr, disr_val, val); size = argvals.len(); @@ -1731,7 +1731,7 @@ pub fn bind_irrefutable_pat(bcx: block, enum_id, var_id); let args = extract_variant_args(bcx, - &repr, + repr, vinfo.disr_val, val); for sub_pats.each |sub_pat| { @@ -1753,7 +1753,7 @@ pub fn bind_irrefutable_pat(bcx: block, // This is the tuple struct case. let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = adt::trans_GEP(bcx, &repr, + let fldptr = adt::trans_GEP(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, @@ -1776,7 +1776,7 @@ pub fn bind_irrefutable_pat(bcx: block, do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { for vec::each(fields) |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); - let fldptr = adt::trans_GEP(bcx, &pat_repr, val, + let fldptr = adt::trans_GEP(bcx, pat_repr, val, discr, ix); bcx = bind_irrefutable_pat(bcx, f.pat, @@ -1789,7 +1789,7 @@ pub fn bind_irrefutable_pat(bcx: block, ast::pat_tup(elems) => { let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = adt::trans_GEP(bcx, &repr, val, 0, i); + let fldptr = adt::trans_GEP(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, fldptr, diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 971a8db215aaa..00c620c7c8fd8 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::container::Map; use core::libc::c_ulonglong; use core::option::{Option, Some, None}; use core::vec; @@ -43,15 +44,17 @@ struct Struct { } -pub fn represent_node(bcx: block, node: ast::node_id) - -> Repr { +pub fn represent_node(bcx: block, node: ast::node_id) -> @Repr { represent_type(bcx.ccx(), node_id_type(bcx, node)) } -pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { +pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { debug!("Representing: %s", ty_to_str(cx.tcx, t)); - // XXX: cache this - match ty::get(t).sty { + match cx.adt_reprs.find(&t) { + Some(repr) => return *repr, + None => { } + } + let repr = @match ty::get(t).sty { ty::ty_tup(ref elems) => { Univariant(mk_struct(cx, *elems), NoDtor) } @@ -97,7 +100,9 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr { } } _ => cx.sess.bug(~"adt::represent_type called on non-ADT type") - } + }; + cx.adt_reprs.insert(t, repr); + return repr; } fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index fb7d5bba1e564..ae1441731e0f3 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -67,6 +67,7 @@ use util::ppaux::{ty_to_str, ty_to_short_str}; use util::ppaux; use core::hash; +use core::hashmap::linear::LinearMap; use core::int; use core::io; use core::libc::{c_uint, c_ulonglong}; @@ -641,7 +642,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let repr = adt::represent_type(cx.ccx(), t); do expr::with_field_tys(cx.tcx(), t, None) |discr, field_tys| { for vec::eachi(field_tys) |i, field_ty| { - let llfld_a = adt::trans_GEP(cx, &repr, av, discr, i); + let llfld_a = adt::trans_GEP(cx, repr, av, discr, i); cx = f(cx, llfld_a, field_ty.mt.ty); } } @@ -654,7 +655,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, ty::ty_tup(args) => { let repr = adt::represent_type(cx.ccx(), t); for vec::eachi(args) |i, arg| { - let llfld_a = adt::trans_GEP(cx, &repr, av, 0, i); + let llfld_a = adt::trans_GEP(cx, repr, av, 0, i); cx = f(cx, llfld_a, *arg); } } @@ -668,9 +669,9 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, // NB: we must hit the discriminant first so that structural // comparison know not to proceed when the discriminants differ. - match adt::trans_switch(cx, &repr, av) { + match adt::trans_switch(cx, repr, av) { (_match::single, None) => { - cx = iter_variant(cx, &repr, av, variants[0], + cx = iter_variant(cx, repr, av, variants[0], substs.tps, f); } (_match::switch, Some(lldiscrim_a)) => { @@ -686,9 +687,9 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, sub_block(cx, ~"enum-iter-variant-" + int::to_str(variant.disr_val)); let variant_cx = - iter_variant(variant_cx, &repr, av, *variant, + iter_variant(variant_cx, repr, av, *variant, substs.tps, f); - match adt::trans_case(cx, &repr, variant.disr_val) { + match adt::trans_case(cx, repr, variant.disr_val) { _match::single_result(r) => { AddCase(llswitch, r.val, variant_cx.llbb) } @@ -1863,9 +1864,9 @@ pub fn trans_enum_variant(ccx: @CrateContext, ty::node_id_to_type(ccx.tcx, enum_id)); let repr = adt::represent_type(ccx, enum_ty); - adt::trans_set_discr(bcx, &repr, fcx.llretptr, disr); + adt::trans_set_discr(bcx, repr, fcx.llretptr, disr); for vec::eachi(args) |i, va| { - let lldestptr = adt::trans_GEP(bcx, &repr, fcx.llretptr, disr, i); + let lldestptr = adt::trans_GEP(bcx, repr, fcx.llretptr, disr, i); // If this argument to this function is a enum, it'll have come in to // this function as an opaque blob due to the way that type_of() @@ -1935,7 +1936,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, let repr = adt::represent_type(ccx, tup_ty); for fields.eachi |i, field| { - let lldestptr = adt::trans_GEP(bcx, &repr, fcx.llretptr, 0, i); + let lldestptr = adt::trans_GEP(bcx, repr, fcx.llretptr, 0, i); let llarg = match fcx.llargs.get(&field.node.id) { local_mem(x) => x, _ => { @@ -3050,6 +3051,7 @@ pub fn trans_crate(sess: session::Session, module_data: HashMap(), lltypes: ty::new_ty_hash(), llsizingtypes: ty::new_ty_hash(), + adt_reprs: @mut LinearMap::new(), names: new_namegen(sess.parse_sess.interner), next_addrspace: new_addrspace_gen(), symbol_hasher: symbol_hasher, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 109a4985d3cb6..a363a950f9b24 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -26,6 +26,7 @@ use lib; use metadata::common::LinkMeta; use middle::astencode; use middle::resolve; +use middle::trans::adt; use middle::trans::base; use middle::trans::build; use middle::trans::callee; @@ -44,6 +45,7 @@ use util::ppaux::{expr_repr, ty_to_str}; use core::cast; use core::hash; +use core::hashmap::linear::LinearMap; use core::libc::{c_uint, c_longlong, c_ulonglong}; use core::ptr; use core::str; @@ -203,6 +205,7 @@ pub struct CrateContext { module_data: HashMap<~str, ValueRef>, lltypes: HashMap, llsizingtypes: HashMap, + adt_reprs: @mut LinearMap, names: namegen, next_addrspace: addrspace_gen, symbol_hasher: @hash::State, diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index c42db4a90a18f..cc5236609abdd 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -245,7 +245,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { let (bt, bv) = const_autoderef(cx, bt, bv); do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx, field, field_tys); - adt::const_get_element(cx, &brepr, bv, discr, ix) + adt::const_get_element(cx, brepr, bv, discr, ix) } } @@ -326,7 +326,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { (expr::cast_enum, expr::cast_integral) | (expr::cast_enum, expr::cast_float) => { let repr = adt::represent_type(cx, basety); - let iv = C_int(cx, adt::const_get_discrim(cx, &repr, v)); + let iv = C_int(cx, adt::const_get_discrim(cx, repr, v)); let ety_cast = expr::cast_type_kind(ety); match ety_cast { expr::cast_integral => { @@ -356,12 +356,12 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { ast::expr_tup(es) => { let ety = ty::expr_ty(cx.tcx, e); let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &repr, 0, es.map(|e| const_expr(cx, *e))) + adt::trans_const(cx, repr, 0, es.map(|e| const_expr(cx, *e))) } ast::expr_rec(ref fs, None) => { let ety = ty::expr_ty(cx.tcx, e); let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &repr, 0, + adt::trans_const(cx, repr, 0, fs.map(|f| const_expr(cx, f.node.expr))) } ast::expr_struct(_, ref fs, None) => { @@ -378,7 +378,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { } } }); - adt::trans_const(cx, &repr, discr, cs) + adt::trans_const(cx, repr, discr, cs) } } ast::expr_vec(es, ast::m_imm) => { @@ -442,7 +442,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { let vinfo = ty::enum_variant_with_id(cx.tcx, enum_did, variant_did); - adt::trans_const(cx, &repr, vinfo.disr_val, []) + adt::trans_const(cx, repr, vinfo.disr_val, []) } Some(ast::def_struct(_)) => { let ety = ty::expr_ty(cx.tcx, e); @@ -460,7 +460,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { Some(ast::def_struct(_)) => { let ety = ty::expr_ty(cx.tcx, e); let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &repr, 0, + adt::trans_const(cx, repr, 0, args.map(|a| const_expr(cx, *a))) } Some(ast::def_variant(enum_did, variant_did)) => { @@ -469,7 +469,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { let vinfo = ty::enum_variant_with_id(cx.tcx, enum_did, variant_did); - adt::trans_const(cx, &repr, vinfo.disr_val, + adt::trans_const(cx, repr, vinfo.disr_val, args.map(|a| const_expr(cx, *a))) } _ => cx.sess.span_bug(e.span, ~"expected a struct or \ diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 79fd1dde5411c..7590d009f94fe 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -679,7 +679,7 @@ pub impl Datum { } let repr = adt::represent_type(ccx, self.ty); - assert adt::is_newtypeish(&repr); + assert adt::is_newtypeish(repr); let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]); return match self.mode { ByRef => { @@ -687,7 +687,7 @@ pub impl Datum { // rather than a ptr to the enum type. ( Some(Datum { - val: adt::trans_GEP(bcx, &repr, self.val, + val: adt::trans_GEP(bcx, repr, self.val, 0, 0), ty: ty, mode: ByRef, @@ -719,7 +719,7 @@ pub impl Datum { } let repr = adt::represent_type(ccx, self.ty); - assert adt::is_newtypeish(&repr); + assert adt::is_newtypeish(repr); let ty = fields[0].mt.ty; return match self.mode { ByRef => { @@ -729,7 +729,7 @@ pub impl Datum { // destructors. ( Some(Datum { - val: adt::trans_GEP(bcx, &repr, self.val, + val: adt::trans_GEP(bcx, repr, self.val, 0, 0), ty: ty, mode: ByRef, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 72926f91af52c..3df34e53ae3ef 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -604,7 +604,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_tup(ref args) => { let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr)); - return trans_adt(bcx, &repr, 0, args.mapi(|i, arg| (i, *arg)), + return trans_adt(bcx, repr, 0, args.mapi(|i, arg| (i, *arg)), None, dest); } ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => { @@ -726,7 +726,7 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, // Nullary variant. let ty = expr_ty(bcx, ref_expr); let repr = adt::represent_type(ccx, ty); - adt::trans_set_discr(bcx, &repr, lldest, + adt::trans_set_discr(bcx, repr, lldest, variant_info.disr_val); return bcx; } @@ -891,7 +891,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { datum: do base_datum.get_element(bcx, field_tys[ix].mt.ty, ZeroMem) |srcval| { - adt::trans_GEP(bcx, &repr, srcval, discr, ix) + adt::trans_GEP(bcx, repr, srcval, discr, ix) }, bcx: bcx } @@ -1192,7 +1192,7 @@ fn trans_rec_or_struct(bcx: block, }; let repr = adt::represent_type(bcx.ccx(), ty); - trans_adt(bcx, &repr, discr, numbered_fields, optbase, dest) + trans_adt(bcx, repr, discr, numbered_fields, optbase, dest) } } @@ -1645,7 +1645,7 @@ fn trans_imm_cast(bcx: block, expr: @ast::expr, (cast_enum, cast_float) => { let bcx = bcx; let repr = adt::represent_type(ccx, t_in); - let lldiscrim_a = adt::trans_cast_to_int(bcx, &repr, llexpr); + let lldiscrim_a = adt::trans_cast_to_int(bcx, repr, llexpr); match k_out { cast_integral => int_cast(bcx, ll_t_out, val_ty(lldiscrim_a), diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index f2ad0465e5b5b..44f5e9df58bdb 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -469,7 +469,7 @@ pub fn trans_struct_drop(bcx: block, take_ref: bool) -> block { let repr = adt::represent_type(bcx.ccx(), t); - let drop_flag = adt::trans_drop_flag_ptr(bcx, &repr, v0); + let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0); do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| { let mut bcx = cx; @@ -507,7 +507,7 @@ pub fn trans_struct_drop(bcx: block, ty::struct_mutable_fields(bcx.tcx(), class_did, substs); for vec::eachi(field_tys) |i, fld| { - let llfld_a = adt::trans_GEP(bcx, &repr, v0, 0, i); + let llfld_a = adt::trans_GEP(bcx, repr, v0, 0, i); bcx = drop_ty(bcx, llfld_a, fld.mt.ty); } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 1f14a24b0ae3a..06c183f20e43e 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -147,7 +147,7 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_tup(*) | ty::ty_rec(*) | ty::ty_struct(*) | ty::ty_enum(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::sizing_fields_of(cx, &repr)) + T_struct(adt::sizing_fields_of(cx, repr)) } ty::ty_self | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { @@ -244,7 +244,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_type => T_ptr(cx.tydesc_type), ty::ty_tup(*) | ty::ty_rec(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::fields_of(cx, &repr)) + T_struct(adt::fields_of(cx, repr)) } ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx), ty::ty_struct(did, ref substs) => { @@ -269,7 +269,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { match ty::get(t).sty { ty::ty_enum(*) | ty::ty_struct(*) => { let repr = adt::represent_type(cx, t); - common::set_struct_body(llty, adt::fields_of(cx, &repr)); + common::set_struct_body(llty, adt::fields_of(cx, repr)); } _ => () } From d6acb96c9cb1d0fad0f5171d6417eb048f6f23b4 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 27 Feb 2013 23:08:52 -0800 Subject: [PATCH 32/37] Add lots of comments to adt.rs, and some minor cleanup. --- src/librustc/middle/trans/adt.rs | 182 ++++++++++++++++++++++++++----- 1 file changed, 152 insertions(+), 30 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 00c620c7c8fd8..c080481b92b5a 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -8,10 +8,56 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + * # Representation of Algebraic Data Types + * + * This module determines how to represent enums, structs, tuples, and + * (deprecated) structural records based on their monomorphized types; + * it is responsible both for choosing a representation and + * translating basic operations on values of those types. + * + * Note that the interface treats everything as a general case of an + * enum, so structs/tuples/etc. have one pseudo-variant with + * discriminant 0; i.e., as if they were a univariant enum. + * + * Having everything in one place will enable improvements to data + * structure representation; possibilities include: + * + * - Aligning enum bodies correctly, which in turn makes possible SIMD + * vector types (which are strict-alignment even on x86) and ports + * to strict-alignment architectures (PowerPC, SPARC, etc.). + * + * - User-specified alignment (e.g., cacheline-aligning parts of + * concurrently accessed data structures); LLVM can't represent this + * directly, so we'd have to insert padding fields in any structure + * that might contain one and adjust GEP indices accordingly. See + * issue #4578. + * + * - Rendering `Option<&T>` as a possibly-null `*T` instead of using + * an extra word (and likewise for `@T` and `~T`). Can and probably + * should also apply to any enum with one empty case and one case + * starting with a non-null pointer (e.g., `Result<(), ~str>`). + * + * - Using smaller integer types for discriminants. + * + * - Store nested enums' discriminants in the same word. Rather, if + * some variants start with enums, and those enums representations + * have unused alignment padding between discriminant and body, the + * outer enum's discriminant can be stored there and those variants + * can start at offset 0. Kind of fancy, and might need work to + * make copies of the inner enum type cooperate, but it could help + * with `Option` or `Result` wrapped around another enum. + * + * - Tagged pointers would be neat, but given that any type can be + * used unboxed and any field can have pointers (including mutable) + * taken to it, implementing them for Rust seems difficult. + */ + use core::container::Map; use core::libc::c_ulonglong; use core::option::{Option, Some, None}; use core::vec; + use lib::llvm::{ValueRef, TypeRef, True, False}; use middle::trans::_match; use middle::trans::build::*; @@ -23,31 +69,58 @@ use syntax::ast; use util::ppaux::ty_to_str; -// XXX: should this be done with boxed traits instead of ML-style? +/// Representations. pub enum Repr { + /** + * `Unit` exists only so that an enum with a single C-like variant + * can occupy no space, for ABI compatibility with rustc from + * before (and during) the creation of this module. It may not be + * worth keeping around; `CEnum` and `Univariant` cover it + * overwise. + */ Unit(int), - CEnum(int, int), /* discriminant range */ + /// C-like enums; basically an int. + CEnum(int, int), // discriminant range + /// Single-case variants, and structs/tuples/records. Univariant(Struct, Destructor), + /** + * General-case enums: discriminant as int, followed by fields. + * The fields start immediately after the discriminant, meaning + * that they may not be correctly aligned for the platform's ABI; + * see above. + */ General(~[Struct]) } +/** + * Structs without destructors have historically had an extra layer of + * LLVM-struct to make accessing them work the same as structs with + * destructors. This could probably be flattened to a boolean now + * that this module exists. + */ enum Destructor { - DtorPresent, - DtorAbsent, - NoDtor + StructWithDtor, + StructWithoutDtor, + NonStruct } +/// For structs, and struct-like parts of anything fancier. struct Struct { size: u64, align: u64, fields: ~[ty::t] } - +/** + * Convenience for `represent_type`. There should probably be more or + * these, for places in trans where the `ty::t` isn't directly + * available. + */ pub fn represent_node(bcx: block, node: ast::node_id) -> @Repr { represent_type(bcx.ccx(), node_id_type(bcx, node)) } +/// Decides how to represent a given type. pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { debug!("Representing: %s", ty_to_str(cx.tcx, t)); match cx.adt_reprs.find(&t) { @@ -56,18 +129,19 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { } let repr = @match ty::get(t).sty { ty::ty_tup(ref elems) => { - Univariant(mk_struct(cx, *elems), NoDtor) + Univariant(mk_struct(cx, *elems), NonStruct) } ty::ty_rec(ref fields) => { // XXX: Are these in the right order? - Univariant(mk_struct(cx, fields.map(|f| f.mt.ty)), DtorAbsent) + Univariant(mk_struct(cx, fields.map(|f| f.mt.ty)), + StructWithoutDtor) } ty::ty_struct(def_id, ref substs) => { let fields = ty::lookup_struct_fields(cx.tcx, def_id); let dt = ty::ty_dtor(cx.tcx, def_id).is_present(); Univariant(mk_struct(cx, fields.map(|field| { ty::lookup_field_type(cx.tcx, def_id, field.id, substs) - })), if dt { DtorPresent } else { DtorAbsent }) + })), if dt { StructWithDtor } else { StructWithoutDtor }) } ty::ty_enum(def_id, ref substs) => { struct Case { discr: int, tys: ~[ty::t] }; @@ -80,17 +154,22 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { }; if cases.len() == 0 { // Uninhabitable; represent as unit - Univariant(mk_struct(cx, ~[]), NoDtor) + Unit(0) } else if cases.len() == 1 && cases[0].tys.len() == 0 { + // `()`-like; see comment on definition of `Unit`. Unit(cases[0].discr) } else if cases.len() == 1 { - // struct, tuple, newtype, etc. + // Equivalent to a struct/tuple/newtype. assert cases[0].discr == 0; - Univariant(mk_struct(cx, cases[0].tys), NoDtor) + Univariant(mk_struct(cx, cases[0].tys), NonStruct) } else if cases.all(|c| c.tys.len() == 0) { + // All bodies empty -> intlike let discrs = cases.map(|c| c.discr); CEnum(discrs.min(), discrs.max()) } else { + // The general case. Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. if !cases.alli(|i,c| c.discr == (i as int)) { cx.sess.bug(fmt!("non-C-like enum %s with specified \ discriminants", @@ -115,13 +194,18 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct { } } - -pub fn sizing_fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { - generic_fields_of(cx, r, true) -} +/** + * Returns the fields of a struct for the given representation. + * All nominal types are LLVM structs, in order to be able to use + * forward-declared opaque types to prevent circularity in `type_of`. + */ pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { generic_fields_of(cx, r, false) } +/// Like `fields_of`, but for `type_of::sizing_type_of` (q.v.). +pub fn sizing_fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] { + generic_fields_of(cx, r, true) +} fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) -> ~[TypeRef] { match *r { @@ -134,9 +218,9 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) st.fields.map(|&ty| type_of::type_of(cx, ty)) }; match dt { - NoDtor => f, - DtorAbsent => ~[T_struct(f)], - DtorPresent => ~[T_struct(f), T_i8()] + NonStruct => f, + StructWithoutDtor => ~[T_struct(f)], + StructWithDtor => ~[T_struct(f), T_i8()] } } General(ref sts) => { @@ -164,6 +248,10 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) } } +/** + * Obtain as much of a "discriminant" as this representation has. + * This should ideally be less tightly tied to `_match`. + */ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> (_match::branch_kind, Option) { match *r { @@ -176,6 +264,10 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) } } +/** + * If the representation is potentially of a C-like enum, implement + * coercion to numeric types. + */ pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef) -> ValueRef { match *r { @@ -183,11 +275,18 @@ pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef) CEnum(min, max) => load_discr(bcx, scrutinee, min, max), Univariant(*) => bcx.ccx().sess.bug(~"type has no explicit \ discriminant"), + // Note: this case is used internally by trans_switch, + // even though it shouldn't be reached by an external caller. General(ref cases) => load_discr(bcx, scrutinee, 0, (cases.len() - 1) as int) } } +/** + * Yield information about how to dispatch a case of the + * discriminant-like value returned by `trans_switch`. + * This should ideally be less tightly tied to `_match`. + */ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { match *r { CEnum(*) => { @@ -202,6 +301,11 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { } } +/** + * Begin initializing a new value of the given case of the given + * representation. The fields should then be initialized with + * `trans_GEP` and stores. + */ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { match *r { Unit(the_discr) => { @@ -211,7 +315,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { assert min <= discr && discr <= max; Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) } - Univariant(_, DtorPresent) => { + Univariant(_, StructWithDtor) => { assert discr == 0; Store(bcx, C_u8(1), GEPi(bcx, val, [0, 1])) } @@ -224,6 +328,10 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { } } +/** + * The number of fields in a given case; for use when obtaining this + * information from the type or definition is less convenient. + */ pub fn num_args(r: &Repr, discr: int) -> uint { match *r { Unit(*) | CEnum(*) => 0, @@ -232,11 +340,12 @@ pub fn num_args(r: &Repr, discr: int) -> uint { } } +/// Access a field, at a point when the value's case is known. pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) -> ValueRef { // Note: if this ever needs to generate conditionals (e.g., if we // decide to do some kind of cdr-coding-like non-unique repr - // someday), it'll need to return a possibly-new bcx as well. + // someday), it will need to return a possibly-new bcx as well. match *r { Unit(*) | CEnum(*) => { bcx.ccx().sess.bug(~"element access in C-like enum") @@ -244,8 +353,8 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) Univariant(ref st, dt) => { assert discr == 0; let val = match dt { - NoDtor => val, - DtorPresent | DtorAbsent => GEPi(bcx, val, [0, 0]) + NonStruct => val, + StructWithDtor | StructWithoutDtor => GEPi(bcx, val, [0, 0]) }; struct_GEP(bcx, st, val, ix, false) } @@ -271,14 +380,26 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, GEPi(bcx, val, [0, ix]) } +/// Access the struct drop flag, if present. pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef { match *r { - Univariant(_, DtorPresent) => GEPi(bcx, val, [0, 1]), + Univariant(_, StructWithDtor) => GEPi(bcx, val, [0, 1]), _ => bcx.ccx().sess.bug(~"tried to get drop flag of non-droppable \ type") } } +/** + * Construct a constant value, suitable for initializing a + * GlobalVariable, given a case and constant values for its fields. + * Note that this may have a different LLVM type (and different + * alignment!) from the representation's `type_of`, so it needs a + * pointer cast before use. + * + * Currently it has the same size as the type, but this may be changed + * in the future to avoid allocating unnecessary space after values of + * shorter-than-maximum cases. + */ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, vals: &[ValueRef]) -> ValueRef { match *r { @@ -294,10 +415,10 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, assert discr == 0; let s = C_struct(build_const_struct(ccx, st, vals)); match dt { - NoDtor => s, + NonStruct => s, // The actual destructor flag doesn't need to be present. // But add an extra struct layer for compatibility. - DtorPresent | DtorAbsent => C_struct(~[s]) + StructWithDtor | StructWithoutDtor => C_struct(~[s]) } } General(ref cases) => { @@ -345,7 +466,7 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef]) #[always_inline] fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } - +/// Get the discriminant of a constant value. (Not currently used.) pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef) -> int { match *r { @@ -356,13 +477,14 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef) } } +/// Access a field of a constant value. pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, _discr: int, ix: uint) -> ValueRef { // Not to be confused with common::const_get_elt. match *r { Unit(*) | CEnum(*) => ccx.sess.bug(~"element access in C-like enum \ const"), - Univariant(_, NoDtor) => const_struct_field(ccx, val, ix), + Univariant(_, NonStruct) => const_struct_field(ccx, val, ix), Univariant(*) => const_struct_field(ccx, const_get_elt(ccx, val, [0]), ix), General(*) => const_struct_field(ccx, const_get_elt(ccx, val, @@ -395,8 +517,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint) /// Is it safe to bitcast a value to the one field of its one variant? pub fn is_newtypeish(r: &Repr) -> bool { match *r { - Univariant(ref st, DtorAbsent) - | Univariant(ref st, NoDtor) => st.fields.len() == 1, + Univariant(ref st, StructWithoutDtor) + | Univariant(ref st, NonStruct) => st.fields.len() == 1, _ => false } } From 8dca7be1dfac6193832575495e3f6483634189f1 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Thu, 28 Feb 2013 11:24:30 -0800 Subject: [PATCH 33/37] A little more cosmetic cleanup --- src/librustc/middle/trans/adt.rs | 51 ++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index c080481b92b5a..6b347287ae42c 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -230,24 +230,6 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) } } -fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) - -> ValueRef { - let ptr = GEPi(bcx, scrutinee, [0, 0]); - if max + 1 == min { - // i.e., if the range is everything. The lo==hi case would be - // rejected by the LLVM verifier (it would mean either an - // empty set, which is impossible, or the entire range of the - // type, which is pointless). - Load(bcx, ptr) - } else { - // llvm::ConstantRange can deal with ranges that wrap around, - // so an overflow on (max + 1) is fine. - LoadRangeAssert(bcx, ptr, min as c_ulonglong, - (max + 1) as c_ulonglong, - /* signed: */ True) - } -} - /** * Obtain as much of a "discriminant" as this representation has. * This should ideally be less tightly tied to `_match`. @@ -282,6 +264,24 @@ pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef) } } +fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) + -> ValueRef { + let ptr = GEPi(bcx, scrutinee, [0, 0]); + if max + 1 == min { + // i.e., if the range is everything. The lo==hi case would be + // rejected by the LLVM verifier (it would mean either an + // empty set, which is impossible, or the entire range of the + // type, which is pointless). + Load(bcx, ptr) + } else { + // llvm::ConstantRange can deal with ranges that wrap around, + // so an overflow on (max + 1) is fine. + LoadRangeAssert(bcx, ptr, min as c_ulonglong, + (max + 1) as c_ulonglong, + /* signed: */ True) + } +} + /** * Yield information about how to dispatch a case of the * discriminant-like value returned by `trans_switch`. @@ -433,10 +433,10 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, } } -fn padding(size: u64) -> ValueRef { - C_undef(T_array(T_i8(), size /*bad*/as uint)) -} - +/** + * Building structs is a little complicated, because we might need to + * insert padding if a field's value is less aligned than its type. + */ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef]) -> ~[ValueRef] { assert vals.len() == st.fields.len(); @@ -457,12 +457,18 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef]) } assert !is_undef(vals[i]); // If that assert fails, could change it to wrap in a struct? + // (See `const_struct_field` for why real fields must not be undef.) cfields.push(vals[i]); } return cfields; } +fn padding(size: u64) -> ValueRef { + C_undef(T_array(T_i8(), size /*bad*/as uint)) +} + +// XXX this utility routine should be somewhere more general #[always_inline] fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } @@ -492,6 +498,7 @@ pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, } } +/// Extract field of struct-like const, skipping our alignment padding. fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint) -> ValueRef { // Get the ix-th non-undef element of the struct. From 6840b48074ddb97d3a77f87c833fa8b9f10c1ccc Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Thu, 28 Feb 2013 12:13:00 -0800 Subject: [PATCH 34/37] trans_cast_to_int is hard to explain; make it trans_get_discr instead. --- src/librustc/middle/trans/adt.rs | 20 +++++++++----------- src/librustc/middle/trans/expr.rs | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 6b347287ae42c..98f152904704d 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -231,14 +231,16 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool) } /** - * Obtain as much of a "discriminant" as this representation has. + * Obtain a representation of the discriminant sufficient to translate + * destructuring; this may or may not involve the actual discriminant. + * * This should ideally be less tightly tied to `_match`. */ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) -> (_match::branch_kind, Option) { match *r { CEnum(*) | General(*) => { - (_match::switch, Some(trans_cast_to_int(bcx, r, scrutinee))) + (_match::switch, Some(trans_get_discr(bcx, r, scrutinee))) } Unit(*) | Univariant(*) => { (_match::single, None) @@ -246,24 +248,19 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef) } } -/** - * If the representation is potentially of a C-like enum, implement - * coercion to numeric types. - */ -pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef) +/// Obtain the actual discriminant of a value. +pub fn trans_get_discr(bcx: block, r: &Repr, scrutinee: ValueRef) -> ValueRef { match *r { Unit(the_disc) => C_int(bcx.ccx(), the_disc), CEnum(min, max) => load_discr(bcx, scrutinee, min, max), - Univariant(*) => bcx.ccx().sess.bug(~"type has no explicit \ - discriminant"), - // Note: this case is used internally by trans_switch, - // even though it shouldn't be reached by an external caller. + Univariant(*) => C_int(bcx.ccx(), 0), General(ref cases) => load_discr(bcx, scrutinee, 0, (cases.len() - 1) as int) } } +/// Helper for cases where the discriminant is simply loaded. fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) -> ValueRef { let ptr = GEPi(bcx, scrutinee, [0, 0]); @@ -285,6 +282,7 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int) /** * Yield information about how to dispatch a case of the * discriminant-like value returned by `trans_switch`. + * * This should ideally be less tightly tied to `_match`. */ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 3df34e53ae3ef..edda2f6c2c15c 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1645,7 +1645,7 @@ fn trans_imm_cast(bcx: block, expr: @ast::expr, (cast_enum, cast_float) => { let bcx = bcx; let repr = adt::represent_type(ccx, t_in); - let lldiscrim_a = adt::trans_cast_to_int(bcx, repr, llexpr); + let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr); match k_out { cast_integral => int_cast(bcx, ll_t_out, val_ty(lldiscrim_a), From e13111fc5ab9a968d5668712bb75bc49350a7f25 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 2 Mar 2013 14:03:41 -0800 Subject: [PATCH 35/37] Even more comments for ADT-related interfaces --- src/librustc/middle/trans/adt.rs | 26 +++++++++++++++++++++++--- src/librustc/middle/trans/expr.rs | 26 +++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 98f152904704d..e61925395f2a7 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -394,9 +394,20 @@ pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef { * alignment!) from the representation's `type_of`, so it needs a * pointer cast before use. * - * Currently it has the same size as the type, but this may be changed - * in the future to avoid allocating unnecessary space after values of - * shorter-than-maximum cases. + * The LLVM type system does not directly support unions, and only + * pointers can be bitcast, so a constant (and, by extension, the + * GlobalVariable initialized by it) will have a type that can vary + * depending on which case of an enum it is. + * + * To understand the alignment situation, consider `enum E { V64(u64), + * V32(u32, u32) }` on win32. The type should have 8-byte alignment + * to accommodate the u64 (currently it doesn't; this is a known bug), + * but `V32(x, y)` would have LLVM type `{i32, i32, i32}`, which is + * 4-byte aligned. + * + * Currently the returned value has the same size as the type, but + * this may be changed in the future to avoid allocating unnecessary + * space after values of shorter-than-maximum cases. */ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, vals: &[ValueRef]) -> ValueRef { @@ -424,6 +435,9 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, let max_sz = cases.map(|s| s.size).max(); let body = build_const_struct(ccx, case, vals); + // The unary packed struct has alignment 1 regardless of + // its contents, so it will always be located at the + // expected offset at runtime. C_struct([C_int(ccx, discr), C_packed_struct([C_struct(body)]), padding(max_sz - case.size)]) @@ -434,6 +448,12 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int, /** * Building structs is a little complicated, because we might need to * insert padding if a field's value is less aligned than its type. + * + * Continuing the example from `trans_const`, a value of type `(u32, + * E)` should have the `E` at offset 8, but if that field's + * initializer is 4-byte aligned then simply translating the tuple as + * a two-element struct will locate it at offset 4, and accesses to it + * will read the wrong memory. */ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef]) -> ~[ValueRef] { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index edda2f6c2c15c..699f73e7d777d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1158,9 +1158,9 @@ fn trans_rec_or_struct(bcx: block, let mut need_base = vec::from_elem(field_tys.len(), true); let numbered_fields = do fields.map |field| { - match do vec::position(field_tys) |field_ty| { - field_ty.ident == field.node.ident - } { + let opt_pos = vec::position(field_tys, |field_ty| + field_ty.ident == field.node.ident); + match opt_pos { Some(i) => { need_base[i] = false; (i, field.node.expr) @@ -1196,11 +1196,31 @@ fn trans_rec_or_struct(bcx: block, } } +/** + * Information that `trans_adt` needs in order to fill in the fields + * of a struct copied from a base struct (e.g., from an expression + * like `Foo { a: b, ..base }`. + * + * Note that `fields` may be empty; the base expression must always be + * evaluated for side-effects. + */ struct StructBaseInfo { + /// The base expression; will be evaluated after all explicit fields. expr: @ast::expr, + /// The indices of fields to copy paired with their types. fields: ~[(uint, ty::t)] } +/** + * Constructs an ADT instance: + * + * - `fields` should be a list of field indices paired with the + * expression to store into that field. The initializers will be + * evaluated in the order specified by `fields`. + * + * - `optbase` contains information on the base struct (if any) from + * which remaining fields are copied; see comments on `StructBaseInfo`. + */ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, fields: &[(uint, @ast::expr)], optbase: Option, From 1f9bc64bae3ddb282c2e82be2b5c0d2a403267cd Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Sat, 2 Mar 2013 16:08:49 -0800 Subject: [PATCH 36/37] adt.rs renaming: "field" rather than "element"; set_discr -> start_init. This way "field" refers to the abstraction and "element" (as in get_elt, "get element pointer", etc.) refers to the low-level LLVM operations. --- src/librustc/middle/trans/_match.rs | 14 ++++++------- src/librustc/middle/trans/adt.rs | 31 +++++++++++++++++------------ src/librustc/middle/trans/base.rs | 14 +++++++------ src/librustc/middle/trans/consts.rs | 2 +- src/librustc/middle/trans/datum.rs | 4 ++-- src/librustc/middle/trans/expr.rs | 14 ++++++------- src/librustc/middle/trans/glue.rs | 2 +- 7 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 96afc83904d44..3de1c35b65e9f 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -838,7 +838,7 @@ pub fn extract_variant_args(bcx: block, -> ExtractedBlock { let _icx = bcx.insn_ctxt("match::extract_variant_args"); let args = do vec::from_fn(adt::num_args(repr, disr_val)) |i| { - adt::trans_GEP(bcx, repr, val, disr_val, i) + adt::trans_field_ptr(bcx, repr, val, disr_val, i) }; ExtractedBlock { vals: args, bcx: bcx } @@ -1274,7 +1274,7 @@ pub fn compile_submatch(bcx: block, do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { let rec_vals = rec_fields.map(|field_name| { let ix = ty::field_idx_strict(tcx, *field_name, field_tys); - adt::trans_GEP(bcx, pat_repr, val, discr, ix) + adt::trans_field_ptr(bcx, pat_repr, val, discr, ix) }); compile_submatch( bcx, @@ -1293,7 +1293,7 @@ pub fn compile_submatch(bcx: block, _ => ccx.sess.bug(~"non-tuple type in tuple pattern") }; let tup_vals = do vec::from_fn(n_tup_elts) |i| { - adt::trans_GEP(bcx, tup_repr, val, 0, i) + adt::trans_field_ptr(bcx, tup_repr, val, 0, i) }; compile_submatch(bcx, enter_tup(bcx, dm, m, col, val, n_tup_elts), vec::append(tup_vals, vals_left), chk); @@ -1315,7 +1315,7 @@ pub fn compile_submatch(bcx: block, let struct_repr = adt::represent_type(bcx.ccx(), struct_ty); let llstructvals = do vec::from_fn(struct_element_count) |i| { - adt::trans_GEP(bcx, struct_repr, val, 0, i) + adt::trans_field_ptr(bcx, struct_repr, val, 0, i) }; compile_submatch(bcx, enter_tuple_struct(bcx, dm, m, col, val, @@ -1753,7 +1753,7 @@ pub fn bind_irrefutable_pat(bcx: block, // This is the tuple struct case. let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = adt::trans_GEP(bcx, repr, + let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, @@ -1776,7 +1776,7 @@ pub fn bind_irrefutable_pat(bcx: block, do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { for vec::each(fields) |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); - let fldptr = adt::trans_GEP(bcx, pat_repr, val, + let fldptr = adt::trans_field_ptr(bcx, pat_repr, val, discr, ix); bcx = bind_irrefutable_pat(bcx, f.pat, @@ -1789,7 +1789,7 @@ pub fn bind_irrefutable_pat(bcx: block, ast::pat_tup(elems) => { let repr = adt::represent_node(bcx, pat.id); for vec::eachi(elems) |i, elem| { - let fldptr = adt::trans_GEP(bcx, repr, val, 0, i); + let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, fldptr, diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index e61925395f2a7..3d3b40e4ff262 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -301,10 +301,10 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result { /** * Begin initializing a new value of the given case of the given - * representation. The fields should then be initialized with - * `trans_GEP` and stores. + * representation. The fields, if any, should then be initialized via + * `trans_field_ptr`. */ -pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) { +pub fn trans_start_init(bcx: block, r: &Repr, val: ValueRef, discr: int) { match *r { Unit(the_discr) => { assert discr == the_discr; @@ -339,8 +339,8 @@ pub fn num_args(r: &Repr, discr: int) -> uint { } /// Access a field, at a point when the value's case is known. -pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) - -> ValueRef { +pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int, + ix: uint) -> ValueRef { // Note: if this ever needs to generate conditionals (e.g., if we // decide to do some kind of cdr-coding-like non-unique repr // someday), it will need to return a possibly-new bcx as well. @@ -354,16 +354,16 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint) NonStruct => val, StructWithDtor | StructWithoutDtor => GEPi(bcx, val, [0, 0]) }; - struct_GEP(bcx, st, val, ix, false) + struct_field_ptr(bcx, st, val, ix, false) } General(ref cases) => { - struct_GEP(bcx, &cases[discr as uint], - GEPi(bcx, val, [0, 1]), ix, true) + struct_field_ptr(bcx, &cases[discr as uint], + GEPi(bcx, val, [0, 1]), ix, true) } } } -fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint, +fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint, needs_cast: bool) -> ValueRef { let ccx = bcx.ccx(); @@ -501,10 +501,15 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef) } } -/// Access a field of a constant value. -pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef, - _discr: int, ix: uint) -> ValueRef { - // Not to be confused with common::const_get_elt. +/** + * Extract a field of a constant value, as appropriate for its + * representation. + * + * (Not to be confused with `common::const_get_elt`, which operates on + * raw LLVM-level structs and arrays.) + */ +pub fn const_get_field(ccx: @CrateContext, r: &Repr, val: ValueRef, + _discr: int, ix: uint) -> ValueRef { match *r { Unit(*) | CEnum(*) => ccx.sess.bug(~"element access in C-like enum \ const"), diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ae1441731e0f3..8280243455d9b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -630,7 +630,8 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let mut cx = cx; for variant.args.eachi |i, &arg| { - cx = f(cx, adt::trans_GEP(cx, repr, av, variant.disr_val, i), + cx = f(cx, + adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), ty::subst_tps(tcx, tps, None, arg)); } return cx; @@ -642,7 +643,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let repr = adt::represent_type(cx.ccx(), t); do expr::with_field_tys(cx.tcx(), t, None) |discr, field_tys| { for vec::eachi(field_tys) |i, field_ty| { - let llfld_a = adt::trans_GEP(cx, repr, av, discr, i); + let llfld_a = adt::trans_field_ptr(cx, repr, av, discr, i); cx = f(cx, llfld_a, field_ty.mt.ty); } } @@ -655,7 +656,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, ty::ty_tup(args) => { let repr = adt::represent_type(cx.ccx(), t); for vec::eachi(args) |i, arg| { - let llfld_a = adt::trans_GEP(cx, repr, av, 0, i); + let llfld_a = adt::trans_field_ptr(cx, repr, av, 0, i); cx = f(cx, llfld_a, *arg); } } @@ -1864,9 +1865,10 @@ pub fn trans_enum_variant(ccx: @CrateContext, ty::node_id_to_type(ccx.tcx, enum_id)); let repr = adt::represent_type(ccx, enum_ty); - adt::trans_set_discr(bcx, repr, fcx.llretptr, disr); + adt::trans_start_init(bcx, repr, fcx.llretptr, disr); for vec::eachi(args) |i, va| { - let lldestptr = adt::trans_GEP(bcx, repr, fcx.llretptr, disr, i); + let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr, + disr, i); // If this argument to this function is a enum, it'll have come in to // this function as an opaque blob due to the way that type_of() @@ -1936,7 +1938,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, let repr = adt::represent_type(ccx, tup_ty); for fields.eachi |i, field| { - let lldestptr = adt::trans_GEP(bcx, repr, fcx.llretptr, 0, i); + let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr, 0, i); let llarg = match fcx.llargs.get(&field.node.id) { local_mem(x) => x, _ => { diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index cc5236609abdd..d19ffe8cb211f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -245,7 +245,7 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { let (bt, bv) = const_autoderef(cx, bt, bv); do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx, field, field_tys); - adt::const_get_element(cx, brepr, bv, discr, ix) + adt::const_get_field(cx, brepr, bv, discr, ix) } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 7590d009f94fe..e608991456417 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -687,7 +687,7 @@ pub impl Datum { // rather than a ptr to the enum type. ( Some(Datum { - val: adt::trans_GEP(bcx, repr, self.val, + val: adt::trans_field_ptr(bcx, repr, self.val, 0, 0), ty: ty, mode: ByRef, @@ -729,7 +729,7 @@ pub impl Datum { // destructors. ( Some(Datum { - val: adt::trans_GEP(bcx, repr, self.val, + val: adt::trans_field_ptr(bcx, repr, self.val, 0, 0), ty: ty, mode: ByRef, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 699f73e7d777d..1dae9fccc6211 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -726,8 +726,8 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, // Nullary variant. let ty = expr_ty(bcx, ref_expr); let repr = adt::represent_type(ccx, ty); - adt::trans_set_discr(bcx, repr, lldest, - variant_info.disr_val); + adt::trans_start_init(bcx, repr, lldest, + variant_info.disr_val); return bcx; } } @@ -891,7 +891,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { datum: do base_datum.get_element(bcx, field_tys[ix].mt.ty, ZeroMem) |srcval| { - adt::trans_GEP(bcx, repr, srcval, discr, ix) + adt::trans_field_ptr(bcx, repr, srcval, discr, ix) }, bcx: bcx } @@ -1240,9 +1240,9 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, SaveIn(pos) => pos }; let mut temp_cleanups = ~[]; - adt::trans_set_discr(bcx, repr, addr, discr); + adt::trans_start_init(bcx, repr, addr, discr); for fields.each |&(i, e)| { - let dest = adt::trans_GEP(bcx, repr, addr, discr, i); + let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); let e_ty = expr_ty(bcx, e); bcx = trans_into(bcx, e, SaveIn(dest)); add_clean_temp_mem(bcx, dest, e_ty); @@ -1254,9 +1254,9 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr)); for base.fields.each |&(i, t)| { let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| { - adt::trans_GEP(bcx, repr, srcval, discr, i) + adt::trans_field_ptr(bcx, repr, srcval, discr, i) }; - let dest = adt::trans_GEP(bcx, repr, addr, discr, i); + let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); bcx = datum.store_to(bcx, base.expr.id, INIT, dest); } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 44f5e9df58bdb..b692ae67950ec 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -507,7 +507,7 @@ pub fn trans_struct_drop(bcx: block, ty::struct_mutable_fields(bcx.tcx(), class_did, substs); for vec::eachi(field_tys) |i, fld| { - let llfld_a = adt::trans_GEP(bcx, repr, v0, 0, i); + let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i); bcx = drop_ty(bcx, llfld_a, fld.mt.ty); } From a69ec175f8ebddf210f846abdbb7e8a441790f0a Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 5 Mar 2013 11:54:33 -0800 Subject: [PATCH 37/37] GC now-unused imports --- src/librustc/middle/trans/_match.rs | 3 --- src/librustc/middle/trans/type_of.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 3de1c35b65e9f..5bfa314e39769 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -145,7 +145,6 @@ use core::prelude::*; use back::abi; -use lib; use lib::llvm::{llvm, ValueRef, BasicBlockRef}; use middle::const_eval; use middle::borrowck::root_map_key; @@ -170,9 +169,7 @@ use util::common::indenter; use core::dvec::DVec; use core::dvec; -use core::libc::c_ulonglong; use std::oldmap::HashMap; -use syntax::ast::def_id; use syntax::ast; use syntax::ast::ident; use syntax::ast_util::path_to_ident; diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 06c183f20e43e..8dac607bd5287 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -15,12 +15,10 @@ use middle::trans::adt; use middle::trans::base; use middle::trans::common::*; use middle::trans::common; -use middle::trans::machine; use middle::ty; use util::ppaux; use core::option::None; -use core::vec; use syntax::ast; pub fn type_of_explicit_arg(ccx: @CrateContext, arg: ty::arg) -> TypeRef {