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