(index<- )        ./librustc/middle/trans/expr.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
    1  // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
    2  // file at the top-level directory of this distribution and at
    3  // http://rust-lang.org/COPYRIGHT.
    4  //
    5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    8  // option. This file may not be copied, modified, or distributed
    9  // except according to those terms.
   10  
   11  /*!
   12   * # Translation of Expressions
   13   *
   14   * Public entry points:
   15   *
   16   * - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
   17   *   storing the result into `dest`. This is the preferred form, if you
   18   *   can manage it.
   19   *
   20   * - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
   21   *   `Datum` with the result. You can then store the datum, inspect
   22   *   the value, etc. This may introduce temporaries if the datum is a
   23   *   structural type.
   24   *
   25   * - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
   26   *   expression and ensures that the result has a cleanup associated with it,
   27   *   creating a temporary stack slot if necessary.
   28   *
   29   * - `trans_local_var -> Datum`: looks up a local variable or upvar.
   30   *
   31   * See doc.rs for more comments.
   32   */
   33  
   34  #![allow(non_camel_case_types)]
   35  
   36  use back::abi;
   37  use lib::llvm::{ValueRef, llvm};
   38  use lib;
   39  use metadata::csearch;
   40  use middle::lang_items::MallocFnLangItem;
   41  use middle::trans::_match;
   42  use middle::trans::adt;
   43  use middle::trans::asm;
   44  use middle::trans::base::*;
   45  use middle::trans::base;
   46  use middle::trans::build::*;
   47  use middle::trans::callee;
   48  use middle::trans::cleanup;
   49  use middle::trans::cleanup::CleanupMethods;
   50  use middle::trans::closure;
   51  use middle::trans::common::*;
   52  use middle::trans::consts;
   53  use middle::trans::controlflow;
   54  use middle::trans::datum::*;
   55  use middle::trans::debuginfo;
   56  use middle::trans::glue;
   57  use middle::trans::machine;
   58  use middle::trans::meth;
   59  use middle::trans::inline;
   60  use middle::trans::tvec;
   61  use middle::trans::type_of;
   62  use middle::ty::struct_fields;
   63  use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
   64  use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
   65  use middle::ty;
   66  use middle::typeck::MethodCall;
   67  use util::common::indenter;
   68  use util::ppaux::Repr;
   69  use util::nodemap::NodeMap;
   70  use middle::trans::machine::{llsize_of, llsize_of_alloc};
   71  use middle::trans::type_::Type;
   72  
   73  use syntax::ast;
   74  use syntax::codemap;
   75  use syntax::print::pprust::{expr_to_str};
   76  
   77  // Destinations
   78  
   79  // These are passed around by the code generating functions to track the
   80  // destination of a computation's value.
   81  
   82  #[deriving(Eq)]
   83  pub enum Dest {
   84      SaveIn(ValueRef),
   85      Ignore,
   86  }
   87  
   88  impl Dest {
   89      pub fn to_str(&self, ccx&CrateContext) -> ~str {
   90          match *self {
   91              SaveIn(v) => format!("SaveIn({})", ccx.tn.val_to_str(v)),
   92              Ignore => "Ignore".to_owned()
   93          }
   94      }
   95  }
   96  
   97  pub fn trans_into<'a>(bcx: &'a Block<'a>,
   98                        expr: &ast::Expr,
   99                        destDest)
  100                        -> &'a Block<'a> {
  101      /*!
  102       * This function is equivalent to `trans(bcx, expr).store_to_dest(dest)`
  103       * but it may generate better optimized LLVM code.
  104       */
  105  
  106      let mut bcx = bcx;
  107  
  108      if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
  109          // use trans, which may be less efficient but
  110          // which will perform the adjustments:
  111          let datum = unpack_datum!(bcx, trans(bcx, expr));
  112          return datum.store_to_dest(bcx, dest, expr.id)
  113      }
  114  
  115      debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
  116      debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
  117  
  118      bcx.fcx.push_ast_cleanup_scope(expr.id);
  119  
  120      let kind = ty::expr_kind(bcx.tcx(), expr);
  121      bcx = match kind {
  122          ty::LvalueExpr | ty::RvalueDatumExpr => {
  123              trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
  124          }
  125          ty::RvalueDpsExpr => {
  126              trans_rvalue_dps_unadjusted(bcx, expr, dest)
  127          }
  128          ty::RvalueStmtExpr => {
  129              trans_rvalue_stmt_unadjusted(bcx, expr)
  130          }
  131      };
  132  
  133      bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
  134  }
  135  
  136  pub fn trans<'a>(bcx: &'a Block<'a>,
  137                   expr: &ast::Expr)
  138                   -> DatumBlock<'a, Expr> {
  139      /*!
  140       * Translates an expression, returning a datum (and new block)
  141       * encapsulating the result. When possible, it is preferred to
  142       * use `trans_into`, as that may avoid creating a temporary on
  143       * the stack.
  144       */
  145  
  146      debug!("trans(expr={})", bcx.expr_to_str(expr));
  147  
  148      let mut bcx = bcx;
  149      let fcx = bcx.fcx;
  150  
  151      fcx.push_ast_cleanup_scope(expr.id);
  152      let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
  153      let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
  154      bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
  155      return DatumBlock(bcx, datum);
  156  }
  157  
  158  fn apply_adjustments<'a>(bcx: &'a Block<'a>,
  159                           expr: &ast::Expr,
  160                           datumDatum<Expr>)
  161                           -> DatumBlock<'a, Expr> {
  162      /*!
  163       * Helper for trans that apply adjustments from `expr` to `datum`,
  164       * which should be the unadjusted translation of `expr`.
  165       */
  166  
  167      let mut bcx = bcx;
  168      let mut datum = datum;
  169      let adjustment = match bcx.tcx().adjustments.borrow().find_copy(&expr.id) {
  170          None => {
  171              return DatumBlock(bcx, datum);
  172          }
  173          Some(adj) => { adj }
  174      };
  175      debug!("unadjusted datum for expr {}{}",
  176             expr.id, datum.to_str(bcx.ccx()));
  177      match adjustment {
  178          AutoAddEnv(..) => {
  179              datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
  180          }
  181          AutoDerefRef(ref adj) => {
  182              if adj.autoderefs > 0 {
  183                  datum = unpack_datum!(
  184                      bcx, deref_multiple(bcx, expr, datum, adj.autoderefs));
  185              }
  186  
  187              datum = match adj.autoref {
  188                  None => {
  189                      datum
  190                  }
  191                  Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
  192                  Some(AutoPtr(..)) => {
  193                      unpack_datum!(bcx, auto_ref(bcx, datum, expr))
  194                  }
  195                  Some(AutoBorrowVec(..)) => {
  196                      unpack_datum!(bcx, auto_slice(bcx, expr, datum))
  197                  }
  198                  Some(AutoBorrowVecRef(..)) => {
  199                      unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
  200                  }
  201                  Some(AutoBorrowObj(..)) => {
  202                      unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum))
  203                  }
  204              };
  205          }
  206          AutoObject(..) => {
  207              let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
  208              let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
  209              bcx = meth::trans_trait_cast(
  210                  bcx, datum, expr.id, SaveIn(scratch.val));
  211              datum = scratch.to_expr_datum();
  212          }
  213      }
  214      debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
  215      return DatumBlock {bcx: bcx, datum: datum};
  216  
  217      fn auto_slice<'a>(
  218                    bcx&'a Block<'a>,
  219                    expr&ast::Expr,
  220                    datumDatum<Expr>)
  221                    -> DatumBlock<'a, Expr> {
  222          // This is not the most efficient thing possible; since slices
  223          // are two words it'd be better if this were compiled in
  224          // 'dest' mode, but I can't find a nice way to structure the
  225          // code and keep it DRY that accommodates that use case at the
  226          // moment.
  227  
  228          let mut bcx = bcx;
  229          let tcx = bcx.tcx();
  230          let unit_ty = ty::sequence_element_type(tcx, datum.ty);
  231  
  232          // Arrange cleanup, if not already done. This is needed in
  233          // case we are auto-slicing an owned vector or some such.
  234          let datum = unpack_datum!(
  235              bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id));
  236  
  237          let (base, len) = datum.get_vec_base_and_len(bcx);
  238  
  239          // this type may have a different region/mutability than the
  240          // real one, but it will have the same runtime representation
  241          let slice_ty = ty::mk_slice(tcx, ty::ReStatic,
  242                                      ty::mt { ty: unit_ty, mutbl: ast::MutImmutable });
  243  
  244          let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust");
  245          Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
  246          Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
  247          DatumBlock(bcx, scratch.to_expr_datum())
  248      }
  249  
  250      fn add_env<'a>(bcx&'a Block<'a>,
  251                     expr&ast::Expr,
  252                     datumDatum<Expr>)
  253                     -> DatumBlock<'a, Expr> {
  254          // This is not the most efficient thing possible; since closures
  255          // are two words it'd be better if this were compiled in
  256          // 'dest' mode, but I can't find a nice way to structure the
  257          // code and keep it DRY that accommodates that use case at the
  258          // moment.
  259  
  260          let closure_ty = expr_ty_adjusted(bcx, expr);
  261          let fn_ptr = datum.to_llscalarish(bcx);
  262          let def = ty::resolve_expr(bcx.tcx(), expr);
  263          closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
  264      }
  265  
  266      fn auto_slice_and_ref<'a>(
  267                            bcx: &'a Block<'a>,
  268                            expr: &ast::Expr,
  269                            datumDatum<Expr>)
  270                            -> DatumBlock<'a, Expr> {
  271          let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
  272          auto_ref(bcx, datum, expr)
  273      }
  274  
  275      fn auto_borrow_obj<'a>(bcx&'a Block<'a>,
  276                             expr&ast::Expr,
  277                             source_datumDatum<Expr>)
  278                             -> DatumBlock<'a, Expr> {
  279          let tcx = bcx.tcx();
  280          let target_obj_ty = expr_ty_adjusted(bcx, expr);
  281          debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx));
  282  
  283          let mut datum = source_datum.to_expr_datum();
  284          datum.ty = target_obj_ty;
  285          DatumBlock(bcx, datum)
  286      }
  287  }
  288  
  289  pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
  290                             expr: &ast::Expr,
  291                             name: &str)
  292                             -> DatumBlock<'a, Lvalue> {
  293      /*!
  294       * Translates an expression in "lvalue" mode -- meaning that it
  295       * returns a reference to the memory that the expr represents.
  296       *
  297       * If this expression is an rvalue, this implies introducing a
  298       * temporary.  In other words, something like `x().f` is
  299       * translated into roughly the equivalent of
  300       *
  301       *   { tmp = x(); tmp.f }
  302       */
  303  
  304      let mut bcx = bcx;
  305      let datum = unpack_datum!(bcx, trans(bcx, expr));
  306      return datum.to_lvalue_datum(bcx, name, expr.id);
  307  }
  308  
  309  fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
  310                          expr: &ast::Expr)
  311                          -> DatumBlock<'a, Expr> {
  312      /*!
  313       * A version of `trans` that ignores adjustments. You almost
  314       * certainly do not want to call this directly.
  315       */
  316  
  317      let mut bcx = bcx;
  318  
  319      debug!("trans_unadjusted(expr={})", bcx.expr_to_str(expr));
  320      let _indenter = indenter();
  321  
  322      debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
  323  
  324      return match ty::expr_kind(bcx.tcx(), expr) {
  325          ty::LvalueExpr | ty::RvalueDatumExpr => {
  326              let datum = unpack_datum!(bcx, {
  327                  trans_datum_unadjusted(bcx, expr)
  328              });
  329  
  330              DatumBlock {bcx: bcx, datum: datum}
  331          }
  332  
  333          ty::RvalueStmtExpr => {
  334              bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
  335              nil(bcx, expr_ty(bcx, expr))
  336          }
  337  
  338          ty::RvalueDpsExpr => {
  339              let ty = expr_ty(bcx, expr);
  340              if type_is_zero_size(bcx.ccx(), ty) {
  341                  bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
  342                  nil(bcx, ty)
  343              } else {
  344                  let scratch = rvalue_scratch_datum(bcx, ty, "");
  345                  bcx = trans_rvalue_dps_unadjusted(
  346                      bcx, expr, SaveIn(scratch.val));
  347  
  348                  // Note: this is not obviously a good idea.  It causes
  349                  // immediate values to be loaded immediately after a
  350                  // return from a call or other similar expression,
  351                  // which in turn leads to alloca's having shorter
  352                  // lifetimes and hence larger stack frames.  However,
  353                  // in turn it can lead to more register pressure.
  354                  // Still, in practice it seems to increase
  355                  // performance, since we have fewer problems with
  356                  // morestack churn.
  357                  let scratch = unpack_datum!(
  358                      bcx, scratch.to_appropriate_datum(bcx));
  359  
  360                  DatumBlock(bcx, scratch.to_expr_datum())
  361              }
  362          }
  363      };
  364  
  365      fn nil<'a>(bcx&'a Block<'a>, tyty::t) -> DatumBlock<'a, Expr> {
  366          let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
  367          let datum = immediate_rvalue(llval, ty);
  368          DatumBlock(bcx, datum.to_expr_datum())
  369      }
  370  }
  371  
  372  fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
  373                                expr: &ast::Expr)
  374                                -> DatumBlock<'a, Expr> {
  375      let mut bcx = bcx;
  376      let fcx = bcx.fcx;
  377      let _icx = push_ctxt("trans_datum_unadjusted");
  378  
  379      match expr.node {
  380          ast::ExprParen(e) => {
  381              trans(bcx, e)
  382          }
  383          ast::ExprPath(_) => {
  384              trans_def(bcx, expr, bcx.def(expr.id))
  385          }
  386          ast::ExprField(base, ident, _) => {
  387              trans_rec_field(bcx, base, ident)
  388          }
  389          ast::ExprIndex(base, idx) => {
  390              trans_index(bcx, expr, base, idx)
  391          }
  392          ast::ExprVstore(contents, ast::ExprVstoreUniq) => {
  393              fcx.push_ast_cleanup_scope(contents.id);
  394              let datum = unpack_datum!(
  395                  bcx, tvec::trans_uniq_vstore(bcx, expr, contents));
  396              bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
  397              DatumBlock(bcx, datum)
  398          }
  399          ast::ExprBox(_, contents) => {
  400              // Special case for `box T`. (The other case, for GC, is handled
  401              // in `trans_rvalue_dps_unadjusted`.)
  402              let box_ty = expr_ty(bcx, expr);
  403              let contents_ty = expr_ty(bcx, contents);
  404              trans_uniq_expr(bcx, box_ty, contents, contents_ty)
  405          }
  406          ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
  407          ast::ExprBinary(op, lhs, rhs) => {
  408              trans_binary(bcx, expr, op, lhs, rhs)
  409          }
  410          ast::ExprUnary(op, x) => {
  411              trans_unary(bcx, expr, op, x)
  412          }
  413          ast::ExprAddrOf(_, x) => {
  414              trans_addr_of(bcx, expr, x)
  415          }
  416          ast::ExprCast(val, _) => {
  417              // Datum output mode means this is a scalar cast:
  418              trans_imm_cast(bcx, val, expr.id)
  419          }
  420          _ => {
  421              bcx.tcx().sess.span_bug(
  422                  expr.span,
  423                  format!("trans_rvalue_datum_unadjusted reached \
  424                        fall-through case: {:?}",
  425                       expr.node));
  426          }
  427      }
  428  }
  429  
  430  fn trans_rec_field<'a>(bcx: &'a Block<'a>,
  431                         base: &ast::Expr,
  432                         fieldast::Ident)
  433                         -> DatumBlock<'a, Expr> {
  434      //! Translates `base.field`.
  435  
  436      let mut bcx = bcx;
  437      let _icx = push_ctxt("trans_rec_field");
  438  
  439      let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
  440      let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
  441      with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
  442              let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
  443              let d = base_datum.get_element(
  444                  field_tys[ix].mt.ty,
  445                  |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
  446              DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
  447          })
  448  }
  449  
  450  fn trans_index<'a>(bcx: &'a Block<'a>,
  451                     index_expr: &ast::Expr,
  452                     base: &ast::Expr,
  453                     idx: &ast::Expr)
  454                     -> DatumBlock<'a, Expr> {
  455      //! Translates `base[idx]`.
  456  
  457      let _icx = push_ctxt("trans_index");
  458      let ccx = bcx.ccx();
  459      let mut bcx = bcx;
  460  
  461      let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
  462  
  463      // Translate index expression and cast to a suitable LLVM integer.
  464      // Rust is less strict than LLVM in this regard.
  465      let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
  466      let ix_val = ix_datum.to_llscalarish(bcx);
  467      let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
  468      let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
  469      let ix_val = {
  470          if ix_size < int_size {
  471              if ty::type_is_signed(expr_ty(bcx, idx)) {
  472                  SExt(bcx, ix_val, ccx.int_type)
  473              } else { ZExt(bcx, ix_val, ccx.int_type) }
  474          } else if ix_size > int_size {
  475              Trunc(bcx, ix_val, ccx.int_type)
  476          } else {
  477              ix_val
  478          }
  479      };
  480  
  481      let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), base_datum.ty));
  482      base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
  483  
  484      let (base, len) = base_datum.get_vec_base_and_len(bcx);
  485  
  486      debug!("trans_index: base {}", bcx.val_to_str(base));
  487      debug!("trans_index: len {}", bcx.val_to_str(len));
  488  
  489      let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
  490      let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
  491      let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
  492      let bcx = with_cond(bcx, expected, |bcx| {
  493              controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
  494          });
  495      let elt = InBoundsGEP(bcx, base, [ix_val]);
  496      let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
  497      DatumBlock(bcx, Datum(elt, vt.unit_ty, LvalueExpr))
  498  }
  499  
  500  fn trans_def<'a>(bcx: &'a Block<'a>,
  501                   ref_expr: &ast::Expr,
  502                   defast::Def)
  503                   -> DatumBlock<'a, Expr>
  504  {
  505      //! Translates a reference to a path.
  506  
  507      let _icx = push_ctxt("trans_def_lvalue");
  508      match def {
  509          ast::DefFn(..) | ast::DefStaticMethod(..) |
  510          ast::DefStruct(_) | ast::DefVariant(..) => {
  511              trans_def_fn_unadjusted(bcx, ref_expr, def)
  512          }
  513          ast::DefStatic(did, _) => {
  514              let const_ty = expr_ty(bcx, ref_expr);
  515  
  516              fn get_did(ccx&CrateContext, didast::DefId)
  517                         -> ast::DefId {
  518                  if did.krate != ast::LOCAL_CRATE {
  519                      inline::maybe_instantiate_inline(ccx, did)
  520                  } else {
  521                      did
  522                  }
  523              }
  524  
  525              fn get_val<'a>(bcx&'a Block<'a>, didast::DefId, const_tyty::t)
  526                         -> ValueRef {
  527                  // For external constants, we don't inline.
  528                  if did.krate == ast::LOCAL_CRATE {
  529                      // The LLVM global has the type of its initializer,
  530                      // which may not be equal to the enum's type for
  531                      // non-C-like enums.
  532                      let val = base::get_item_val(bcx.ccx(), did.node);
  533                      let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
  534                      PointerCast(bcx, val, pty)
  535                  } else {
  536                      match bcx.ccx().extern_const_values.borrow().find(&did) {
  537                          None => {}  // Continue.
  538                          Some(llval) => {
  539                              return *llval;
  540                          }
  541                      }
  542  
  543                      unsafe {
  544                          let llty = type_of::type_of(bcx.ccx(), const_ty);
  545                          let symbol = csearch::get_symbol(
  546                              &bcx.ccx().sess().cstore,
  547                              did);
  548                          let llval = symbol.with_c_str(|buf| {
  549                                  llvm::LLVMAddGlobal(bcx.ccx().llmod,
  550                                                      llty.to_ref(),
  551                                                      buf)
  552                              });
  553                          bcx.ccx().extern_const_values.borrow_mut()
  554                             .insert(did, llval);
  555                          llval
  556                      }
  557                  }
  558              }
  559  
  560              let did = get_did(bcx.ccx(), did);
  561              let val = get_val(bcx, did, const_ty);
  562              DatumBlock(bcx, Datum(val, const_ty, LvalueExpr))
  563          }
  564          _ => {
  565              DatumBlock(bcx, trans_local_var(bcx, def).to_expr_datum())
  566          }
  567      }
  568  }
  569  
  570  fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
  571                                      expr: &ast::Expr)
  572                                      -> &'a Block<'a> {
  573      let mut bcx = bcx;
  574      let _icx = push_ctxt("trans_rvalue_stmt");
  575  
  576      if bcx.unreachable.get() {
  577          return bcx;
  578      }
  579  
  580      match expr.node {
  581          ast::ExprParen(e) => {
  582              trans_into(bcx, e, Ignore)
  583          }
  584          ast::ExprBreak(label_opt) => {
  585              controlflow::trans_break(bcx, expr.id, label_opt)
  586          }
  587          ast::ExprAgain(label_opt) => {
  588              controlflow::trans_cont(bcx, expr.id, label_opt)
  589          }
  590          ast::ExprRet(ex) => {
  591              controlflow::trans_ret(bcx, ex)
  592          }
  593          ast::ExprWhile(cond, body) => {
  594              controlflow::trans_while(bcx, expr.id, cond, body)
  595          }
  596          ast::ExprLoop(body, _) => {
  597              controlflow::trans_loop(bcx, expr.id, body)
  598          }
  599          ast::ExprAssign(dst, src) => {
  600              let src_datum = unpack_datum!(bcx, trans(bcx, src));
  601              let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign"));
  602  
  603              if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
  604                  // If there are destructors involved, make sure we
  605                  // are copying from an rvalue, since that cannot possible
  606                  // alias an lvalue. We are concerned about code like:
  607                  //
  608                  //   a = a
  609                  //
  610                  // but also
  611                  //
  612                  //   a = a.b
  613                  //
  614                  // where e.g. a : Option<Foo> and a.b :
  615                  // Option<Foo>. In that case, freeing `a` before the
  616                  // assignment may also free `a.b`!
  617                  //
  618                  // We could avoid this intermediary with some analysis
  619                  // to determine whether `dst` may possibly own `src`.
  620                  let src_datum = unpack_datum!(
  621                      bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
  622                  bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
  623                  src_datum.store_to(bcx, dst_datum.val)
  624              } else {
  625                  src_datum.store_to(bcx, dst_datum.val)
  626              }
  627          }
  628          ast::ExprAssignOp(op, dst, src) => {
  629              trans_assign_op(bcx, expr, op, dst, src)
  630          }
  631          ast::ExprInlineAsm(ref a) => {
  632              asm::trans_inline_asm(bcx, a)
  633          }
  634          _ => {
  635              bcx.tcx().sess.span_bug(
  636                  expr.span,
  637                  format!("trans_rvalue_stmt_unadjusted reached \
  638                        fall-through case: {:?}",
  639                       expr.node));
  640          }
  641      }
  642  }
  643  
  644  fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
  645                                     expr: &ast::Expr,
  646                                     destDest)
  647                                     -> &'a Block<'a> {
  648      let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
  649      let mut bcx = bcx;
  650      let tcx = bcx.tcx();
  651      let fcx = bcx.fcx;
  652  
  653      match expr.node {
  654          ast::ExprParen(e) => {
  655              trans_into(bcx, e, dest)
  656          }
  657          ast::ExprPath(_) => {
  658              trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
  659          }
  660          ast::ExprIf(cond, thn, els) => {
  661              controlflow::trans_if(bcx, expr.id, cond, thn, els, dest)
  662          }
  663          ast::ExprMatch(discr, ref arms) => {
  664              _match::trans_match(bcx, expr, discr, arms.as_slice(), dest)
  665          }
  666          ast::ExprBlock(blk) => {
  667              controlflow::trans_block(bcx, blk, dest)
  668          }
  669          ast::ExprStruct(_, ref fields, base) => {
  670              trans_rec_or_struct(bcx,
  671                                  fields.as_slice(),
  672                                  base,
  673                                  expr.span,
  674                                  expr.id,
  675                                  dest)
  676          }
  677          ast::ExprTup(ref args) => {
  678              let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
  679              let numbered_fieldsVec<(uint, @ast::Expr)> =
  680                  args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
  681              trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
  682          }
  683          ast::ExprLit(lit) => {
  684              match lit.node {
  685                  ast::LitStr(ref s, _) => {
  686                      tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
  687                  }
  688                  _ => {
  689                      bcx.tcx()
  690                         .sess
  691                         .span_bug(expr.span,
  692                                   "trans_rvalue_dps_unadjusted shouldn't be \
  693                                    translating this type of literal")
  694                  }
  695              }
  696          }
  697          ast::ExprVstore(contents, ast::ExprVstoreSlice) |
  698          ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
  699              fcx.push_ast_cleanup_scope(contents.id);
  700              bcx = tvec::trans_slice_vstore(bcx, expr, contents, dest);
  701              fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
  702          }
  703          ast::ExprVec(..) | ast::ExprRepeat(..) => {
  704              tvec::trans_fixed_vstore(bcx, expr, expr, dest)
  705          }
  706          ast::ExprFnBlock(decl, body) |
  707          ast::ExprProc(decl, body) => {
  708              let expr_ty = expr_ty(bcx, expr);
  709              let store = ty::ty_closure_store(expr_ty);
  710              debug!("translating block function {} with type {}",
  711                     expr_to_str(expr), expr_ty.repr(tcx));
  712              closure::trans_expr_fn(bcx, store, decl, body, expr.id, dest)
  713          }
  714          ast::ExprCall(f, ref args) => {
  715              callee::trans_call(bcx, expr, f, callee::ArgExprs(args.as_slice()), dest)
  716          }
  717          ast::ExprMethodCall(_, _, ref args) => {
  718              callee::trans_method_call(bcx,
  719                                        expr,
  720                                        *args.get(0),
  721                                        callee::ArgExprs(args.as_slice()),
  722                                        dest)
  723          }
  724          ast::ExprBinary(_, lhs, rhs) => {
  725              // if not overloaded, would be RvalueDatumExpr
  726              let lhs = unpack_datum!(bcx, trans(bcx, lhs));
  727              let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
  728              trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
  729                                  Some((rhs_datum, rhs.id)), Some(dest)).bcx
  730          }
  731          ast::ExprUnary(_, subexpr) => {
  732              // if not overloaded, would be RvalueDatumExpr
  733              let arg = unpack_datum!(bcx, trans(bcx, subexpr));
  734              trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
  735                                  arg, None, Some(dest)).bcx
  736          }
  737          ast::ExprIndex(base, idx) => {
  738              // if not overloaded, would be RvalueDatumExpr
  739              let base = unpack_datum!(bcx, trans(bcx, base));
  740              let idx_datum = unpack_datum!(bcx, trans(bcx, idx));
  741              trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
  742                                  Some((idx_datum, idx.id)), Some(dest)).bcx
  743          }
  744          ast::ExprCast(val, _) => {
  745              // DPS output mode means this is a trait cast:
  746              match ty::get(node_id_type(bcx, expr.id)).sty {
  747                  ty::ty_trait(..) => {
  748                      let datum = unpack_datum!(bcx, trans(bcx, val));
  749                      meth::trans_trait_cast(bcx, datum, expr.id, dest)
  750                  }
  751                  _ => {
  752                      bcx.tcx().sess.span_bug(expr.span,
  753                                              "expr_cast of non-trait");
  754                  }
  755              }
  756          }
  757          ast::ExprAssignOp(op, dst, src) => {
  758              trans_assign_op(bcx, expr, op, dst, src)
  759          }
  760          ast::ExprBox(_, contents) => {
  761              // Special case for `Gc<T>` for now. The other case, for unique
  762              // pointers, is handled in `trans_rvalue_datum_unadjusted`.
  763              trans_gc(bcx, expr, contents, dest)
  764          }
  765          _ => {
  766              bcx.tcx().sess.span_bug(
  767                  expr.span,
  768                  format!("trans_rvalue_dps_unadjusted reached fall-through case: {:?}",
  769                       expr.node));
  770          }
  771      }
  772  }
  773  
  774  fn trans_def_dps_unadjusted<'a>(
  775                              bcx: &'a Block<'a>,
  776                              ref_expr: &ast::Expr,
  777                              defast::Def,
  778                              destDest)
  779                              -> &'a Block<'a> {
  780      let _icx = push_ctxt("trans_def_dps_unadjusted");
  781  
  782      let lldest = match dest {
  783          SaveIn(lldest) => lldest,
  784          Ignore => { return bcx; }
  785      };
  786  
  787      match def {
  788          ast::DefVariant(tid, vid, _) => {
  789              let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
  790              if variant_info.args.len() > 0u {
  791                  // N-ary variant.
  792                  let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
  793                  Store(bcx, llfn, lldest);
  794                  return bcx;
  795              } else {
  796                  // Nullary variant.
  797                  let ty = expr_ty(bcx, ref_expr);
  798                  let repr = adt::represent_type(bcx.ccx(), ty);
  799                  adt::trans_start_init(bcx, &*repr, lldest,
  800                                        variant_info.disr_val);
  801                  return bcx;
  802              }
  803          }
  804          ast::DefStruct(_) => {
  805              let ty = expr_ty(bcx, ref_expr);
  806              match ty::get(ty).sty {
  807                  ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
  808                      let repr = adt::represent_type(bcx.ccx(), ty);
  809                      adt::trans_start_init(bcx, &*repr, lldest, 0);
  810                  }
  811                  _ => {}
  812              }
  813              bcx
  814          }
  815          _ => {
  816              bcx.tcx().sess.span_bug(ref_expr.span, format!(
  817                  "Non-DPS def {:?} referened by {}",
  818                  def, bcx.node_id_to_str(ref_expr.id)));
  819          }
  820      }
  821  }
  822  
  823  fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
  824                                 ref_expr: &ast::Expr,
  825                                 defast::Def) -> DatumBlock<'a, Expr> {
  826      let _icx = push_ctxt("trans_def_datum_unadjusted");
  827  
  828      let llfn = match def {
  829          ast::DefFn(did, _) |
  830          ast::DefStruct(did) | ast::DefVariant(_, did, _) |
  831          ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
  832              callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
  833          }
  834          ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
  835              meth::trans_static_method_callee(bcx, impl_did,
  836                                               trait_did, ref_expr.id)
  837          }
  838          _ => {
  839              bcx.tcx().sess.span_bug(ref_expr.span, format!(
  840                      "trans_def_fn_unadjusted invoked on: {:?} for {}",
  841                      def,
  842                      ref_expr.repr(bcx.tcx())));
  843          }
  844      };
  845  
  846      let fn_ty = expr_ty(bcx, ref_expr);
  847      DatumBlock(bcx, Datum(llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
  848  }
  849  
  850  pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
  851                             defast::Def)
  852                             -> Datum<Lvalue> {
  853      /*!
  854       * Translates a reference to a local variable or argument.
  855       * This always results in an lvalue datum.
  856       */
  857  
  858      let _icx = push_ctxt("trans_local_var");
  859  
  860      return match def {
  861          ast::DefUpvar(nid, _, _, _) => {
  862              // Can't move upvars, so this is never a ZeroMemLastUse.
  863              let local_ty = node_id_type(bcx, nid);
  864              match bcx.fcx.llupvars.borrow().find(&nid) {
  865                  Some(&val) => Datum(val, local_ty, Lvalue),
  866                  None => {
  867                      bcx.sess().bug(format!(
  868                          "trans_local_var: no llval for upvar {:?} found", nid));
  869                  }
  870              }
  871          }
  872          ast::DefArg(nid, _) => {
  873              take_local(bcx, &*bcx.fcx.llargs.borrow(), nid)
  874          }
  875          ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
  876              take_local(bcx, &*bcx.fcx.lllocals.borrow(), nid)
  877          }
  878          _ => {
  879              bcx.sess().unimpl(format!(
  880                  "unsupported def type in trans_local_var: {:?}", def));
  881          }
  882      };
  883  
  884      fn take_local<'a>(bcx&'a Block<'a>,
  885                        table&NodeMap<Datum<Lvalue>>,
  886                        nidast::NodeId)
  887                        -> Datum<Lvalue> {
  888          let datum = match table.find(&nid) {
  889              Some(&v) => v,
  890              None => {
  891                  bcx.sess().bug(format!(
  892                      "trans_local_var: no datum for local/arg {:?} found", nid));
  893              }
  894          };
  895          debug!("take_local(nid={:?}, v={}, ty={})",
  896                 nid, bcx.val_to_str(datum.val), bcx.ty_to_str(datum.ty));
  897          datum
  898      }
  899  }
  900  
  901  pub fn with_field_tys<R>(tcx: &ty::ctxt,
  902                           tyty::t,
  903                           node_id_optOption<ast::NodeId>,
  904                           op: |ty::Disr, (&[ty::field])-> R)
  905                           -> R {
  906      /*!
  907       * Helper for enumerating the field types of structs, enums, or records.
  908       * The optional node ID here is the node ID of the path identifying the enum
  909       * variant in use. If none, this cannot possibly an enum variant (so, if it
  910       * is and `node_id_opt` is none, this function fails).
  911       */
  912  
  913      match ty::get(ty).sty {
  914          ty::ty_struct(did, ref substs) => {
  915              op(0, struct_fields(tcx, did, substs).as_slice())
  916          }
  917  
  918          ty::ty_enum(_, ref substs) => {
  919              // We want the *variant* ID here, not the enum ID.
  920              match node_id_opt {
  921                  None => {
  922                      tcx.sess.bug(format!(
  923                          "cannot get field types from the enum type {} \
  924                           without a node ID",
  925                          ty.repr(tcx)));
  926                  }
  927                  Some(node_id) => {
  928                      let def = tcx.def_map.borrow().get_copy(&node_id);
  929                      match def {
  930                          ast::DefVariant(enum_id, variant_id, _) => {
  931                              let variant_info = ty::enum_variant_with_id(
  932                                  tcx, enum_id, variant_id);
  933                              op(variant_info.disr_val,
  934                                 struct_fields(tcx,
  935                                               variant_id,
  936                                               substs).as_slice())
  937                          }
  938                          _ => {
  939                              tcx.sess.bug("resolve didn't map this expr to a \
  940                                            variant ID")
  941                          }
  942                      }
  943                  }
  944              }
  945          }
  946  
  947          _ => {
  948              tcx.sess.bug(format!(
  949                  "cannot get field types from the type {}",
  950                  ty.repr(tcx)));
  951          }
  952      }
  953  }
  954  
  955  fn trans_rec_or_struct<'a>(
  956                         bcx: &'a Block<'a>,
  957                         fields: &[ast::Field],
  958                         baseOption<@ast::Expr>,
  959                         expr_spancodemap::Span,
  960                         idast::NodeId,
  961                         destDest)
  962                         -> &'a Block<'a> {
  963      let _icx = push_ctxt("trans_rec");
  964      let bcx = bcx;
  965  
  966      let ty = node_id_type(bcx, id);
  967      let tcx = bcx.tcx();
  968      with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
  969          let mut need_base = Vec::from_elem(field_tys.len(), true);
  970  
  971          let numbered_fields = fields.iter().map(|field| {
  972              let opt_pos =
  973                  field_tys.iter().position(|field_ty|
  974                                            field_ty.ident.name == field.ident.node.name);
  975              match opt_pos {
  976                  Some(i) => {
  977                      *need_base.get_mut(i) = false;
  978                      (i, field.expr)
  979                  }
  980                  None => {
  981                      tcx.sess.span_bug(field.span,
  982                                        "Couldn't find field in struct type")
  983                  }
  984              }
  985          }).collect::<Vec<_>>();
  986          let optbase = match base {
  987              Some(base_expr) => {
  988                  let mut leftovers = Vec::new();
  989                  for (i, b) in need_base.iter().enumerate() {
  990                      if *b {
  991                          leftovers.push((i, field_tys[i].mt.ty))
  992                      }
  993                  }
  994                  Some(StructBaseInfo {expr: base_expr,
  995                                       fields: leftovers })
  996              }
  997              None => {
  998                  if need_base.iter().any(|b| *b) {
  999                      tcx.sess.span_bug(expr_span, "missing fields and no base expr")
 1000                  }
 1001                  None
 1002              }
 1003          };
 1004  
 1005          let repr = adt::represent_type(bcx.ccx(), ty);
 1006          trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
 1007      })
 1008  }
 1009  
 1010  /**
 1011   * Information that `trans_adt` needs in order to fill in the fields
 1012   * of a struct copied from a base struct (e.g., from an expression
 1013   * like `Foo { a: b, ..base }`.
 1014   *
 1015   * Note that `fields` may be empty; the base expression must always be
 1016   * evaluated for side-effects.
 1017   */
 1018  struct StructBaseInfo {
 1019      /// The base expression; will be evaluated after all explicit fields.
 1020      expr: @ast::Expr,
 1021      /// The indices of fields to copy paired with their types.
 1022      fields: Vec<(uint, ty::t)> }
 1023  
 1024  /**
 1025   * Constructs an ADT instance:
 1026   *
 1027   * - `fields` should be a list of field indices paired with the
 1028   * expression to store into that field.  The initializers will be
 1029   * evaluated in the order specified by `fields`.
 1030   *
 1031   * - `optbase` contains information on the base struct (if any) from
 1032   * which remaining fields are copied; see comments on `StructBaseInfo`.
 1033   */
 1034  fn trans_adt<'a>(
 1035               bcx: &'a Block<'a>,
 1036               repr: &adt::Repr,
 1037               discrty::Disr,
 1038               fields: &[(uint, @ast::Expr)],
 1039               optbaseOption<StructBaseInfo>,
 1040               destDest)
 1041               -> &'a Block<'a> {
 1042      let _icx = push_ctxt("trans_adt");
 1043      let fcx = bcx.fcx;
 1044      let mut bcx = bcx;
 1045      let addr = match dest {
 1046          Ignore => {
 1047              for &(_i, e) in fields.iter() {
 1048                  bcx = trans_into(bcx, e, Ignore);
 1049              }
 1050              for sbi in optbase.iter() {
 1051                  // FIXME #7261: this moves entire base, not just certain fields
 1052                  bcx = trans_into(bcx, sbi.expr, Ignore);
 1053              }
 1054              return bcx;
 1055          }
 1056          SaveIn(pos) => pos
 1057      };
 1058  
 1059      // This scope holds intermediates that must be cleaned should
 1060      // failure occur before the ADT as a whole is ready.
 1061      let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
 1062  
 1063      adt::trans_start_init(bcx, repr, addr, discr);
 1064  
 1065      for &(i, e) in fields.iter() {
 1066          let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
 1067          let e_ty = expr_ty_adjusted(bcx, e);
 1068          bcx = trans_into(bcx, e, SaveIn(dest));
 1069          fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
 1070                                dest, e_ty);
 1071      }
 1072  
 1073      for base in optbase.iter() {
 1074          // FIXME #6573: is it sound to use the destination's repr on the base?
 1075          // And, would it ever be reasonable to be here with discr != 0?
 1076          let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base.expr, "base"));
 1077          for &(i, t) in base.fields.iter() {
 1078              let datum = base_datum.get_element(
 1079                  t,
 1080                  |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i));
 1081              let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
 1082              bcx = datum.store_to(bcx, dest);
 1083          }
 1084      }
 1085  
 1086      fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
 1087  
 1088      return bcx;
 1089  }
 1090  
 1091  
 1092  fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
 1093                             expr: &ast::Expr,
 1094                             litast::Lit)
 1095                             -> DatumBlock<'a, Expr> {
 1096      // must not be a string constant, that is a RvalueDpsExpr
 1097      let _icx = push_ctxt("trans_immediate_lit");
 1098      let ty = expr_ty(bcx, expr);
 1099      let v = consts::const_lit(bcx.ccx(), expr, lit);
 1100      immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
 1101  }
 1102  
 1103  fn trans_unary<'a>(bcx: &'a Block<'a>,
 1104                     expr: &ast::Expr,
 1105                     opast::UnOp,
 1106                     sub_expr: &ast::Expr)
 1107                     -> DatumBlock<'a, Expr> {
 1108      let ccx = bcx.ccx();
 1109      let mut bcx = bcx;
 1110      let _icx = push_ctxt("trans_unary_datum");
 1111  
 1112      let method_call = MethodCall::expr(expr.id);
 1113  
 1114      // The only overloaded operator that is translated to a datum
 1115      // is an overloaded deref, since it is always yields a `&T`.
 1116      // Otherwise, we should be in the RvalueDpsExpr path.
 1117      assert!(
 1118          op == ast::UnDeref ||
 1119          !ccx.tcx.method_map.borrow().contains_key(&method_call));
 1120  
 1121      let un_ty = expr_ty(bcx, expr);
 1122  
 1123      match op {
 1124          ast::UnNot => {
 1125              let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
 1126              let llresult = if ty::type_is_bool(un_ty) {
 1127                  let val = datum.to_llscalarish(bcx);
 1128                  let llcond = ICmp(bcx,
 1129                                    lib::llvm::IntEQ,
 1130                                    val,
 1131                                    C_bool(ccx, false));
 1132                  Select(bcx, llcond, C_bool(ccx, true), C_bool(ccx, false))
 1133              } else {
 1134                  // Note: `Not` is bitwise, not suitable for logical not.
 1135                  Not(bcx, datum.to_llscalarish(bcx))
 1136              };
 1137              immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
 1138          }
 1139          ast::UnNeg => {
 1140              let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
 1141              let val = datum.to_llscalarish(bcx);
 1142              let llneg = {
 1143                  if ty::type_is_fp(un_ty) {
 1144                      FNeg(bcx, val)
 1145                  } else {
 1146                      Neg(bcx, val)
 1147                  }
 1148              };
 1149              immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
 1150          }
 1151          ast::UnBox => {
 1152              trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
 1153          }
 1154          ast::UnUniq => {
 1155              trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
 1156          }
 1157          ast::UnDeref => {
 1158              let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
 1159              deref_once(bcx, expr, datum, 0)
 1160          }
 1161      }
 1162  }
 1163  
 1164  fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
 1165                         box_tyty::t,
 1166                         contents: &ast::Expr,
 1167                         contents_tyty::t)
 1168                          -> DatumBlock<'a, Expr> {
 1169      let _icx = push_ctxt("trans_uniq_expr");
 1170      let fcx = bcx.fcx;
 1171      let llty = type_of::type_of(bcx.ccx(), contents_ty);
 1172      let size = llsize_of(bcx.ccx(), llty);
 1173      // We need to a make a pointer type because box_ty is ty_bot
 1174      // if content_ty is, e.g. box fail!().
 1175      let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
 1176      let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size);
 1177      // Unique boxes do not allocate for zero-size types. The standard library
 1178      // may assume that `free` is never called on the pointer returned for
 1179      // `Box<ZeroSizeType>`.
 1180      let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
 1181          trans_into(bcx, contents, SaveIn(val))
 1182      } else {
 1183          let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
 1184          fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
 1185                                  val, cleanup::HeapExchange);
 1186          let bcx = trans_into(bcx, contents, SaveIn(val));
 1187          fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
 1188          bcx
 1189      };
 1190      immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
 1191  }
 1192  
 1193  fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
 1194                            box_tyty::t,
 1195                            contents: &ast::Expr,
 1196                            contents_tyty::t)
 1197                            -> DatumBlock<'a, Expr> {
 1198      let _icx = push_ctxt("trans_managed_expr");
 1199      let fcx = bcx.fcx;
 1200      let ty = type_of::type_of(bcx.ccx(), contents_ty);
 1201      let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
 1202                                                          llsize_of(bcx.ccx(), ty));
 1203      let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
 1204  
 1205      let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
 1206      fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
 1207                              bx, cleanup::HeapManaged);
 1208      let bcx = trans_into(bcx, contents, SaveIn(body));
 1209      fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
 1210      immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
 1211  }
 1212  
 1213  fn trans_addr_of<'a>(bcx: &'a Block<'a>,
 1214                       expr: &ast::Expr,
 1215                       subexpr: &ast::Expr)
 1216                       -> DatumBlock<'a, Expr> {
 1217      let _icx = push_ctxt("trans_addr_of");
 1218      let mut bcx = bcx;
 1219      let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
 1220      let ty = expr_ty(bcx, expr);
 1221      return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
 1222  }
 1223  
 1224  fn trans_gc<'a>(mut bcx: &'a Block<'a>,
 1225                  expr: &ast::Expr,
 1226                  contents: &ast::Expr,
 1227                  destDest)
 1228                  -> &'a Block<'a> {
 1229      let contents_ty = expr_ty(bcx, contents);
 1230      let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
 1231  
 1232      let contents_datum = unpack_datum!(bcx, trans_managed_expr(bcx,
 1233                                                                 box_ty,
 1234                                                                 contents,
 1235                                                                 contents_ty));
 1236  
 1237      match dest {
 1238          Ignore => bcx,
 1239          SaveIn(addr) => {
 1240              let expr_ty = expr_ty(bcx, expr);
 1241              let repr = adt::represent_type(bcx.ccx(), expr_ty);
 1242              adt::trans_start_init(bcx, &*repr, addr, 0);
 1243              let field_dest = adt::trans_field_ptr(bcx, &*repr, addr, 0, 0);
 1244              contents_datum.store_to(bcx, field_dest)
 1245          }
 1246      }
 1247  }
 1248  
 1249  // Important to get types for both lhs and rhs, because one might be _|_
 1250  // and the other not.
 1251  fn trans_eager_binop<'a>(
 1252                       bcx: &'a Block<'a>,
 1253                       binop_expr: &ast::Expr,
 1254                       binop_tyty::t,
 1255                       opast::BinOp,
 1256                       lhs_tty::t,
 1257                       lhsValueRef,
 1258                       rhs_tty::t,
 1259                       rhsValueRef)
 1260                       -> DatumBlock<'a, Expr> {
 1261      let _icx = push_ctxt("trans_eager_binop");
 1262  
 1263      let tcx = bcx.tcx();
 1264      let is_simd = ty::type_is_simd(tcx, lhs_t);
 1265      let intype = {
 1266          if ty::type_is_bot(lhs_t) { rhs_t }
 1267          else if is_simd { ty::simd_type(tcx, lhs_t) }
 1268          else { lhs_t }
 1269      };
 1270      let is_float = ty::type_is_fp(intype);
 1271      let is_signed = ty::type_is_signed(intype);
 1272  
 1273      let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
 1274  
 1275      let mut bcx = bcx;
 1276      let val = match op {
 1277        ast::BiAdd => {
 1278          if is_float { FAdd(bcx, lhs, rhs) }
 1279          else { Add(bcx, lhs, rhs) }
 1280        }
 1281        ast::BiSub => {
 1282          if is_float { FSub(bcx, lhs, rhs) }
 1283          else { Sub(bcx, lhs, rhs) }
 1284        }
 1285        ast::BiMul => {
 1286          if is_float { FMul(bcx, lhs, rhs) }
 1287          else { Mul(bcx, lhs, rhs) }
 1288        }
 1289        ast::BiDiv => {
 1290          if is_float {
 1291              FDiv(bcx, lhs, rhs)
 1292          } else {
 1293              // Only zero-check integers; fp /0 is NaN
 1294              bcx = base::fail_if_zero(bcx, binop_expr.span,
 1295                                       op, rhs, rhs_t);
 1296              if is_signed {
 1297                  SDiv(bcx, lhs, rhs)
 1298              } else {
 1299                  UDiv(bcx, lhs, rhs)
 1300              }
 1301          }
 1302        }
 1303        ast::BiRem => {
 1304          if is_float {
 1305              FRem(bcx, lhs, rhs)
 1306          } else {
 1307              // Only zero-check integers; fp %0 is NaN
 1308              bcx = base::fail_if_zero(bcx, binop_expr.span,
 1309                                       op, rhs, rhs_t);
 1310              if is_signed {
 1311                  SRem(bcx, lhs, rhs)
 1312              } else {
 1313                  URem(bcx, lhs, rhs)
 1314              }
 1315          }
 1316        }
 1317        ast::BiBitOr => Or(bcx, lhs, rhs),
 1318        ast::BiBitAnd => And(bcx, lhs, rhs),
 1319        ast::BiBitXor => Xor(bcx, lhs, rhs),
 1320        ast::BiShl => Shl(bcx, lhs, rhs),
 1321        ast::BiShr => {
 1322          if is_signed {
 1323              AShr(bcx, lhs, rhs)
 1324          } else { LShr(bcx, lhs, rhs) }
 1325        }
 1326        ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
 1327          if ty::type_is_bot(rhs_t) {
 1328              C_bool(bcx.ccx(), false)
 1329          } else if ty::type_is_scalar(rhs_t) {
 1330              let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
 1331              bcx = cmpr.bcx;
 1332              ZExt(bcx, cmpr.val, Type::i8(bcx.ccx()))
 1333          } else if is_simd {
 1334              base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
 1335          } else {
 1336              bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
 1337          }
 1338        }
 1339        _ => {
 1340          bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
 1341        }
 1342      };
 1343  
 1344      immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
 1345  }
 1346  
 1347  // refinement types would obviate the need for this
 1348  enum lazy_binop_ty {
 1349      lazy_and,
 1350      lazy_or,
 1351  }
 1352  
 1353  fn trans_lazy_binop<'a>(
 1354                      bcx: &'a Block<'a>,
 1355                      binop_expr: &ast::Expr,
 1356                      oplazy_binop_ty,
 1357                      a: &ast::Expr,
 1358                      b: &ast::Expr)
 1359                      -> DatumBlock<'a, Expr> {
 1360      let _icx = push_ctxt("trans_lazy_binop");
 1361      let binop_ty = expr_ty(bcx, binop_expr);
 1362      let fcx = bcx.fcx;
 1363  
 1364      let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
 1365      let lhs = lhs.to_llscalarish(past_lhs);
 1366  
 1367      if past_lhs.unreachable.get() {
 1368          return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
 1369      }
 1370  
 1371      let join = fcx.new_id_block("join", binop_expr.id);
 1372      let before_rhs = fcx.new_id_block("before_rhs", b.id);
 1373  
 1374      let lhs_i1 = bool_to_i1(past_lhs, lhs);
 1375      match op {
 1376        lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
 1377        lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
 1378      }
 1379  
 1380      let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
 1381      let rhs = rhs.to_llscalarish(past_rhs);
 1382  
 1383      if past_rhs.unreachable.get() {
 1384          return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
 1385      }
 1386  
 1387      Br(past_rhs, join.llbb);
 1388      let phi = Phi(join, Type::bool(bcx.ccx()), [lhs, rhs],
 1389                    [past_lhs.llbb, past_rhs.llbb]);
 1390  
 1391      return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
 1392  }
 1393  
 1394  fn trans_binary<'a>(bcx: &'a Block<'a>,
 1395                      expr: &ast::Expr,
 1396                      opast::BinOp,
 1397                      lhs: &ast::Expr,
 1398                      rhs: &ast::Expr)
 1399                      -> DatumBlock<'a, Expr> {
 1400      let _icx = push_ctxt("trans_binary");
 1401      let ccx = bcx.ccx();
 1402  
 1403      // if overloaded, would be RvalueDpsExpr
 1404      assert!(!ccx.tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
 1405  
 1406      match op {
 1407          ast::BiAnd => {
 1408              trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
 1409          }
 1410          ast::BiOr => {
 1411              trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
 1412          }
 1413          _ => {
 1414              let mut bcx = bcx;
 1415              let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
 1416              let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
 1417              let binop_ty = expr_ty(bcx, expr);
 1418  
 1419              debug!("trans_binary (expr {}): lhs_datum={}",
 1420                     expr.id,
 1421                     lhs_datum.to_str(ccx));
 1422              let lhs_ty = lhs_datum.ty;
 1423              let lhs = lhs_datum.to_llscalarish(bcx);
 1424  
 1425              debug!("trans_binary (expr {}): rhs_datum={}",
 1426                     expr.id,
 1427                     rhs_datum.to_str(ccx));
 1428              let rhs_ty = rhs_datum.ty;
 1429              let rhs = rhs_datum.to_llscalarish(bcx);
 1430              trans_eager_binop(bcx, expr, binop_ty, op,
 1431                                lhs_ty, lhs, rhs_ty, rhs)
 1432          }
 1433      }
 1434  }
 1435  
 1436  fn trans_overloaded_op<'a, 'b>(
 1437                         bcx: &'a Block<'a>,
 1438                         expr: &ast::Expr,
 1439                         method_callMethodCall,
 1440                         lhsDatum<Expr>,
 1441                         rhsOption<(Datum<Expr>, ast::NodeId)>,
 1442                         destOption<Dest>)
 1443                         -> Result<'a> {
 1444      let method_ty = bcx.tcx().method_map.borrow().get(&method_call).ty;
 1445      callee::trans_call_inner(bcx,
 1446                               Some(expr_info(expr)),
 1447                               monomorphize_type(bcx, method_ty),
 1448                               |bcx, arg_cleanup_scope| {
 1449                                  meth::trans_method_callee(bcx,
 1450                                                            method_call,
 1451                                                            None,
 1452                                                            arg_cleanup_scope)
 1453                               },
 1454                               callee::ArgOverloadedOp(lhs, rhs),
 1455                               dest)
 1456  }
 1457  
 1458  fn int_cast(bcx: &Block,
 1459              lldsttypeType,
 1460              llsrctypeType,
 1461              llsrcValueRef,
 1462              signed: bool)
 1463              -> ValueRef {
 1464      let _icx = push_ctxt("int_cast");
 1465      unsafe {
 1466          let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
 1467          let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
 1468          return if dstsz == srcsz {
 1469              BitCast(bcx, llsrc, lldsttype)
 1470          } else if srcsz > dstsz {
 1471              TruncOrBitCast(bcx, llsrc, lldsttype)
 1472          } else if signed {
 1473              SExtOrBitCast(bcx, llsrc, lldsttype)
 1474          } else {
 1475              ZExtOrBitCast(bcx, llsrc, lldsttype)
 1476          };
 1477      }
 1478  }
 1479  
 1480  fn float_cast(bcx: &Block,
 1481                lldsttypeType,
 1482                llsrctypeType,
 1483                llsrcValueRef)
 1484                -> ValueRef {
 1485      let _icx = push_ctxt("float_cast");
 1486      let srcsz = llsrctype.float_width();
 1487      let dstsz = lldsttype.float_width();
 1488      return if dstsz > srcsz {
 1489          FPExt(bcx, llsrc, lldsttype)
 1490      } else if srcsz > dstsz {
 1491          FPTrunc(bcx, llsrc, lldsttype)
 1492      } else { llsrc };
 1493  }
 1494  
 1495  #[deriving(Eq)]
 1496  pub enum cast_kind {
 1497      cast_pointer,
 1498      cast_integral,
 1499      cast_float,
 1500      cast_enum,
 1501      cast_other,
 1502  }
 1503  
 1504  pub fn cast_type_kind(tty::t) -> cast_kind {
 1505      match ty::get(t).sty {
 1506          ty::ty_char        => cast_integral,
 1507          ty::ty_float(..)   => cast_float,
 1508          ty::ty_ptr(..)     => cast_pointer,
 1509          ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
 1510              ty::ty_vec(_, None) | ty::ty_str => cast_other,
 1511              _ => cast_pointer,
 1512          },
 1513          ty::ty_bare_fn(..) => cast_pointer,
 1514          ty::ty_int(..)     => cast_integral,
 1515          ty::ty_uint(..)    => cast_integral,
 1516          ty::ty_bool        => cast_integral,
 1517          ty::ty_enum(..)    => cast_enum,
 1518          _                  => cast_other
 1519      }
 1520  }
 1521  
 1522  fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
 1523                        expr: &ast::Expr,
 1524                        idast::NodeId)
 1525                        -> DatumBlock<'a, Expr> {
 1526      let _icx = push_ctxt("trans_cast");
 1527      let mut bcx = bcx;
 1528      let ccx = bcx.ccx();
 1529  
 1530      let t_in = expr_ty(bcx, expr);
 1531      let t_out = node_id_type(bcx, id);
 1532      let k_in = cast_type_kind(t_in);
 1533      let k_out = cast_type_kind(t_out);
 1534      let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
 1535      let ll_t_in = type_of::type_of(ccx, t_in);
 1536      let ll_t_out = type_of::type_of(ccx, t_out);
 1537  
 1538      // Convert the value to be cast into a ValueRef, either by-ref or
 1539      // by-value as appropriate given its type:
 1540      let datum = unpack_datum!(bcx, trans(bcx, expr));
 1541      let newval = match (k_in, k_out) {
 1542          (cast_integral, cast_integral) => {
 1543              let llexpr = datum.to_llscalarish(bcx);
 1544              int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
 1545          }
 1546          (cast_float, cast_float) => {
 1547              let llexpr = datum.to_llscalarish(bcx);
 1548              float_cast(bcx, ll_t_out, ll_t_in, llexpr)
 1549          }
 1550          (cast_integral, cast_float) => {
 1551              let llexpr = datum.to_llscalarish(bcx);
 1552              if s_in {
 1553                  SIToFP(bcx, llexpr, ll_t_out)
 1554              } else { UIToFP(bcx, llexpr, ll_t_out) }
 1555          }
 1556          (cast_float, cast_integral) => {
 1557              let llexpr = datum.to_llscalarish(bcx);
 1558              if ty::type_is_signed(t_out) {
 1559                  FPToSI(bcx, llexpr, ll_t_out)
 1560              } else { FPToUI(bcx, llexpr, ll_t_out) }
 1561          }
 1562          (cast_integral, cast_pointer) => {
 1563              let llexpr = datum.to_llscalarish(bcx);
 1564              IntToPtr(bcx, llexpr, ll_t_out)
 1565          }
 1566          (cast_pointer, cast_integral) => {
 1567              let llexpr = datum.to_llscalarish(bcx);
 1568              PtrToInt(bcx, llexpr, ll_t_out)
 1569          }
 1570          (cast_pointer, cast_pointer) => {
 1571              let llexpr = datum.to_llscalarish(bcx);
 1572              PointerCast(bcx, llexpr, ll_t_out)
 1573          }
 1574          (cast_enum, cast_integral) |
 1575          (cast_enum, cast_float) => {
 1576              let mut bcx = bcx;
 1577              let repr = adt::represent_type(ccx, t_in);
 1578              let datum = unpack_datum!(
 1579                  bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
 1580              let llexpr_ptr = datum.to_llref();
 1581              let lldiscrim_a =
 1582                  adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
 1583              match k_out {
 1584                  cast_integral => int_cast(bcx, ll_t_out,
 1585                                            val_ty(lldiscrim_a),
 1586                                            lldiscrim_a, true),
 1587                  cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
 1588                  _ => ccx.sess().bug(format!("translating unsupported cast: \
 1589                                              {} ({:?}) -> {} ({:?})",
 1590                                              t_in.repr(bcx.tcx()), k_in,
 1591                                              t_out.repr(bcx.tcx()), k_out))
 1592              }
 1593          }
 1594          _ => ccx.sess().bug(format!("translating unsupported cast: \
 1595                                      {} ({:?}) -> {} ({:?})",
 1596                                      t_in.repr(bcx.tcx()), k_in,
 1597                                      t_out.repr(bcx.tcx()), k_out))
 1598      };
 1599      return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
 1600  }
 1601  
 1602  fn trans_assign_op<'a>(
 1603                     bcx: &'a Block<'a>,
 1604                     expr: &ast::Expr,
 1605                     opast::BinOp,
 1606                     dst: &ast::Expr,
 1607                     src: @ast::Expr)
 1608                     -> &'a Block<'a> {
 1609      let _icx = push_ctxt("trans_assign_op");
 1610      let mut bcx = bcx;
 1611  
 1612      debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
 1613  
 1614      // User-defined operator methods cannot be used with `+=` etc right now
 1615      assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
 1616  
 1617      // Evaluate LHS (destination), which should be an lvalue
 1618      let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
 1619      assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
 1620      let dst_ty = dst_datum.ty;
 1621      let dst = Load(bcx, dst_datum.val);
 1622  
 1623      // Evaluate RHS
 1624      let rhs_datum = unpack_datum!(bcx, trans(bcx, src));
 1625      let rhs_ty = rhs_datum.ty;
 1626      let rhs = rhs_datum.to_llscalarish(bcx);
 1627  
 1628      // Perform computation and store the result
 1629      let result_datum = unpack_datum!(
 1630          bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
 1631                                 dst_ty, dst, rhs_ty, rhs));
 1632      return result_datum.store_to(bcx, dst_datum.val);
 1633  }
 1634  
 1635  fn auto_ref<'a>(bcx: &'a Block<'a>,
 1636                  datumDatum<Expr>,
 1637                  expr: &ast::Expr)
 1638                  -> DatumBlock<'a, Expr> {
 1639      let mut bcx = bcx;
 1640  
 1641      // Ensure cleanup of `datum` if not already scheduled and obtain
 1642      // a "by ref" pointer.
 1643      let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
 1644  
 1645      // Compute final type. Note that we are loose with the region and
 1646      // mutability, since those things don't matter in trans.
 1647      let referent_ty = lv_datum.ty;
 1648      let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
 1649  
 1650      // Get the pointer.
 1651      let llref = lv_datum.to_llref();
 1652  
 1653      // Construct the resulting datum, using what was the "by ref"
 1654      // ValueRef of type `referent_ty` to be the "by value" ValueRef
 1655      // of type `&referent_ty`.
 1656      DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
 1657  }
 1658  
 1659  fn deref_multiple<'a>(bcx: &'a Block<'a>,
 1660                        expr: &ast::Expr,
 1661                        datumDatum<Expr>,
 1662                        times: uint)
 1663                        -> DatumBlock<'a, Expr> {
 1664      let mut bcx = bcx;
 1665      let mut datum = datum;
 1666      for i in range(1, times+1) {
 1667          datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
 1668      }
 1669      DatumBlock { bcx: bcx, datum: datum }
 1670  }
 1671  
 1672  fn deref_once<'a>(bcx: &'a Block<'a>,
 1673                    expr: &ast::Expr,
 1674                    datumDatum<Expr>,
 1675                    derefs: uint)
 1676                    -> DatumBlock<'a, Expr> {
 1677      let ccx = bcx.ccx();
 1678  
 1679      debug!("deref_once(expr={}, datum={}, derefs={})",
 1680             expr.repr(bcx.tcx()),
 1681             datum.to_str(ccx),
 1682             derefs);
 1683  
 1684      let mut bcx = bcx;
 1685  
 1686      // Check for overloaded deref.
 1687      let method_call = MethodCall {
 1688          expr_id: expr.id,
 1689          autoderef: derefs as u32
 1690      };
 1691      let method_ty = ccx.tcx.method_map.borrow()
 1692                         .find(&method_call).map(|method| method.ty);
 1693      let datum = match method_ty {
 1694          Some(method_ty) => {
 1695              // Overloaded. Evaluate `trans_overloaded_op`, which will
 1696              // invoke the user's deref() method, which basically
 1697              // converts from the `Shaht<T>` pointer that we have into
 1698              // a `&T` pointer.  We can then proceed down the normal
 1699              // path (below) to dereference that `&T`.
 1700              let datum = if derefs == 0 {
 1701                  datum
 1702              } else {
 1703                  // Always perform an AutoPtr when applying an overloaded auto-deref.
 1704                  unpack_datum!(bcx, auto_ref(bcx, datum, expr))
 1705              };
 1706              let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
 1707                                                                datum, None, None));
 1708              let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
 1709              Datum(val, ref_ty, RvalueExpr(Rvalue(ByValue)))
 1710          }
 1711          None => {
 1712              // Not overloaded. We already have a pointer we know how to deref.
 1713              datum
 1714          }
 1715      };
 1716  
 1717      let r = match ty::get(datum.ty).sty {
 1718          ty::ty_uniq(content_ty) => {
 1719              match ty::get(content_ty).sty {
 1720                  ty::ty_vec(_, None) | ty::ty_str
 1721                      => bcx.tcx().sess.span_bug(expr.span, "unexpected ~[T]"),
 1722                  _ => deref_owned_pointer(bcx, expr, datum, content_ty),
 1723              }
 1724          }
 1725  
 1726          ty::ty_box(content_ty) => {
 1727              let datum = unpack_datum!(
 1728                  bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
 1729              let llptrref = datum.to_llref();
 1730              let llptr = Load(bcx, llptrref);
 1731              let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
 1732              DatumBlock(bcx, Datum(llbody, content_ty, LvalueExpr))
 1733          }
 1734  
 1735          ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
 1736          ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
 1737              match ty::get(content_ty).sty {
 1738                  ty::ty_vec(_, None) | ty::ty_str
 1739                      => bcx.tcx().sess.span_bug(expr.span, "unexpected &[T]"),
 1740                  _ => {
 1741                      assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
 1742  
 1743                      let ptr = datum.to_llscalarish(bcx);
 1744  
 1745                      // Always generate an lvalue datum, even if datum.mode is
 1746                      // an rvalue.  This is because datum.mode is only an
 1747                      // rvalue for non-owning pointers like &T or *T, in which
 1748                      // case cleanup *is* scheduled elsewhere, by the true
 1749                      // owner (or, in the case of *T, by the user).
 1750                      DatumBlock(bcx, Datum(ptr, content_ty, LvalueExpr))
 1751                  }
 1752              }
 1753          }
 1754  
 1755          _ => {
 1756              bcx.tcx().sess.span_bug(
 1757                  expr.span,
 1758                  format!("deref invoked on expr of illegal type {}",
 1759                          datum.ty.repr(bcx.tcx())));
 1760          }
 1761      };
 1762  
 1763      debug!("deref_once(expr={}, derefs={}, result={})",
 1764             expr.id, derefs, r.datum.to_str(ccx));
 1765  
 1766      return r;
 1767  
 1768      fn deref_owned_pointer<'a>(bcx&'a Block<'a>,
 1769                                 expr&ast::Expr,
 1770                                 datumDatum<Expr>,
 1771                                 content_tyty::t)
 1772                                 -> DatumBlock<'a, Expr> {
 1773          /*!
 1774           * We microoptimize derefs of owned pointers a bit here.
 1775           * Basically, the idea is to make the deref of an rvalue
 1776           * result in an rvalue. This helps to avoid intermediate stack
 1777           * slots in the resulting LLVM. The idea here is that, if the
 1778           * `Box<T>` pointer is an rvalue, then we can schedule a *shallow*
 1779           * free of the `Box<T>` pointer, and then return a ByRef rvalue
 1780           * into the pointer. Because the free is shallow, it is legit
 1781           * to return an rvalue, because we know that the contents are
 1782           * not yet scheduled to be freed. The language rules ensure that the
 1783           * contents will be used (or moved) before the free occurs.
 1784           */
 1785  
 1786          match datum.kind {
 1787              RvalueExpr(Rvalue { mode: ByRef }) => {
 1788                  let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
 1789                  let ptr = Load(bcx, datum.val);
 1790                  if !type_is_zero_size(bcx.ccx(), content_ty) {
 1791                      bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange);
 1792                  }
 1793              }
 1794              RvalueExpr(Rvalue { mode: ByValue }) => {
 1795                  let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
 1796                  if !type_is_zero_size(bcx.ccx(), content_ty) {
 1797                      bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange);
 1798                  }
 1799              }
 1800              LvalueExpr => { }
 1801          }
 1802  
 1803          // If we had an rvalue in, we produce an rvalue out.
 1804          let (llptr, kind) = match datum.kind {
 1805              LvalueExpr => {
 1806                  (Load(bcx, datum.val), LvalueExpr)
 1807              }
 1808              RvalueExpr(Rvalue { mode: ByRef }) => {
 1809                  (Load(bcx, datum.val), RvalueExpr(Rvalue(ByRef)))
 1810              }
 1811              RvalueExpr(Rvalue { mode: ByValue }) => {
 1812                  (datum.val, RvalueExpr(Rvalue(ByRef)))
 1813              }
 1814          };
 1815  
 1816          let datum = Datum { ty: content_ty, val: llptr, kind: kind };
 1817          DatumBlock { bcx: bcx, datum: datum }
 1818      }
 1819  }


librustc/middle/trans/expr.rs:1033:4-1033:4 -fn- definition:
 */
fn trans_adt<'a>(
             bcx: &'a Block<'a>,
references:- 2
680:                 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
681:             trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
682:         }
--
1005:         let repr = adt::represent_type(bcx.ccx(), ty);
1006:         trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
1007:     })


librustc/middle/trans/expr.rs:1163:1-1163:1 -fn- definition:
fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
                       box_ty: ty::t,
                       contents: &ast::Expr,
references:- 2
1154:         ast::UnUniq => {
1155:             trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1156:         }


librustc/middle/trans/expr.rs:217:4-217:4 -fn- definition:
    fn auto_slice<'a>(
                  bcx: &'a Block<'a>,
                  expr: &ast::Expr,
references:- 2
270:                           -> DatumBlock<'a, Expr> {
271:         let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
272:         auto_ref(bcx, datum, expr)


librustc/middle/trans/expr.rs:1352:1-1352:1 -fn- definition:
fn trans_lazy_binop<'a>(
                    bcx: &'a Block<'a>,
                    binop_expr: &ast::Expr,
references:- 2
1407:         ast::BiAnd => {
1408:             trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1409:         }
1410:         ast::BiOr => {
1411:             trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1412:         }


librustc/middle/trans/expr.rs:1601:1-1601:1 -fn- definition:
fn trans_assign_op<'a>(
                   bcx: &'a Block<'a>,
                   expr: &ast::Expr,
references:- 2
628:         ast::ExprAssignOp(op, dst, src) => {
629:             trans_assign_op(bcx, expr, op, dst, src)
630:         }
--
757:         ast::ExprAssignOp(op, dst, src) => {
758:             trans_assign_op(bcx, expr, op, dst, src)
759:         }


librustc/middle/trans/expr.rs:900:1-900:1 -fn- definition:
pub fn with_field_tys<R>(tcx: &ty::ctxt,
                         ty: ty::t,
                         node_id_opt: Option<ast::NodeId>,
references:- 7
440:     let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
441:     with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
442:             let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
--
967:     let tcx = bcx.tcx();
968:     with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
969:         let mut need_base = Vec::from_elem(field_tys.len(), true);
librustc/middle/trans/consts.rs:
418:               let (bv, inlineable) = const_expr(cx, base, is_local);
419:               expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
420:                   let ix = ty::field_idx_strict(cx.tcx(), field.name, field_tys);
--
541:               expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
542:                   let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
librustc/middle/trans/base.rs:
691:           let repr = adt::represent_type(cx.ccx(), t);
692:           expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| {
693:               for (i, field_ty) in field_tys.iter().enumerate() {
librustc/middle/trans/_match.rs:
1504:             let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
1505:             expr::with_field_tys(tcx, pat_ty, Some(pat_id), |discr, field_tys| {
1506:                 let rec_vals = rec_fields.iter().map(|field_name| {
--
2244:             let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
2245:             expr::with_field_tys(tcx, pat_ty, Some(pat.id), |discr, field_tys| {
2246:                 for f in fields.iter() {


librustc/middle/trans/expr.rs:1435:1-1435:1 -fn- definition:
fn trans_overloaded_op<'a, 'b>(
                       bcx: &'a Block<'a>,
                       expr: &ast::Expr,
references:- 4
1705:             };
1706:             let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
1707:                                                               datum, None, None));


librustc/middle/trans/expr.rs:308:1-308:1 -fn- definition:
fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
                        expr: &ast::Expr)
                        -> DatumBlock<'a, Expr> {
references:- 2
122:         ty::LvalueExpr | ty::RvalueDatumExpr => {
123:             trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
124:         }
--
151:     fcx.push_ast_cleanup_scope(expr.id);
152:     let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
153:     let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));


librustc/middle/trans/expr.rs:96:1-96:1 -fn- definition:
pub fn trans_into<'a>(bcx: &'a Block<'a>,
                      expr: &ast::Expr,
                      dest: Dest)
references:- 18
581:         ast::ExprParen(e) => {
582:             trans_into(bcx, e, Ignore)
583:         }
--
1051:                 // FIXME #7261: this moves entire base, not just certain fields
1052:                 bcx = trans_into(bcx, sbi.expr, Ignore);
1053:             }
--
1067:         let e_ty = expr_ty_adjusted(bcx, e);
1068:         bcx = trans_into(bcx, e, SaveIn(dest));
1069:         fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
--
1207:                             bx, cleanup::HeapManaged);
1208:     let bcx = trans_into(bcx, contents, SaveIn(body));
1209:     fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
librustc/middle/trans/_match.rs:
2000:                         bcx, pat.id, path, BindLocal, var_scope, (),
2001:                         |(), bcx, v, _| expr::trans_into(bcx, init_expr,
2002:                                                          expr::SaveIn(v)));
librustc/middle/trans/tvec.rs:
373:                 Ignore => {
374:                     return expr::trans_into(bcx, element, Ignore);
375:                 }
librustc/middle/trans/controlflow.rs:
154:                 Some(elexpr) => {
155:                     bcx = expr::trans_into(bcx, elexpr, dest);
156:                     debuginfo::clear_source_location(bcx.fcx);
--
328:         Some(x) => {
329:             bcx = expr::trans_into(bcx, x, dest);
330:         }


librustc/middle/trans/expr.rs:82:16-82:16 -enum- definition:
pub enum Dest {
    SaveIn(ValueRef),
    Ignore,
references:- 27
645:                                    expr: &ast::Expr,
646:                                    dest: Dest)
647:                                    -> &'a Block<'a> {
--
1441:                        rhs: Option<(Datum<Expr>, ast::NodeId)>,
1442:                        dest: Option<Dest>)
1443:                        -> Result<'a> {
librustc/middle/trans/_match.rs:
1826:                    arms: &[ast::Arm],
1827:                    dest: Dest)
1828:                    -> &'a Block<'a> {
--
1876:                          arms: &[ast::Arm],
1877:                          dest: Dest) -> &'a Block<'a> {
1878:     let _icx = push_ctxt("match::trans_match_inner");
librustc/middle/trans/closure.rs:
317:                      id: ast::NodeId,
318:                      dest: expr::Dest)
319:                      -> &'a Block<'a> {
librustc/middle/trans/tvec.rs:
118:                           content_expr: &ast::Expr,
119:                           dest: expr::Dest)
120:                           -> &'a Block<'a> {
--
308:                      content_expr: &ast::Expr,
309:                      dest: Dest)
310:                      -> &'a Block<'a> {
librustc/middle/trans/meth.rs:
526:                             id: ast::NodeId,
527:                             dest: expr::Dest)
528:                             -> &'a Block<'a> {
librustc/middle/trans/controlflow.rs:
86:                        b: &ast::Block,
87:                        mut dest: expr::Dest)
88:                        -> &'a Block<'a> {
--
124:                     els: Option<@ast::Expr>,
125:                     dest: expr::Dest)
126:                     -> &'a Block<'a> {
librustc/middle/trans/datum.rs:
408:                              bcx: &'a Block<'a>,
409:                              dest: expr::Dest,
410:                              expr_id: ast::NodeId)
--
673:     pub fn store_to_dest(self,
674:                          dest: expr::Dest,
675:                          expr_id: ast::NodeId) -> &'a Block<'a> {
librustc/middle/trans/callee.rs:
477:                          args: CallArgs,
478:                          dest: expr::Dest)
479:                          -> &'a Block<'a> {
--
498:                        args: &[ValueRef],
499:                        dest: Option<expr::Dest>)
500:                        -> Result<'a> {
--
527:                         args: CallArgs,
528:                         dest: Option<expr::Dest>)
529:                         -> Result<'a> {
librustc/middle/trans/expr.rs:
83: pub enum Dest {


librustc/middle/trans/expr.rs:1495:16-1495:16 -enum- definition:
pub enum cast_kind {
    cast_pointer,
    cast_integral,
references:- 4
1496: pub enum cast_kind {
--
1504: pub fn cast_type_kind(t: ty::t) -> cast_kind {
1505:     match ty::get(t).sty {


librustc/middle/trans/expr.rs:569:1-569:1 -fn- definition:
fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
                                    expr: &ast::Expr)
                                    -> &'a Block<'a> {
references:- 2
333:         ty::RvalueStmtExpr => {
334:             bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
335:             nil(bcx, expr_ty(bcx, expr))


librustc/middle/trans/expr.rs:1192:1-1192:1 -fn- definition:
fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
                          box_ty: ty::t,
                          contents: &ast::Expr,
references:- 2
1232:     let contents_datum = unpack_datum!(bcx, trans_managed_expr(bcx,
1233:                                                                box_ty,


librustc/middle/trans/expr.rs:135:1-135:1 -fn- definition:
pub fn trans<'a>(bcx: &'a Block<'a>,
                 expr: &ast::Expr)
                 -> DatumBlock<'a, Expr> {
references:- 30
librustc/middle/trans/_match.rs:
librustc/middle/trans/tvec.rs:
librustc/middle/trans/meth.rs:
librustc/middle/trans/asm.rs:
librustc/middle/trans/controlflow.rs:
librustc/middle/trans/callee.rs:


librustc/middle/trans/expr.rs:1457:1-1457:1 -fn- definition:
fn int_cast(bcx: &Block,
            lldsttype: Type,
            llsrctype: Type,
references:- 2
1583:             match k_out {
1584:                 cast_integral => int_cast(bcx, ll_t_out,
1585:                                           val_ty(lldiscrim_a),


librustc/middle/trans/expr.rs:288:1-288:1 -fn- definition:
pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
                           expr: &ast::Expr,
                           name: &str)
references:- 9
461:     let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
--
1075:         // And, would it ever be reasonable to be here with discr != 0?
1076:         let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base.expr, "base"));
1077:         for &(i, t) in base.fields.iter() {
--
1218:     let mut bcx = bcx;
1219:     let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1220:     let ty = expr_ty(bcx, expr);
--
1617:     // Evaluate LHS (destination), which should be an lvalue
1618:     let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1619:     assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
librustc/middle/trans/_match.rs:
2009:             let init_datum =
2010:                 unpack_datum!(bcx, expr::trans_to_lvalue(bcx, init_expr, "let"));
2011:             if ty::type_is_bot(expr_ty(bcx, init_expr)) {
librustc/middle/trans/controlflow.rs:
78:     if ty::type_needs_drop(cx.tcx(), ty) {
79:         expr::trans_to_lvalue(cx, e, "stmt").bcx
80:     } else {
librustc/middle/trans/expr.rs:
439:     let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
440:     let repr = adt::represent_type(bcx.ccx(), base_datum.ty);


librustc/middle/trans/expr.rs:1017:4-1017:4 -struct- definition:
 */
struct StructBaseInfo {
    /// The base expression; will be evaluated after all explicit fields.
references:- 2
993:                 }
994:                 Some(StructBaseInfo {expr: base_expr,
995:                                      fields: leftovers })
--
1038:              fields: &[(uint, @ast::Expr)],
1039:              optbase: Option<StructBaseInfo>,
1040:              dest: Dest)


librustc/middle/trans/expr.rs:1250:22-1250:22 -fn- definition:
// and the other not.
fn trans_eager_binop<'a>(
                     bcx: &'a Block<'a>,
references:- 2
1429:             let rhs = rhs_datum.to_llscalarish(bcx);
1430:             trans_eager_binop(bcx, expr, binop_ty, op,
1431:                               lhs_ty, lhs, rhs_ty, rhs)
--
1629:     let result_datum = unpack_datum!(
1630:         bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1631:                                dst_ty, dst, rhs_ty, rhs));


librustc/middle/trans/expr.rs:643:1-643:1 -fn- definition:
fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
                                   expr: &ast::Expr,
                                   dest: Dest)
references:- 3
340:             if type_is_zero_size(bcx.ccx(), ty) {
341:                 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
342:                 nil(bcx, ty)
--
344:                 let scratch = rvalue_scratch_datum(bcx, ty, "");
345:                 bcx = trans_rvalue_dps_unadjusted(
346:                     bcx, expr, SaveIn(scratch.val));


librustc/middle/trans/expr.rs:1634:1-1634:1 -fn- definition:
fn auto_ref<'a>(bcx: &'a Block<'a>,
                datum: Datum<Expr>,
                expr: &ast::Expr)
references:- 3
1703:                 // Always perform an AutoPtr when applying an overloaded auto-deref.
1704:                 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
1705:             };


librustc/middle/trans/expr.rs:884:4-884:4 -fn- definition:
    fn take_local<'a>(bcx: &'a Block<'a>,
                      table: &NodeMap<Datum<Lvalue>>,
                      nid: ast::NodeId)
references:- 2
875:         ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
876:             take_local(bcx, &*bcx.fcx.lllocals.borrow(), nid)
877:         }


librustc/middle/trans/expr.rs:849:1-849:1 -fn- definition:
pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
                           def: ast::Def)
                           -> Datum<Lvalue> {
references:- 2
librustc/middle/trans/closure.rs:
241:     for freevar in freevars.iter() {
242:         let datum = expr::trans_local_var(bcx, freevar.def);
243:         env_vals.push(EnvValue {action: freevar_mode, datum: datum});
librustc/middle/trans/expr.rs:
564:         _ => {
565:             DatumBlock(bcx, trans_local_var(bcx, def).to_expr_datum())
566:         }


librustc/middle/trans/expr.rs:1671:1-1671:1 -fn- definition:
fn deref_once<'a>(bcx: &'a Block<'a>,
                  expr: &ast::Expr,
                  datum: Datum<Expr>,
references:- 2
1666:     for i in range(1, times+1) {
1667:         datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
1668:     }


librustc/middle/trans/expr.rs:365:4-365:4 -fn- definition:
    fn nil<'a>(bcx: &'a Block<'a>, ty: ty::t) -> DatumBlock<'a, Expr> {
        let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
        let datum = immediate_rvalue(llval, ty);
references:- 2
334:             bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
335:             nil(bcx, expr_ty(bcx, expr))
336:         }
--
341:                 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
342:                 nil(bcx, ty)
343:             } else {


librustc/middle/trans/expr.rs:1503:1-1503:1 -fn- definition:
pub fn cast_type_kind(t: ty::t) -> cast_kind {
    match ty::get(t).sty {
        ty::ty_char        => cast_integral,
references:- 5
1531:     let t_out = node_id_type(bcx, id);
1532:     let k_in = cast_type_kind(t_in);
1533:     let k_out = cast_type_kind(t_out);
1534:     let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
librustc/middle/trans/consts.rs:
471:             let (v, inlineable) = const_expr(cx, base, is_local);
472:             return (match (expr::cast_type_kind(basety),
473:                            expr::cast_type_kind(ety)) {
--
497:                 let iv = C_integral(cx.int_type, discr, false);
498:                 let ety_cast = expr::cast_type_kind(ety);
499:                 match ety_cast {