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