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