]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/expr.rs
0da1a9acef21225856ae3b63f03fbcf0b9f20f5e
[rust.git] / src / librustc / middle / trans / expr.rs
1 // Copyright 2012 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
13 # Translation of expressions.
14
15 ## Recommended entry point
16
17 If you wish to translate an expression, the preferred way to do
18 so is to use:
19
20     expr::trans_into(block, expr, Dest) -> block
21
22 This will generate code that evaluates `expr`, storing the result into
23 `Dest`, which must either be the special flag ignore (throw the result
24 away) or be a pointer to memory of the same type/size as the
25 expression.  It returns the resulting basic block.  This form will
26 handle all automatic adjustments and moves for you.
27
28 ## Translation to a datum
29
30 In some cases, `trans_into()` is too narrow of an interface.
31 Generally this occurs either when you know that the result value is
32 going to be a scalar, or when you need to evaluate the expression into
33 some memory location so you can go and inspect it (e.g., assignments,
34 `match` expressions, the `&` operator).
35
36 In such cases, you want the following function:
37
38     trans_to_datum(block, expr) -> DatumBlock
39
40 This function generates code to evaluate the expression and return a
41 `Datum` describing where the result is to be found.  This function
42 tries to return its result in the most efficient way possible, without
43 introducing extra copies or sacrificing information.  Therefore, for
44 lvalue expressions, you always get a by-ref `Datum` in return that
45 points at the memory for this lvalue (almost, see [1]).  For rvalue
46 expressions, we will return a by-value `Datum` whenever possible, but
47 it is often necessary to allocate a stack slot, store the result of
48 the rvalue in there, and then return a pointer to the slot (see the
49 discussion later on about the different kinds of rvalues).
50
51 NB: The `trans_to_datum()` function does perform adjustments, but
52 since it returns a pointer to the value "in place" it does not handle
53 any moves that may be relevant.  If you are transing an expression
54 whose result should be moved, you should either use the Datum methods
55 `move_to()` (for unconditional moves) or `store_to()` (for moves
56 conditioned on the type of the expression) at some point.
57
58 ## Translating local variables
59
60 `trans_local_var()` can be used to trans a ref to a local variable
61 that is not an expression.  This is needed for captures.
62
63 ## Ownership and cleanups
64
65 The current system for cleanups associates required cleanups with
66 block contexts.  Block contexts are structured into a tree that
67 resembles the code itself.  Not every block context has cleanups
68 associated with it, only those blocks that have a kind of
69 `block_scope`.  See `common::block_kind` for more details.
70
71 If you invoke `trans_into()`, no cleanup is scheduled for you.  The
72 value is written into the given destination and is assumed to be owned
73 by that destination.
74
75 When you invoke `trans_to_datum()` on an rvalue, the resulting
76 datum/value will have an appropriate cleanup scheduled for the
77 innermost cleanup scope.  If you later use `move_to()` or
78 `drop_val()`, this cleanup will be canceled.
79
80 During the evaluation of an expression, temporary cleanups are created
81 and later canceled.  These represent intermediate or partial results
82 which must be cleaned up in the event of task failure.
83
84 ## Implementation details
85
86 We divide expressions into three categories, based on how they are most
87 naturally implemented:
88
89 1. Lvalues
90 2. Datum rvalues
91 3. DPS rvalues
92 4. Statement rvalues
93
94 Lvalues always refer to user-assignable memory locations.
95 Translating those always results in a by-ref datum; this introduces
96 no inefficiencies into the generated code, because all lvalues are
97 naturally addressable.
98
99 Datum rvalues are rvalues that always generate datums as a result.
100 These are generally scalar results, such as `a+b` where `a` and `b`
101 are integers.
102
103 DPS rvalues are rvalues that, when translated, must be given a
104 memory location to write into (or the Ignore flag).  These are
105 generally expressions that produce structural results that are
106 larger than one word (e.g., a struct literal), but also expressions
107 (like `if`) that involve control flow (otherwise we'd have to
108 generate phi nodes).
109
110 Finally, statement rvalues are rvalues that always produce a nil
111 return type, such as `while` loops or assignments (`a = b`).
112
113 ## Caveats
114
115 [1] Actually, some lvalues are only stored by value and not by
116 reference.  An example (as of this writing) would be immutable
117 arguments or pattern bindings of immediate type.  However, mutable
118 lvalues are *never* stored by value.
119
120 */
121
122 use core::prelude::*;
123
124 use back::abi;
125 use lib;
126 use lib::llvm::{ValueRef, TypeRef, llvm, True};
127 use middle::borrowck::root_map_key;
128 use middle::trans::_match;
129 use middle::trans::adt;
130 use middle::trans::base;
131 use middle::trans::base::*;
132 use middle::trans::build::*;
133 use middle::trans::callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
134 use middle::trans::callee;
135 use middle::trans::closure;
136 use middle::trans::common::*;
137 use middle::trans::consts;
138 use middle::trans::controlflow;
139 use middle::trans::datum::*;
140 use middle::trans::debuginfo;
141 use middle::trans::inline;
142 use middle::trans::machine;
143 use middle::trans::meth;
144 use middle::trans::tvec;
145 use middle::trans::type_of;
146 use middle::ty;
147 use middle::ty::struct_mutable_fields;
148 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
149                  AutoDerefRef, AutoAddEnv};
150 use util::common::indenter;
151 use util::ppaux::ty_to_str;
152
153 use core::hashmap::linear::LinearMap;
154 use syntax::print::pprust::{expr_to_str};
155 use syntax::ast;
156 use syntax::codemap;
157
158 // Destinations
159
160 // These are passed around by the code generating functions to track the
161 // destination of a computation's value.
162
163 pub enum Dest {
164     SaveIn(ValueRef),
165     Ignore,
166 }
167
168 pub impl Dest {
169     fn to_str(&self, ccx: @CrateContext) -> ~str {
170         match *self {
171             SaveIn(v) => fmt!("SaveIn(%s)", val_str(ccx.tn, v)),
172             Ignore => ~"Ignore"
173         }
174     }
175 }
176
177 impl cmp::Eq for Dest {
178     fn eq(&self, other: &Dest) -> bool {
179         match ((*self), (*other)) {
180             (SaveIn(e0a), SaveIn(e0b)) => e0a == e0b,
181             (Ignore, Ignore) => true,
182             (SaveIn(*), _) => false,
183             (Ignore, _) => false,
184         }
185     }
186     fn ne(&self, other: &Dest) -> bool { !(*self).eq(other) }
187 }
188
189 fn drop_and_cancel_clean(bcx: block, dat: Datum) -> block {
190     let bcx = dat.drop_val(bcx);
191     dat.cancel_clean(bcx);
192     return bcx;
193 }
194
195 pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
196     debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
197     return match bcx.tcx().adjustments.find(&expr.id) {
198         None => {
199             trans_to_datum_unadjusted(bcx, expr)
200         }
201         Some(&@AutoAddEnv(*)) => {
202             let mut bcx = bcx;
203             let mut datum = unpack_datum!(bcx, {
204                 trans_to_datum_unadjusted(bcx, expr)
205             });
206             add_env(bcx, expr, datum)
207         }
208         Some(&@AutoDerefRef(ref adj)) => {
209             let mut bcx = bcx;
210             let mut datum = unpack_datum!(bcx, {
211                 trans_to_datum_unadjusted(bcx, expr)
212             });
213
214             if adj.autoderefs > 0 {
215                 let DatumBlock { bcx: new_bcx, datum: new_datum } =
216                     datum.autoderef(bcx, expr.id, adj.autoderefs);
217                 datum = new_datum;
218                 bcx = new_bcx;
219             }
220
221             datum = match adj.autoref {
222                 None => datum,
223                 Some(ref autoref) => {
224                     match autoref.kind {
225                         AutoPtr => {
226                             unpack_datum!(bcx, auto_ref(bcx, datum))
227                         }
228                         AutoBorrowVec => {
229                             unpack_datum!(bcx, auto_slice(bcx, datum))
230                         }
231                         AutoBorrowVecRef => {
232                             unpack_datum!(bcx, auto_slice_and_ref(bcx, datum))
233                         }
234                         AutoBorrowFn => {
235                             // currently, all closure types are
236                             // represented precisely the same, so no
237                             // runtime adjustment is required:
238                             datum
239                         }
240                     }
241                 }
242             };
243
244             debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
245
246             return DatumBlock {bcx: bcx, datum: datum};
247         }
248     };
249
250     fn auto_ref(bcx: block, datum: Datum) -> DatumBlock {
251         DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
252     }
253
254     fn auto_slice(bcx: block, datum: Datum) -> DatumBlock {
255         // This is not the most efficient thing possible; since slices
256         // are two words it'd be better if this were compiled in
257         // 'dest' mode, but I can't find a nice way to structure the
258         // code and keep it DRY that accommodates that use case at the
259         // moment.
260
261         let tcx = bcx.tcx();
262         let unit_ty = ty::sequence_element_type(tcx, datum.ty);
263         let (base, len) = datum.get_base_and_len(bcx);
264
265         // this type may have a different region/mutability than the
266         // real one, but it will have the same runtime representation
267         let slice_ty = ty::mk_evec(tcx,
268                                    ty::mt { ty: unit_ty, mutbl: ast::m_imm },
269                                    ty::vstore_slice(ty::re_static));
270
271         let scratch = scratch_datum(bcx, slice_ty, false);
272         Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
273         Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
274         DatumBlock {bcx: bcx, datum: scratch}
275     }
276
277     fn add_env(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
278         // This is not the most efficient thing possible; since closures
279         // are two words it'd be better if this were compiled in
280         // 'dest' mode, but I can't find a nice way to structure the
281         // code and keep it DRY that accommodates that use case at the
282         // moment.
283
284         let tcx = bcx.tcx();
285         let closure_ty = expr_ty_adjusted(bcx, expr);
286         debug!("add_env(closure_ty=%s)", ty_to_str(tcx, closure_ty));
287         let scratch = scratch_datum(bcx, closure_ty, false);
288         let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
289         fail_unless!(datum.appropriate_mode() == ByValue);
290         Store(bcx, datum.to_appropriate_llval(bcx), llfn);
291         let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
292         Store(bcx, base::null_env_ptr(bcx), llenv);
293         DatumBlock {bcx: bcx, datum: scratch}
294     }
295
296     fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock {
297         let DatumBlock { bcx, datum } = auto_slice(bcx, datum);
298         auto_ref(bcx, datum)
299     }
300 }
301
302 pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
303     if bcx.tcx().adjustments.contains_key(&expr.id) {
304         // use trans_to_datum, which is mildly less efficient but
305         // which will perform the adjustments:
306         let datumblock = trans_to_datum(bcx, expr);
307         return match dest {
308             Ignore => datumblock.bcx,
309             SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
310         };
311     }
312
313     let ty = expr_ty(bcx, expr);
314
315     debug!("trans_into_unadjusted(expr=%s, dest=%s)",
316            bcx.expr_to_str(expr),
317            dest.to_str(bcx.ccx()));
318     let _indenter = indenter();
319
320     debuginfo::update_source_pos(bcx, expr.span);
321
322     let dest = {
323         if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
324             Ignore
325         } else {
326             dest
327         }
328     };
329
330     let kind = bcx.expr_kind(expr);
331     debug!("expr kind = %?", kind);
332     return match kind {
333         ty::LvalueExpr => {
334             let datumblock = trans_lvalue_unadjusted(bcx, expr);
335             match dest {
336                 Ignore => datumblock.bcx,
337                 SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
338             }
339         }
340         ty::RvalueDatumExpr => {
341             let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
342             match dest {
343                 Ignore => datumblock.drop_val(),
344
345                 // NB: We always do `move_to()` regardless of the
346                 // moves_map because we're processing an rvalue
347                 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
348             }
349         }
350         ty::RvalueDpsExpr => {
351             trans_rvalue_dps_unadjusted(bcx, expr, dest)
352         }
353         ty::RvalueStmtExpr => {
354             trans_rvalue_stmt_unadjusted(bcx, expr)
355         }
356     };
357 }
358
359 fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
360     /*!
361      *
362      * Translates an lvalue expression, always yielding a by-ref
363      * datum.  Generally speaking you should call trans_to_datum()
364      * instead, but sometimes we call trans_lvalue() directly as a
365      * means of asserting that a particular expression is an lvalue. */
366
367     return match bcx.tcx().adjustments.find(&expr.id) {
368         None => trans_lvalue_unadjusted(bcx, expr),
369         Some(_) => {
370             bcx.sess().span_bug(
371                 expr.span,
372                 fmt!("trans_lvalue() called on an expression \
373                       with adjustments"));
374         }
375     };
376 }
377
378 fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
379     /*!
380      *
381      * Translates an expression into a datum.  If this expression
382      * is an rvalue, this will result in a temporary value being
383      * created.  If you already know where the result should be stored,
384      * you should use `trans_into()` instead. */
385
386     let mut bcx = bcx;
387
388     debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
389     let _indenter = indenter();
390
391     debuginfo::update_source_pos(bcx, expr.span);
392
393     match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
394         ty::LvalueExpr => {
395             return trans_lvalue_unadjusted(bcx, expr);
396         }
397
398         ty::RvalueDatumExpr => {
399             let datum = unpack_datum!(bcx, {
400                 trans_rvalue_datum_unadjusted(bcx, expr)
401             });
402             datum.add_clean(bcx);
403             return DatumBlock {bcx: bcx, datum: datum};
404         }
405
406         ty::RvalueStmtExpr => {
407             bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
408             return nil(bcx, expr_ty(bcx, expr));
409         }
410
411         ty::RvalueDpsExpr => {
412             let ty = expr_ty(bcx, expr);
413             if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
414                 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
415                 return nil(bcx, ty);
416             } else {
417                 let scratch = scratch_datum(bcx, ty, false);
418                 bcx = trans_rvalue_dps_unadjusted(
419                     bcx, expr, SaveIn(scratch.val));
420
421                 // Note: this is not obviously a good idea.  It causes
422                 // immediate values to be loaded immediately after a
423                 // return from a call or other similar expression,
424                 // which in turn leads to alloca's having shorter
425                 // lifetimes and hence larger stack frames.  However,
426                 // in turn it can lead to more register pressure.
427                 // Still, in practice it seems to increase
428                 // performance, since we have fewer problems with
429                 // morestack churn.
430                 let scratch = scratch.to_appropriate_datum(bcx);
431
432                 scratch.add_clean(bcx);
433                 return DatumBlock {bcx: bcx, datum: scratch};
434             }
435         }
436     }
437
438     fn nil(bcx: block, ty: ty::t) -> DatumBlock {
439         let datum = immediate_rvalue(C_nil(), ty);
440         DatumBlock {bcx: bcx, datum: datum}
441     }
442 }
443
444 fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
445     let _icx = bcx.insn_ctxt("trans_rvalue_datum_unadjusted");
446
447     trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
448
449     match expr.node {
450         ast::expr_path(_) => {
451             return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
452         }
453         ast::expr_vstore(contents, ast::expr_vstore_box) |
454         ast::expr_vstore(contents, ast::expr_vstore_mut_box) => {
455             return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
456                                                       expr, contents);
457         }
458         ast::expr_vstore(contents, ast::expr_vstore_uniq) => {
459             let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
460             return tvec::trans_uniq_or_managed_vstore(bcx, heap,
461                                                       expr, contents);
462         }
463         ast::expr_lit(lit) => {
464             return trans_immediate_lit(bcx, expr, *lit);
465         }
466         ast::expr_binary(op, lhs, rhs) => {
467             // if overloaded, would be RvalueDpsExpr
468             fail_unless!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
469
470             return trans_binary(bcx, expr, op, lhs, rhs);
471         }
472         ast::expr_unary(op, x) => {
473             return trans_unary_datum(bcx, expr, op, x);
474         }
475         ast::expr_addr_of(_, x) => {
476             return trans_addr_of(bcx, expr, x);
477         }
478         ast::expr_cast(val, _) => {
479             return trans_imm_cast(bcx, val, expr.id);
480         }
481         ast::expr_paren(e) => {
482             return trans_rvalue_datum_unadjusted(bcx, e);
483         }
484         _ => {
485             bcx.tcx().sess.span_bug(
486                 expr.span,
487                 fmt!("trans_rvalue_datum_unadjusted reached \
488                       fall-through case: %?",
489                      expr.node));
490         }
491     }
492 }
493
494 fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
495     let mut bcx = bcx;
496     let _icx = bcx.insn_ctxt("trans_rvalue_stmt");
497
498     trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
499
500     match expr.node {
501         ast::expr_break(label_opt) => {
502             return controlflow::trans_break(bcx, label_opt);
503         }
504         ast::expr_again(label_opt) => {
505             return controlflow::trans_cont(bcx, label_opt);
506         }
507         ast::expr_ret(ex) => {
508             return controlflow::trans_ret(bcx, ex);
509         }
510         ast::expr_log(_, lvl, a) => {
511             return controlflow::trans_log(expr, lvl, bcx, a);
512         }
513         ast::expr_while(cond, ref body) => {
514             return controlflow::trans_while(bcx, cond, body);
515         }
516         ast::expr_loop(ref body, opt_label) => {
517             return controlflow::trans_loop(bcx, body, opt_label);
518         }
519         ast::expr_assign(dst, src) => {
520             let src_datum = unpack_datum!(
521                 bcx, trans_to_datum(bcx, src));
522             let dst_datum = unpack_datum!(
523                 bcx, trans_lvalue(bcx, dst));
524             return src_datum.store_to_datum(
525                 bcx, src.id, DROP_EXISTING, dst_datum);
526         }
527         ast::expr_swap(dst, src) => {
528             let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
529             let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src));
530
531             // If the source and destination are the same, then don't swap.
532             // Avoids performing an overlapping memcpy
533             let dst_datum_ref = dst_datum.to_ref_llval(bcx);
534             let src_datum_ref = src_datum.to_ref_llval(bcx);
535             let cmp = ICmp(bcx, lib::llvm::IntEQ,
536                            src_datum_ref,
537                            dst_datum_ref);
538
539             let swap_cx = base::sub_block(bcx, ~"swap");
540             let next_cx = base::sub_block(bcx, ~"next");
541
542             CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb);
543
544             let scratch = scratch_datum(swap_cx, dst_datum.ty, false);
545
546             let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch);
547             let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum);
548             let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum);
549
550             Br(swap_cx, next_cx.llbb);
551
552             return next_cx;
553         }
554         ast::expr_assign_op(op, dst, src) => {
555             return trans_assign_op(bcx, expr, op, dst, src);
556         }
557         ast::expr_paren(a) => {
558             return trans_rvalue_stmt_unadjusted(bcx, a);
559         }
560         ast::expr_inline_asm(asm, ref ins, ref outs,
561                              clobs, volatile, alignstack) => {
562             let mut constraints = ~[];
563             let mut cleanups = ~[];
564             let mut aoutputs = ~[];
565
566             let outputs = do outs.map |&(c, out)| {
567                 constraints.push(copy *c);
568
569                 let aoutty = ty::arg {
570                     mode: ast::expl(ast::by_copy),
571                     ty: expr_ty(bcx, out)
572                 };
573                 aoutputs.push(unpack_result!(bcx, {
574                     callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups,
575                                            None, callee::DontAutorefArg)
576                     }));
577
578                 let e = match out.node {
579                     ast::expr_addr_of(_, e) => e,
580                     _ => fail!(~"Expression must be addr of")
581                 };
582
583                 let outty = ty::arg {
584                     mode: ast::expl(ast::by_copy),
585                     ty: expr_ty(bcx, e)
586                 };
587
588                 unpack_result!(bcx, {
589                     callee::trans_arg_expr(bcx, outty, e, &mut cleanups,
590                                            None, callee::DontAutorefArg)
591                 })
592
593             };
594
595             for cleanups.each |c| {
596                 revoke_clean(bcx, *c);
597             }
598             cleanups = ~[];
599
600             let inputs = do ins.map |&(c, in)| {
601                 constraints.push(copy *c);
602
603                 let inty = ty::arg {
604                     mode: ast::expl(ast::by_copy),
605                     ty: expr_ty(bcx, in)
606                 };
607
608                 unpack_result!(bcx, {
609                     callee::trans_arg_expr(bcx, inty, in, &mut cleanups,
610                                            None, callee::DontAutorefArg)
611                 })
612
613             };
614
615             for cleanups.each |c| {
616                 revoke_clean(bcx, *c);
617             }
618
619             let mut constraints = str::connect(constraints, ",");
620
621             // Add the clobbers
622             if *clobs != ~"" {
623                 if constraints == ~"" {
624                     constraints += *clobs;
625                 } else {
626                     constraints += ~"," + *clobs;
627                 }
628             } else {
629                 constraints += *clobs;
630             }
631
632             debug!("Asm Constraints: %?", constraints);
633
634             let output = if outputs.len() == 0 {
635                 T_void()
636             } else if outputs.len() == 1 {
637                 val_ty(outputs[0])
638             } else {
639                 T_struct(outputs.map(|o| val_ty(*o)))
640             };
641
642             let r = do str::as_c_str(*asm) |a| {
643                 do str::as_c_str(constraints) |c| {
644                     InlineAsmCall(bcx, a, c, inputs, output, volatile,
645                                   alignstack, lib::llvm::AD_ATT)
646                 }
647             };
648
649             if outputs.len() == 1 {
650                 let op = PointerCast(bcx, aoutputs[0],
651                                      T_ptr(val_ty(outputs[0])));
652                 Store(bcx, r, op);
653             } else {
654                 for aoutputs.eachi |i, o| {
655                     let v = ExtractValue(bcx, r, i);
656                     let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
657                     Store(bcx, v, op);
658                 }
659             }
660
661             return bcx;
662         }
663         _ => {
664             bcx.tcx().sess.span_bug(
665                 expr.span,
666                 fmt!("trans_rvalue_stmt_unadjusted reached \
667                       fall-through case: %?",
668                      expr.node));
669         }
670     };
671 }
672
673 fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
674                                dest: Dest) -> block {
675     let mut bcx = bcx;
676     let _icx = bcx.insn_ctxt("trans_rvalue_dps_unadjusted");
677     let tcx = bcx.tcx();
678
679     trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
680
681     match expr.node {
682         ast::expr_paren(e) => {
683             return trans_rvalue_dps_unadjusted(bcx, e, dest);
684         }
685         ast::expr_path(_) => {
686             return trans_def_dps_unadjusted(bcx, expr,
687                                             bcx.def(expr.id), dest);
688         }
689         ast::expr_if(cond, ref thn, els) => {
690             return controlflow::trans_if(bcx, cond, thn, els, dest);
691         }
692         ast::expr_match(discr, ref arms) => {
693             return _match::trans_match(bcx, expr, discr, /*bad*/copy *arms,
694                                        dest);
695         }
696         ast::expr_block(ref blk) => {
697             return do base::with_scope(bcx, blk.info(),
698                                        ~"block-expr body") |bcx| {
699                 controlflow::trans_block(bcx, blk, dest)
700             };
701         }
702         ast::expr_struct(_, ref fields, base) => {
703             return trans_rec_or_struct(bcx, (*fields), base, expr.id, dest);
704         }
705         ast::expr_tup(ref args) => {
706             let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
707             return trans_adt(bcx, repr, 0, args.mapi(|i, arg| (i, *arg)),
708                              None, dest);
709         }
710         ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => {
711             return tvec::trans_lit_str(bcx, expr, s, dest);
712         }
713         ast::expr_vstore(contents, ast::expr_vstore_slice) |
714         ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
715             return tvec::trans_slice_vstore(bcx, expr, contents, dest);
716         }
717         ast::expr_vstore(contents, ast::expr_vstore_fixed(_)) => {
718             return tvec::trans_fixed_vstore(bcx, expr, contents, dest);
719         }
720         ast::expr_vec(*) | ast::expr_repeat(*) => {
721             return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
722         }
723         ast::expr_fn_block(ref decl, ref body) => {
724             let expr_ty = expr_ty(bcx, expr);
725             let sigil = ty::ty_closure_sigil(expr_ty);
726             debug!("translating fn_block %s with type %s",
727                    expr_to_str(expr, tcx.sess.intr()),
728                    ty_to_str(tcx, expr_ty));
729             return closure::trans_expr_fn(bcx, sigil, decl, body,
730                                           expr.id, expr.id,
731                                           None, dest);
732         }
733         ast::expr_loop_body(blk) => {
734             let expr_ty = expr_ty(bcx, expr);
735             let sigil = ty::ty_closure_sigil(expr_ty);
736             match blk.node {
737                 ast::expr_fn_block(ref decl, ref body) => {
738                     return closure::trans_expr_fn(bcx, sigil,
739                                                   decl, body,
740                                                   expr.id, blk.id,
741                                                   Some(None), dest);
742                 }
743                 _ => {
744                     bcx.sess().impossible_case(
745                         expr.span,
746                         "loop_body has the wrong kind of contents")
747                 }
748             }
749         }
750         ast::expr_do_body(blk) => {
751             return trans_into(bcx, blk, dest);
752         }
753         ast::expr_copy(a) => {
754             return trans_into(bcx, a, dest);
755         }
756         ast::expr_call(f, ref args, _) => {
757             return callee::trans_call(
758                 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
759         }
760         ast::expr_method_call(rcvr, _, _, ref args, _) => {
761             return callee::trans_method_call(bcx,
762                                              expr,
763                                              rcvr,
764                                              callee::ArgExprs(*args),
765                                              dest);
766         }
767         ast::expr_binary(_, lhs, rhs) => {
768             // if not overloaded, would be RvalueDatumExpr
769             return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest);
770         }
771         ast::expr_unary(_, subexpr) => {
772             // if not overloaded, would be RvalueDatumExpr
773             return trans_overloaded_op(bcx, expr, subexpr, ~[], dest);
774         }
775         ast::expr_index(base, idx) => {
776             // if not overloaded, would be RvalueDatumExpr
777             return trans_overloaded_op(bcx, expr, base, ~[idx], dest);
778         }
779         ast::expr_cast(val, _) => {
780             match ty::get(node_id_type(bcx, expr.id)).sty {
781                 ty::ty_trait(_, _, store) => {
782                     return meth::trans_trait_cast(bcx, val, expr.id, dest,
783                                                   store);
784                 }
785                 _ => {
786                     bcx.tcx().sess.span_bug(expr.span,
787                                             ~"expr_cast of non-trait");
788                 }
789             }
790         }
791         ast::expr_assign_op(op, dst, src) => {
792             return trans_assign_op(bcx, expr, op, dst, src);
793         }
794         _ => {
795             bcx.tcx().sess.span_bug(
796                 expr.span,
797                 fmt!("trans_rvalue_dps_unadjusted reached \
798                       fall-through case: %?",
799                      expr.node));
800         }
801     }
802 }
803
804 fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr,
805                             def: ast::def, dest: Dest) -> block {
806     let _icx = bcx.insn_ctxt("trans_def_dps_unadjusted");
807     let ccx = bcx.ccx();
808
809     let lldest = match dest {
810         SaveIn(lldest) => lldest,
811         Ignore => { return bcx; }
812     };
813
814     match def {
815         ast::def_variant(tid, vid) => {
816             let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
817             if variant_info.args.len() > 0u {
818                 // N-ary variant.
819                 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
820                 Store(bcx, fn_data.llfn, lldest);
821                 return bcx;
822             } else {
823                 // Nullary variant.
824                 let ty = expr_ty(bcx, ref_expr);
825                 let repr = adt::represent_type(ccx, ty);
826                 adt::trans_start_init(bcx, repr, lldest,
827                                       variant_info.disr_val);
828                 return bcx;
829             }
830         }
831         ast::def_struct(*) => {
832             // Nothing to do here.
833             // XXX: May not be true in the case of classes with destructors.
834             return bcx;
835         }
836         _ => {
837             bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
838                 "Non-DPS def %? referened by %s",
839                 def, bcx.node_id_to_str(ref_expr.id)));
840         }
841     }
842 }
843
844 fn trans_def_datum_unadjusted(bcx: block,
845                               ref_expr: @ast::expr,
846                               def: ast::def) -> DatumBlock
847 {
848     let _icx = bcx.insn_ctxt("trans_def_datum_unadjusted");
849
850     match def {
851         ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
852             let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
853             return fn_data_to_datum(bcx, ref_expr, did, fn_data);
854         }
855         ast::def_static_method(impl_did, Some(trait_did), _) => {
856             let fn_data = meth::trans_static_method_callee(bcx, impl_did,
857                                                            trait_did,
858                                                            ref_expr.id);
859             return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
860         }
861         _ => {
862             bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
863                 "Non-DPS def %? referened by %s",
864                 def, bcx.node_id_to_str(ref_expr.id)));
865         }
866     }
867
868     fn fn_data_to_datum(bcx: block,
869                         ref_expr: @ast::expr,
870                         def_id: ast::def_id,
871                         fn_data: callee::FnData) -> DatumBlock {
872         /*!
873         *
874         * Translates a reference to a top-level fn item into a rust
875         * value.  This is just a fn pointer.
876         */
877
878         let is_extern = {
879             let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
880             ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
881         };
882         let (rust_ty, llval) = if is_extern {
883             let rust_ty = ty::mk_ptr(
884                 bcx.tcx(),
885                 ty::mt {
886                     ty: ty::mk_mach_uint(bcx.tcx(), ast::ty_u8),
887                     mutbl: ast::m_imm
888                 }); // *u8
889             (rust_ty, PointerCast(bcx, fn_data.llfn, T_ptr(T_i8())))
890         } else {
891             let fn_ty = expr_ty(bcx, ref_expr);
892             (fn_ty, fn_data.llfn)
893         };
894         return DatumBlock {
895             bcx: bcx,
896             datum: Datum {val: llval,
897                           ty: rust_ty,
898                           mode: ByValue,
899                           source: RevokeClean}
900         };
901     }
902 }
903
904 fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
905     /*!
906      *
907      * Translates an lvalue expression, always yielding a by-ref
908      * datum.  Does not apply any adjustments. */
909
910     let _icx = bcx.insn_ctxt("trans_lval");
911     let mut bcx = bcx;
912
913     debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr));
914     let _indenter = indenter();
915
916     trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr)));
917
918     let unrooted_datum = unpack_datum!(bcx, unrooted(bcx, expr));
919
920     // If the lvalue must remain rooted, create a scratch datum, copy
921     // the lvalue in there, and then arrange for it to be cleaned up
922     // at the end of the scope with id `scope_id`:
923     let root_key = root_map_key { id: expr.id, derefs: 0u };
924     for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| {
925         bcx = unrooted_datum.root(bcx, *root_info);
926     }
927
928     return DatumBlock {bcx: bcx, datum: unrooted_datum};
929
930     fn unrooted(bcx: block, expr: @ast::expr) -> DatumBlock {
931         /*!
932          *
933          * Translates `expr`.  Note that this version generally
934          * yields an unrooted, unmoved version.  Rooting and possible
935          * moves are dealt with above in trans_lvalue_unadjusted().
936          *
937          * One exception is if `expr` refers to a local variable,
938          * in which case the source may already be FromMovedLvalue
939          * if appropriate.
940          */
941
942         let mut bcx = bcx;
943
944         match expr.node {
945             ast::expr_paren(e) => {
946                 return unrooted(bcx, e);
947             }
948             ast::expr_path(_) => {
949                 return trans_def_lvalue(bcx, expr, bcx.def(expr.id));
950             }
951             ast::expr_field(base, ident, _) => {
952                 return trans_rec_field(bcx, base, ident);
953             }
954             ast::expr_index(base, idx) => {
955                 return trans_index(bcx, expr, base, idx);
956             }
957             ast::expr_unary(ast::deref, base) => {
958                 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
959                 return basedatum.deref(bcx, base, 0);
960             }
961             _ => {
962                 bcx.tcx().sess.span_bug(
963                     expr.span,
964                     fmt!("trans_lvalue reached fall-through case: %?",
965                          expr.node));
966             }
967         }
968     }
969
970     fn trans_rec_field(bcx: block,
971                        base: @ast::expr,
972                        field: ast::ident) -> DatumBlock {
973         /*!
974          *
975          * Translates `base.field`.  Note that this version always
976          * yields an unrooted, unmoved version.  Rooting and possible
977          * moves are dealt with above in trans_lvalue_unadjusted().
978          */
979
980         let mut bcx = bcx;
981         let _icx = bcx.insn_ctxt("trans_rec_field");
982
983         let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
984         let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
985         do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
986             let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
987             DatumBlock {
988                 datum: do base_datum.get_element(bcx,
989                                                  field_tys[ix].mt.ty,
990                                                  ZeroMem) |srcval| {
991                     adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
992                 },
993                 bcx: bcx
994             }
995         }
996     }
997
998     fn trans_index(bcx: block,
999                    index_expr: @ast::expr,
1000                    base: @ast::expr,
1001                    idx: @ast::expr) -> DatumBlock {
1002         /*!
1003          *
1004          * Translates `base[idx]`.  Note that this version always
1005          * yields an unrooted, unmoved version.  Rooting and possible
1006          * moves are dealt with above in trans_lvalue_unadjusted().
1007          */
1008
1009         let _icx = bcx.insn_ctxt("trans_index");
1010         let ccx = bcx.ccx();
1011         let base_ty = expr_ty(bcx, base);
1012         let mut bcx = bcx;
1013
1014         let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
1015
1016         // Translate index expression and cast to a suitable LLVM integer.
1017         // Rust is less strict than LLVM in this regard.
1018         let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
1019         let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
1020         let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
1021         let ix_val = {
1022             if ix_size < int_size {
1023                 if ty::type_is_signed(expr_ty(bcx, idx)) {
1024                     SExt(bcx, ix_val, ccx.int_type)
1025                 } else { ZExt(bcx, ix_val, ccx.int_type) }
1026             } else if ix_size > int_size {
1027                 Trunc(bcx, ix_val, ccx.int_type)
1028             } else {
1029                 ix_val
1030             }
1031         };
1032
1033         let vt = tvec::vec_types(bcx, base_datum.ty);
1034         base::maybe_name_value(bcx.ccx(), vt.llunit_size, ~"unit_sz");
1035         let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
1036         base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
1037
1038         let mut (base, len) = base_datum.get_base_and_len(bcx);
1039
1040         if ty::type_is_str(base_ty) {
1041             // acccount for null terminator in the case of string
1042             len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
1043         }
1044
1045         debug!("trans_index: base %s", val_str(bcx.ccx().tn, base));
1046         debug!("trans_index: len %s", val_str(bcx.ccx().tn, len));
1047
1048         let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
1049         let bcx = do with_cond(bcx, bounds_check) |bcx| {
1050             let unscaled_len = UDiv(bcx, len, vt.llunit_size);
1051             controlflow::trans_fail_bounds_check(bcx, index_expr.span,
1052                                                  ix_val, unscaled_len)
1053         };
1054         let elt = InBoundsGEP(bcx, base, ~[ix_val]);
1055         let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
1056         return DatumBlock {
1057             bcx: bcx,
1058             datum: Datum {val: elt,
1059                           ty: vt.unit_ty,
1060                           mode: ByRef,
1061                           source: ZeroMem}
1062         };
1063     }
1064
1065     fn trans_def_lvalue(bcx: block,
1066                         ref_expr: @ast::expr,
1067                         def: ast::def)
1068         -> DatumBlock
1069     {
1070         /*!
1071          *
1072          * Translates a reference to a path.  Note that this version
1073          * generally yields an unrooted, unmoved version.  Rooting and
1074          * possible moves are dealt with above in
1075          * trans_lvalue_unadjusted(), with the caveat that local variables
1076          * may already be in move mode.
1077          */
1078
1079         let _icx = bcx.insn_ctxt("trans_def_lvalue");
1080         let ccx = bcx.ccx();
1081         match def {
1082             ast::def_const(did) => {
1083                 let const_ty = expr_ty(bcx, ref_expr);
1084
1085                 fn get_did(ccx: @CrateContext, did: ast::def_id)
1086                     -> ast::def_id {
1087                     if did.crate != ast::local_crate {
1088                         inline::maybe_instantiate_inline(ccx, did, true)
1089                     } else {
1090                         did
1091                     }
1092                 }
1093
1094                 fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
1095                     -> ValueRef {
1096                     // The LLVM global has the type of its initializer,
1097                     // which may not be equal to the enum's type for
1098                     // non-C-like enums.
1099                     PointerCast(bcx, base::get_item_val(bcx.ccx(), did.node),
1100                                 T_ptr(type_of(bcx.ccx(), const_ty)))
1101                 }
1102
1103                 let did = get_did(ccx, did);
1104                 let val = get_val(bcx, did, const_ty);
1105                 DatumBlock {
1106                     bcx: bcx,
1107                     datum: Datum {val: val,
1108                                   ty: const_ty,
1109                                   mode: ByRef,
1110                                   source: ZeroMem}
1111                 }
1112             }
1113             _ => {
1114                 DatumBlock {
1115                     bcx: bcx,
1116                     datum: trans_local_var(bcx, def)
1117                 }
1118             }
1119         }
1120     }
1121 }
1122
1123 pub fn trans_local_var(bcx: block, def: ast::def) -> Datum {
1124     let _icx = bcx.insn_ctxt("trans_local_var");
1125
1126     return match def {
1127         ast::def_upvar(nid, _, _, _) => {
1128             // Can't move upvars, so this is never a ZeroMemLastUse.
1129             let local_ty = node_id_type(bcx, nid);
1130             match bcx.fcx.llupvars.find(&nid) {
1131                 Some(&val) => {
1132                     Datum {
1133                         val: val,
1134                         ty: local_ty,
1135                         mode: ByRef,
1136                         source: ZeroMem
1137                     }
1138                 }
1139                 None => {
1140                     bcx.sess().bug(fmt!(
1141                         "trans_local_var: no llval for upvar %? found", nid));
1142                 }
1143             }
1144         }
1145         ast::def_arg(nid, _, _) => {
1146             take_local(bcx, bcx.fcx.llargs, nid)
1147         }
1148         ast::def_local(nid, _) | ast::def_binding(nid, _) => {
1149             take_local(bcx, bcx.fcx.lllocals, nid)
1150         }
1151         ast::def_self(nid, _) => {
1152             let self_info: ValSelfData = match bcx.fcx.llself {
1153                 Some(ref self_info) => *self_info,
1154                 None => {
1155                     bcx.sess().bug(fmt!(
1156                         "trans_local_var: reference to self \
1157                          out of context with id %?", nid));
1158                 }
1159             };
1160
1161             // This cast should not be necessary. We should cast self *once*,
1162             // but right now this conflicts with default methods.
1163             let real_self_ty = monomorphize_type(bcx, self_info.t);
1164             let llselfty = T_ptr(type_of::type_of(bcx.ccx(), real_self_ty));
1165
1166             let casted_val = PointerCast(bcx, self_info.v, llselfty);
1167             Datum {
1168                 val: casted_val,
1169                 ty: self_info.t,
1170                 mode: ByRef,
1171                 source: ZeroMem
1172             }
1173         }
1174         _ => {
1175             bcx.sess().unimpl(fmt!(
1176                 "unsupported def type in trans_local_var: %?", def));
1177         }
1178     };
1179
1180     fn take_local(bcx: block,
1181                   table: &LinearMap<ast::node_id, local_val>,
1182                   nid: ast::node_id) -> Datum {
1183         let (v, mode) = match table.find(&nid) {
1184             Some(&local_mem(v)) => (v, ByRef),
1185             Some(&local_imm(v)) => (v, ByValue),
1186             None => {
1187                 bcx.sess().bug(fmt!(
1188                     "trans_local_var: no llval for local/arg %? found", nid));
1189             }
1190         };
1191         let ty = node_id_type(bcx, nid);
1192
1193         debug!("take_local(nid=%?, v=%s, mode=%?, ty=%s)",
1194                nid, bcx.val_str(v), mode, bcx.ty_to_str(ty));
1195
1196         Datum {
1197             val: v,
1198             ty: ty,
1199             mode: mode,
1200             source: ZeroMem
1201         }
1202     }
1203 }
1204
1205 // The optional node ID here is the node ID of the path identifying the enum
1206 // variant in use. If none, this cannot possibly an enum variant (so, if it
1207 // is and `node_id_opt` is none, this function fails).
1208 pub fn with_field_tys<R>(tcx: ty::ctxt,
1209                          ty: ty::t,
1210                          node_id_opt: Option<ast::node_id>,
1211                          op: &fn(int, (&[ty::field])) -> R) -> R {
1212     match ty::get(ty).sty {
1213         ty::ty_struct(did, ref substs) => {
1214             op(0, struct_mutable_fields(tcx, did, substs))
1215         }
1216
1217         ty::ty_enum(_, ref substs) => {
1218             // We want the *variant* ID here, not the enum ID.
1219             match node_id_opt {
1220                 None => {
1221                     tcx.sess.bug(fmt!(
1222                         "cannot get field types from the enum type %s \
1223                          without a node ID",
1224                         ty_to_str(tcx, ty)));
1225                 }
1226                 Some(node_id) => {
1227                     match *tcx.def_map.get(&node_id) {
1228                         ast::def_variant(enum_id, variant_id) => {
1229                             let variant_info = ty::enum_variant_with_id(
1230                                 tcx, enum_id, variant_id);
1231                             op(variant_info.disr_val, struct_mutable_fields(
1232                                 tcx, variant_id, substs))
1233                         }
1234                         _ => {
1235                             tcx.sess.bug(~"resolve didn't map this expr to a \
1236                                            variant ID")
1237                         }
1238                     }
1239                 }
1240             }
1241         }
1242
1243         _ => {
1244             tcx.sess.bug(fmt!(
1245                 "cannot get field types from the type %s",
1246                 ty_to_str(tcx, ty)));
1247         }
1248     }
1249 }
1250
1251 fn trans_rec_or_struct(bcx: block,
1252                        fields: &[ast::field],
1253                        base: Option<@ast::expr>,
1254                        id: ast::node_id,
1255                        dest: Dest) -> block
1256 {
1257     let _icx = bcx.insn_ctxt("trans_rec");
1258     let mut bcx = bcx;
1259
1260     let ty = node_id_type(bcx, id);
1261     let tcx = bcx.tcx();
1262     do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| {
1263         let mut need_base = vec::from_elem(field_tys.len(), true);
1264
1265         let numbered_fields = do fields.map |field| {
1266             let opt_pos = vec::position(field_tys, |field_ty|
1267                                         field_ty.ident == field.node.ident);
1268             match opt_pos {
1269                 Some(i) => {
1270                     need_base[i] = false;
1271                     (i, field.node.expr)
1272                 }
1273                 None => {
1274                     tcx.sess.span_bug(field.span,
1275                                       ~"Couldn't find field in struct type")
1276                 }
1277             }
1278         };
1279         let optbase = match base {
1280             Some(base_expr) => {
1281                 let mut leftovers = ~[];
1282                 for need_base.eachi |i, b| {
1283                     if *b {
1284                         leftovers.push((i, field_tys[i].mt.ty))
1285                     }
1286                 }
1287                 Some(StructBaseInfo {expr: base_expr,
1288                                      fields: leftovers })
1289             }
1290             None => {
1291                 if need_base.any(|b| *b) {
1292                     // XXX should be span bug
1293                     tcx.sess.bug(~"missing fields and no base expr")
1294                 }
1295                 None
1296             }
1297         };
1298
1299         let repr = adt::represent_type(bcx.ccx(), ty);
1300         trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1301     }
1302 }
1303
1304 /**
1305  * Information that `trans_adt` needs in order to fill in the fields
1306  * of a struct copied from a base struct (e.g., from an expression
1307  * like `Foo { a: b, ..base }`.
1308  *
1309  * Note that `fields` may be empty; the base expression must always be
1310  * evaluated for side-effects.
1311  */
1312 struct StructBaseInfo {
1313     /// The base expression; will be evaluated after all explicit fields.
1314     expr: @ast::expr,
1315     /// The indices of fields to copy paired with their types.
1316     fields: ~[(uint, ty::t)]
1317 }
1318
1319 /**
1320  * Constructs an ADT instance:
1321  *
1322  * - `fields` should be a list of field indices paired with the
1323  * expression to store into that field.  The initializers will be
1324  * evaluated in the order specified by `fields`.
1325  *
1326  * - `optbase` contains information on the base struct (if any) from
1327  * which remaining fields are copied; see comments on `StructBaseInfo`.
1328  */
1329 fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
1330              fields: &[(uint, @ast::expr)],
1331              optbase: Option<StructBaseInfo>,
1332              dest: Dest) -> block {
1333     let _icx = bcx.insn_ctxt("trans_adt");
1334     let mut bcx = bcx;
1335     let addr = match dest {
1336         Ignore => {
1337             for fields.each |&(_i, e)| {
1338                 bcx = trans_into(bcx, e, Ignore);
1339             }
1340             for optbase.each |sbi| {
1341                 bcx = trans_into(bcx, sbi.expr, Ignore);
1342             }
1343             return bcx;
1344         }
1345         SaveIn(pos) => pos
1346     };
1347     let mut temp_cleanups = ~[];
1348     adt::trans_start_init(bcx, repr, addr, discr);
1349     for fields.each |&(i, e)| {
1350         let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1351         let e_ty = expr_ty(bcx, e);
1352         bcx = trans_into(bcx, e, SaveIn(dest));
1353         add_clean_temp_mem(bcx, dest, e_ty);
1354         temp_cleanups.push(dest);
1355     }
1356     for optbase.each |base| {
1357         // XXX is it sound to use the destination's repr on the base?
1358         // XXX would it ever be reasonable to be here with discr != 0?
1359         let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1360         for base.fields.each |&(i, t)| {
1361             let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| {
1362                 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1363             };
1364             let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1365             bcx = datum.store_to(bcx, base.expr.id, INIT, dest);
1366         }
1367     }
1368
1369     for vec::each(temp_cleanups) |cleanup| {
1370         revoke_clean(bcx, *cleanup);
1371     }
1372     return bcx;
1373 }
1374
1375
1376 fn trans_immediate_lit(bcx: block, expr: @ast::expr,
1377                        lit: ast::lit) -> DatumBlock {
1378     // must not be a string constant, that is a RvalueDpsExpr
1379     let _icx = bcx.insn_ctxt("trans_immediate_lit");
1380     let ty = expr_ty(bcx, expr);
1381     immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1382 }
1383
1384 fn trans_unary_datum(bcx: block,
1385                      un_expr: @ast::expr,
1386                      op: ast::unop,
1387                      sub_expr: @ast::expr) -> DatumBlock {
1388     let _icx = bcx.insn_ctxt("trans_unary_datum");
1389
1390     // if deref, would be LvalueExpr
1391     fail_unless!(op != ast::deref);
1392
1393     // if overloaded, would be RvalueDpsExpr
1394     fail_unless!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1395
1396     let un_ty = expr_ty(bcx, un_expr);
1397     let sub_ty = expr_ty(bcx, sub_expr);
1398
1399     return match op {
1400         ast::not => {
1401             let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1402
1403             // If this is a boolean type, we must not use the LLVM Not
1404             // instruction, as that is a *bitwise* not and we want *logical*
1405             // not on our 8-bit boolean values.
1406             let llresult = match ty::get(un_ty).sty {
1407                 ty::ty_bool => {
1408                     let llcond = ICmp(bcx,
1409                                       lib::llvm::IntEQ,
1410                                       val,
1411                                       C_bool(false));
1412                     Select(bcx, llcond, C_bool(true), C_bool(false))
1413                 }
1414                 _ => Not(bcx, val)
1415             };
1416             immediate_rvalue_bcx(bcx, llresult, un_ty)
1417         }
1418         ast::neg => {
1419             let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1420             let llneg = {
1421                 if ty::type_is_fp(un_ty) {
1422                     FNeg(bcx, val)
1423                 } else {
1424                     Neg(bcx, val)
1425                 }
1426             };
1427             immediate_rvalue_bcx(bcx, llneg, un_ty)
1428         }
1429         ast::box(_) => {
1430             trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1431                              heap_managed)
1432         }
1433         ast::uniq(_) => {
1434             let heap  = heap_for_unique(bcx, un_ty);
1435             trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1436         }
1437         ast::deref => {
1438             bcx.sess().bug(~"deref expressions should have been \
1439                              translated using trans_lvalue(), not \
1440                              trans_unary_datum()")
1441         }
1442     };
1443
1444     fn trans_boxed_expr(bcx: block,
1445                         box_ty: ty::t,
1446                         contents: @ast::expr,
1447                         contents_ty: ty::t,
1448                         heap: heap) -> DatumBlock {
1449         let _icx = bcx.insn_ctxt("trans_boxed_expr");
1450         let base::MallocResult { bcx, box: bx, body } =
1451             base::malloc_general(bcx, contents_ty, heap);
1452         add_clean_free(bcx, bx, heap);
1453         let bcx = trans_into(bcx, contents, SaveIn(body));
1454         revoke_clean(bcx, bx);
1455         return immediate_rvalue_bcx(bcx, bx, box_ty);
1456     }
1457 }
1458
1459 fn trans_addr_of(bcx: block, expr: @ast::expr,
1460                  subexpr: @ast::expr) -> DatumBlock {
1461     let _icx = bcx.insn_ctxt("trans_addr_of");
1462     let mut bcx = bcx;
1463     let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1464     let llval = sub_datum.to_ref_llval(bcx);
1465     return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1466 }
1467
1468 // Important to get types for both lhs and rhs, because one might be _|_
1469 // and the other not.
1470 fn trans_eager_binop(bcx: block,
1471                      binop_expr: @ast::expr,
1472                      binop_ty: ty::t,
1473                      op: ast::binop,
1474                      lhs_datum: &Datum,
1475                      rhs_datum: &Datum)
1476                   -> DatumBlock {
1477     let mut bcx = bcx;
1478     let _icx = bcx.insn_ctxt("trans_eager_binop");
1479
1480     let lhs = lhs_datum.to_appropriate_llval(bcx);
1481     let lhs_t = lhs_datum.ty;
1482
1483     let rhs = rhs_datum.to_appropriate_llval(bcx);
1484     let rhs_t = rhs_datum.ty;
1485
1486     let intype = {
1487         if ty::type_is_bot(lhs_t) { rhs_t }
1488         else { lhs_t }
1489     };
1490     let is_float = ty::type_is_fp(intype);
1491
1492     let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1493
1494     let mut bcx = bcx;
1495     let val = match op {
1496       ast::add => {
1497         if is_float { FAdd(bcx, lhs, rhs) }
1498         else { Add(bcx, lhs, rhs) }
1499       }
1500       ast::subtract => {
1501         if is_float { FSub(bcx, lhs, rhs) }
1502         else { Sub(bcx, lhs, rhs) }
1503       }
1504       ast::mul => {
1505         if is_float { FMul(bcx, lhs, rhs) }
1506         else { Mul(bcx, lhs, rhs) }
1507       }
1508       ast::div => {
1509         if is_float {
1510             FDiv(bcx, lhs, rhs)
1511         } else {
1512             // Only zero-check integers; fp /0 is NaN
1513             bcx = base::fail_if_zero(bcx, binop_expr.span,
1514                                      op, rhs, rhs_t);
1515             if ty::type_is_signed(intype) {
1516                 SDiv(bcx, lhs, rhs)
1517             } else {
1518                 UDiv(bcx, lhs, rhs)
1519             }
1520         }
1521       }
1522       ast::rem => {
1523         if is_float {
1524             FRem(bcx, lhs, rhs)
1525         } else {
1526             // Only zero-check integers; fp %0 is NaN
1527             bcx = base::fail_if_zero(bcx, binop_expr.span,
1528                                      op, rhs, rhs_t);
1529             if ty::type_is_signed(intype) {
1530                 SRem(bcx, lhs, rhs)
1531             } else {
1532                 URem(bcx, lhs, rhs)
1533             }
1534         }
1535       }
1536       ast::bitor => Or(bcx, lhs, rhs),
1537       ast::bitand => And(bcx, lhs, rhs),
1538       ast::bitxor => Xor(bcx, lhs, rhs),
1539       ast::shl => Shl(bcx, lhs, rhs),
1540       ast::shr => {
1541         if ty::type_is_signed(intype) {
1542             AShr(bcx, lhs, rhs)
1543         } else { LShr(bcx, lhs, rhs) }
1544       }
1545       ast::eq | ast::ne | ast::lt | ast::ge | ast::le | ast::gt => {
1546         if ty::type_is_bot(rhs_t) {
1547             C_bool(false)
1548         } else {
1549             if !ty::type_is_scalar(rhs_t) {
1550                 bcx.tcx().sess.span_bug(binop_expr.span,
1551                                         ~"non-scalar comparison");
1552             }
1553             let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1554             bcx = cmpr.bcx;
1555             ZExt(bcx, cmpr.val, T_i8())
1556         }
1557       }
1558       _ => {
1559         bcx.tcx().sess.span_bug(binop_expr.span, ~"unexpected binop");
1560       }
1561     };
1562
1563     return immediate_rvalue_bcx(bcx, val, binop_ty);
1564 }
1565
1566 // refinement types would obviate the need for this
1567 enum lazy_binop_ty { lazy_and, lazy_or }
1568
1569 fn trans_lazy_binop(bcx: block,
1570                     binop_expr: @ast::expr,
1571                     op: lazy_binop_ty,
1572                     a: @ast::expr,
1573                     b: @ast::expr) -> DatumBlock {
1574     let _icx = bcx.insn_ctxt("trans_lazy_binop");
1575     let binop_ty = expr_ty(bcx, binop_expr);
1576     let mut bcx = bcx;
1577
1578     let Result {bcx: past_lhs, val: lhs} = {
1579         do base::with_scope_result(bcx, a.info(), ~"lhs") |bcx| {
1580             trans_to_datum(bcx, a).to_result()
1581         }
1582     };
1583
1584     if past_lhs.unreachable {
1585         return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1586     }
1587
1588     let join = base::sub_block(bcx, ~"join");
1589     let before_rhs = base::sub_block(bcx, ~"rhs");
1590
1591     let lhs_i1 = bool_to_i1(past_lhs, lhs);
1592     match op {
1593       lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1594       lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1595     }
1596
1597     let Result {bcx: past_rhs, val: rhs} = {
1598         do base::with_scope_result(before_rhs, b.info(), ~"rhs") |bcx| {
1599             trans_to_datum(bcx, b).to_result()
1600         }
1601     };
1602
1603     if past_rhs.unreachable {
1604         return immediate_rvalue_bcx(join, lhs, binop_ty);
1605     }
1606
1607     Br(past_rhs, join.llbb);
1608     let phi = Phi(join, T_bool(), ~[lhs, rhs], ~[past_lhs.llbb,
1609                                                  past_rhs.llbb]);
1610
1611     return immediate_rvalue_bcx(join, phi, binop_ty);
1612 }
1613
1614 fn trans_binary(bcx: block,
1615                 binop_expr: @ast::expr,
1616                 op: ast::binop,
1617                 lhs: @ast::expr,
1618                 rhs: @ast::expr) -> DatumBlock
1619 {
1620     let _icx = bcx.insn_ctxt("trans_binary");
1621
1622     match op {
1623         ast::and => {
1624             trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1625         }
1626         ast::or => {
1627             trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1628         }
1629         _ => {
1630             let mut bcx = bcx;
1631             let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1632             let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1633             let binop_ty = expr_ty(bcx, binop_expr);
1634             trans_eager_binop(bcx, binop_expr, binop_ty, op,
1635                               &lhs_datum, &rhs_datum)
1636         }
1637     }
1638 }
1639
1640 fn trans_overloaded_op(bcx: block,
1641                        expr: @ast::expr,
1642                        rcvr: @ast::expr,
1643                        +args: ~[@ast::expr],
1644                        dest: Dest) -> block
1645 {
1646     let origin = *bcx.ccx().maps.method_map.get(&expr.id);
1647     let fty = node_id_type(bcx, expr.callee_id);
1648     return callee::trans_call_inner(
1649         bcx, expr.info(), fty,
1650         expr_ty(bcx, expr),
1651         |bcx| meth::trans_method_callee(bcx, expr.callee_id, rcvr, origin),
1652         callee::ArgExprs(args), dest, DoAutorefArg);
1653 }
1654
1655 fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
1656             llsrc: ValueRef, signed: bool) -> ValueRef {
1657     let _icx = bcx.insn_ctxt("int_cast");
1658     unsafe {
1659         let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
1660         let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
1661         return if dstsz == srcsz {
1662             BitCast(bcx, llsrc, lldsttype)
1663         } else if srcsz > dstsz {
1664             TruncOrBitCast(bcx, llsrc, lldsttype)
1665         } else if signed {
1666             SExtOrBitCast(bcx, llsrc, lldsttype)
1667         } else {
1668             ZExtOrBitCast(bcx, llsrc, lldsttype)
1669         };
1670     }
1671 }
1672
1673 fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
1674               llsrc: ValueRef) -> ValueRef {
1675     let _icx = bcx.insn_ctxt("float_cast");
1676     let srcsz = lib::llvm::float_width(llsrctype);
1677     let dstsz = lib::llvm::float_width(lldsttype);
1678     return if dstsz > srcsz {
1679         FPExt(bcx, llsrc, lldsttype)
1680     } else if srcsz > dstsz {
1681         FPTrunc(bcx, llsrc, lldsttype)
1682     } else { llsrc };
1683 }
1684
1685 pub enum cast_kind {
1686     cast_pointer,
1687     cast_integral,
1688     cast_float,
1689     cast_enum,
1690     cast_other,
1691 }
1692
1693 impl cmp::Eq for cast_kind {
1694     fn eq(&self, other: &cast_kind) -> bool {
1695         match ((*self), (*other)) {
1696             (cast_pointer, cast_pointer) => true,
1697             (cast_integral, cast_integral) => true,
1698             (cast_float, cast_float) => true,
1699             (cast_enum, cast_enum) => true,
1700             (cast_other, cast_other) => true,
1701             (cast_pointer, _) => false,
1702             (cast_integral, _) => false,
1703             (cast_float, _) => false,
1704             (cast_enum, _) => false,
1705             (cast_other, _) => false,
1706         }
1707     }
1708     fn ne(&self, other: &cast_kind) -> bool { !(*self).eq(other) }
1709 }
1710
1711 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1712     match ty::get(t).sty {
1713         ty::ty_float(*)   => cast_float,
1714         ty::ty_ptr(*)     => cast_pointer,
1715         ty::ty_rptr(*)    => cast_pointer,
1716         ty::ty_int(*)     => cast_integral,
1717         ty::ty_uint(*)    => cast_integral,
1718         ty::ty_bool       => cast_integral,
1719         ty::ty_enum(*)    => cast_enum,
1720         _                 => cast_other
1721     }
1722 }
1723
1724 fn trans_imm_cast(bcx: block, expr: @ast::expr,
1725                   id: ast::node_id) -> DatumBlock {
1726     let _icx = bcx.insn_ctxt("trans_cast");
1727     let ccx = bcx.ccx();
1728
1729     let t_out = node_id_type(bcx, id);
1730
1731     let mut bcx = bcx;
1732     let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1733     let ll_t_in = val_ty(llexpr);
1734     let t_in = expr_ty(bcx, expr);
1735     let ll_t_out = type_of::type_of(ccx, t_out);
1736
1737     let k_in = cast_type_kind(t_in);
1738     let k_out = cast_type_kind(t_out);
1739     let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1740
1741     let newval =
1742         match (k_in, k_out) {
1743             (cast_integral, cast_integral) => {
1744                 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1745             }
1746             (cast_float, cast_float) => {
1747                 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1748             }
1749             (cast_integral, cast_float) => {
1750                 if s_in {
1751                     SIToFP(bcx, llexpr, ll_t_out)
1752                 } else { UIToFP(bcx, llexpr, ll_t_out) }
1753             }
1754             (cast_float, cast_integral) => {
1755                 if ty::type_is_signed(t_out) {
1756                     FPToSI(bcx, llexpr, ll_t_out)
1757                 } else { FPToUI(bcx, llexpr, ll_t_out) }
1758             }
1759             (cast_integral, cast_pointer) => {
1760                 IntToPtr(bcx, llexpr, ll_t_out)
1761             }
1762             (cast_pointer, cast_integral) => {
1763                 PtrToInt(bcx, llexpr, ll_t_out)
1764             }
1765             (cast_pointer, cast_pointer) => {
1766                 PointerCast(bcx, llexpr, ll_t_out)
1767             }
1768             (cast_enum, cast_integral) |
1769             (cast_enum, cast_float) => {
1770                 let bcx = bcx;
1771                 let repr = adt::represent_type(ccx, t_in);
1772                 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr);
1773                 match k_out {
1774                     cast_integral => int_cast(bcx, ll_t_out,
1775                                               val_ty(lldiscrim_a),
1776                                               lldiscrim_a, true),
1777                     cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1778                     _ => ccx.sess.bug(~"translating unsupported cast.")
1779                 }
1780             }
1781             _ => ccx.sess.bug(~"translating unsupported cast.")
1782         };
1783     return immediate_rvalue_bcx(bcx, newval, t_out);
1784 }
1785
1786 fn trans_assign_op(bcx: block,
1787                    expr: @ast::expr,
1788                    op: ast::binop,
1789                    dst: @ast::expr,
1790                    src: @ast::expr) -> block
1791 {
1792     let _icx = bcx.insn_ctxt("trans_assign_op");
1793     let mut bcx = bcx;
1794
1795     debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr));
1796
1797     // Evaluate LHS (destination), which should be an lvalue
1798     let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1799
1800     // A user-defined operator method
1801     if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1802         // FIXME(#2528) evaluates the receiver twice!!
1803         let scratch = scratch_datum(bcx, dst_datum.ty, false);
1804         let bcx = trans_overloaded_op(bcx, expr, dst, ~[src],
1805                                       SaveIn(scratch.val));
1806         return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1807     }
1808
1809     // Evaluate RHS (source)
1810     let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1811
1812     // Perform computation and store the result
1813     let result_datum =
1814         unpack_datum!(bcx,
1815                       trans_eager_binop(
1816                           bcx, expr, dst_datum.ty, op,
1817                           &dst_datum, &src_datum));
1818     return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1819 }
1820
1821 // NOTE: Mode neccessary here?
1822 fn shorten(+x: ~str) -> ~str {
1823     if x.len() > 60 { x.substr(0, 60).to_owned() } else { x }
1824 }