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