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