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.
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.
13 # Translation of expressions.
15 ## Recommended entry point
17 If you wish to translate an expression, the preferred way to do
20 expr::trans_into(block, expr, Dest) -> block
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.
29 ## Translation to a datum
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).
37 In such cases, you want the following function:
39 trans_to_datum(block, expr) -> DatumBlock
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).
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.
59 ## Translating local variables
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.
64 ## Ownership and cleanups
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.
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
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.
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.
85 ## Implementation details
87 We divide expressions into three categories, based on how they are most
88 naturally implemented:
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.
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`
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
111 Finally, statement rvalues are rvalues that always produce a nil
112 return type, such as `while` loops or assignments (`a = b`).
118 use lib::llvm::{ValueRef, llvm, SetLinkage, ExternalLinkage};
120 use metadata::csearch;
121 use middle::trans::_match;
122 use middle::trans::adt;
123 use middle::trans::asm;
124 use middle::trans::base::*;
125 use middle::trans::base;
126 use middle::trans::build::*;
127 use middle::trans::callee::DoAutorefArg;
128 use middle::trans::callee;
129 use middle::trans::closure;
130 use middle::trans::common::*;
131 use middle::trans::consts;
132 use middle::trans::controlflow;
133 use middle::trans::datum::*;
134 use middle::trans::debuginfo;
135 use middle::trans::machine;
136 use middle::trans::meth;
137 use middle::trans::tvec;
138 use middle::trans::type_of;
139 use middle::ty::struct_fields;
140 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
141 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
143 use util::common::indenter;
144 use util::ppaux::Repr;
145 use middle::trans::machine::llsize_of;
147 use middle::trans::type_::Type;
149 use std::hashmap::HashMap;
151 use syntax::print::pprust::{expr_to_str};
157 // These are passed around by the code generating functions to track the
158 // destination of a computation's value.
167 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
169 SaveIn(v) => fmt!("SaveIn(%s)", ccx.tn.val_to_str(v)),
175 fn drop_and_cancel_clean(bcx: @mut Block, dat: Datum) -> @mut Block {
176 let bcx = dat.drop_val(bcx);
177 dat.cancel_clean(bcx);
181 pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
182 debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
185 let mut datum = unpack_datum!(bcx, trans_to_datum_unadjusted(bcx, expr));
186 let adjustment = match bcx.tcx().adjustments.find_copy(&expr.id) {
187 None => { return DatumBlock {bcx: bcx, datum: datum}; }
190 debug!("unadjusted datum: %s", datum.to_str(bcx.ccx()));
193 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
195 AutoDerefRef(ref adj) => {
196 if adj.autoderefs > 0 {
200 datum.autoderef(bcx, expr.span,
201 expr.id, adj.autoderefs));
204 datum = match adj.autoref {
208 Some(AutoUnsafe(*)) | // region + unsafe ptrs have same repr
209 Some(AutoPtr(*)) => {
210 unpack_datum!(bcx, auto_ref(bcx, datum))
212 Some(AutoBorrowVec(*)) => {
213 unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
216 Some(AutoBorrowVecRef(*)) => {
217 unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
220 Some(AutoBorrowFn(*)) => {
221 let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
222 datum.ty, Some(adjustment));
223 unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
225 Some(AutoBorrowObj(*)) => {
226 unpack_datum!(bcx, auto_borrow_obj(
227 bcx, adj.autoderefs, expr, datum))
232 debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
233 return DatumBlock {bcx: bcx, datum: datum};
235 fn auto_ref(bcx: @mut Block, datum: Datum) -> DatumBlock {
236 DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
239 fn auto_borrow_fn(bcx: @mut Block,
241 datum: Datum) -> DatumBlock {
242 // Currently, all closure types are represented precisely the
243 // same, so no runtime adjustment is required, but we still
244 // must patchup the type.
245 DatumBlock {bcx: bcx,
246 datum: Datum {val: datum.val, ty: adjusted_ty,
250 fn auto_slice(bcx: @mut Block,
253 datum: Datum) -> DatumBlock {
254 // This is not the most efficient thing possible; since slices
255 // are two words it'd be better if this were compiled in
256 // 'dest' mode, but I can't find a nice way to structure the
257 // code and keep it DRY that accommodates that use case at the
261 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
263 let (bcx, base, len) =
264 datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);
266 // this type may have a different region/mutability than the
267 // real one, but it will have the same runtime representation
268 let slice_ty = ty::mk_evec(tcx,
269 ty::mt { ty: unit_ty, mutbl: ast::m_imm },
270 ty::vstore_slice(ty::re_static));
272 let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
273 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
274 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
275 DatumBlock {bcx: bcx, datum: scratch}
278 fn add_env(bcx: @mut Block, expr: &ast::expr, datum: Datum) -> DatumBlock {
279 // This is not the most efficient thing possible; since closures
280 // are two words it'd be better if this were compiled in
281 // 'dest' mode, but I can't find a nice way to structure the
282 // code and keep it DRY that accommodates that use case at the
286 let closure_ty = expr_ty_adjusted(bcx, expr);
287 debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx));
288 let scratch = scratch_datum(bcx, closure_ty, "__adjust", false);
289 let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
290 assert_eq!(datum.appropriate_mode(tcx), ByValue);
291 Store(bcx, datum.to_appropriate_llval(bcx), llfn);
292 let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
293 Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
294 DatumBlock {bcx: bcx, datum: scratch}
297 fn auto_slice_and_ref(bcx: @mut Block,
300 datum: Datum) -> DatumBlock {
301 let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
305 fn auto_borrow_obj(mut bcx: @mut Block,
308 source_datum: Datum) -> DatumBlock {
310 let target_obj_ty = expr_ty_adjusted(bcx, expr);
311 debug!("auto_borrow_obj(target=%s)",
312 target_obj_ty.repr(tcx));
313 let scratch = scratch_datum(bcx, target_obj_ty,
314 "__auto_borrow_obj", false);
316 // Convert a @Object, ~Object, or &Object pair into an &Object pair.
318 // Get a pointer to the source object, which is represented as
319 // a (vtable, data) pair.
320 let source_llval = source_datum.to_ref_llval(bcx);
322 // Set the vtable field of the new pair
323 let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
324 let vtable = Load(bcx, vtable_ptr);
325 Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
327 // Load the data for the source, which is either an @T,
328 // ~T, or &T, depending on source_obj_ty.
329 let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
330 let source_data = Load(bcx, source_data_ptr); // always a ptr
331 let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
332 ty::ty_trait(_, _, s, m, _) => (s, m),
336 fmt!("auto_borrow_trait_obj expected a trait, found %s",
337 source_datum.ty.repr(bcx.tcx())));
340 let target_data = match source_store {
341 ty::BoxTraitStore(*) => {
342 // For deref of @T or @mut T, create a dummy datum and
343 // use the datum's deref method. This is more work
344 // than just calling GEPi ourselves, but it ensures
345 // that any write guards will be appropriate
346 // processed. Note that we don't know the type T, so
347 // just substitute `i8`-- it doesn't really matter for
348 // our purposes right now.
353 mutbl: source_mutbl});
355 Datum {val: source_data,
360 source_datum.deref(bcx,
363 derefd_datum.to_rptr(bcx).to_value_llval(bcx)
365 ty::UniqTraitStore(*) => {
366 // For a ~T box, there may or may not be a header,
367 // depending on whether the type T references managed
368 // boxes. However, since we do not *know* the type T
369 // for objects, this presents a hurdle. Our solution is
370 // to load the "borrow offset" from the type descriptor;
371 // this value will either be 0 or sizeof(BoxHeader), depending
374 PointerCast(bcx, source_data, Type::opaque().ptr_to());
375 let lltydesc_ptr_ptr =
376 PointerCast(bcx, vtable,
377 bcx.ccx().tydesc_type.ptr_to().ptr_to());
379 Load(bcx, lltydesc_ptr_ptr);
380 let borrow_offset_ptr =
381 GEPi(bcx, lltydesc_ptr,
382 [0, abi::tydesc_field_borrow_offset]);
384 Load(bcx, borrow_offset_ptr);
385 InBoundsGEP(bcx, llopaque, [borrow_offset])
387 ty::RegionTraitStore(*) => {
391 Store(bcx, target_data,
392 GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
394 DatumBlock { bcx: bcx, datum: scratch }
398 pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
399 if bcx.tcx().adjustments.contains_key(&expr.id) {
400 // use trans_to_datum, which is mildly less efficient but
401 // which will perform the adjustments:
402 let datumblock = trans_to_datum(bcx, expr);
404 Ignore => datumblock.bcx,
405 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
409 let ty = expr_ty(bcx, expr);
411 debug!("trans_into_unadjusted(expr=%s, dest=%s)",
412 bcx.expr_to_str(expr),
413 dest.to_str(bcx.ccx()));
414 let _indenter = indenter();
416 debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
419 if ty::type_is_voidish(ty) {
426 let kind = bcx.expr_kind(expr);
427 debug!("expr kind = %?", kind);
430 let datumblock = trans_lvalue_unadjusted(bcx, expr);
432 Ignore => datumblock.bcx,
433 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
436 ty::RvalueDatumExpr => {
437 let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
439 Ignore => datumblock.drop_val(),
441 // When processing an rvalue, the value will be newly
442 // allocated, so we always `move_to` so as not to
443 // unnecessarily inc ref counts and so forth:
444 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
447 ty::RvalueDpsExpr => {
448 trans_rvalue_dps_unadjusted(bcx, expr, dest)
450 ty::RvalueStmtExpr => {
451 trans_rvalue_stmt_unadjusted(bcx, expr)
456 fn trans_lvalue(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
459 * Translates an lvalue expression, always yielding a by-ref
460 * datum. Generally speaking you should call trans_to_datum()
461 * instead, but sometimes we call trans_lvalue() directly as a
462 * means of asserting that a particular expression is an lvalue. */
464 return match bcx.tcx().adjustments.find(&expr.id) {
465 None => trans_lvalue_unadjusted(bcx, expr),
469 fmt!("trans_lvalue() called on an expression \
475 fn trans_to_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
477 * Translates an expression into a datum. If this expression
478 * is an rvalue, this will result in a temporary value being
479 * created. If you plan to store the value somewhere else,
480 * you should prefer `trans_into()` instead.
485 debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
486 let _indenter = indenter();
488 debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
490 match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
492 return trans_lvalue_unadjusted(bcx, expr);
495 ty::RvalueDatumExpr => {
496 let datum = unpack_datum!(bcx, {
497 trans_rvalue_datum_unadjusted(bcx, expr)
499 datum.add_clean(bcx);
500 return DatumBlock {bcx: bcx, datum: datum};
503 ty::RvalueStmtExpr => {
504 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
505 return nil(bcx, expr_ty(bcx, expr));
508 ty::RvalueDpsExpr => {
509 let ty = expr_ty(bcx, expr);
510 if ty::type_is_voidish(ty) {
511 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
514 let scratch = scratch_datum(bcx, ty, "", false);
515 bcx = trans_rvalue_dps_unadjusted(
516 bcx, expr, SaveIn(scratch.val));
518 // Note: this is not obviously a good idea. It causes
519 // immediate values to be loaded immediately after a
520 // return from a call or other similar expression,
521 // which in turn leads to alloca's having shorter
522 // lifetimes and hence larger stack frames. However,
523 // in turn it can lead to more register pressure.
524 // Still, in practice it seems to increase
525 // performance, since we have fewer problems with
527 let scratch = scratch.to_appropriate_datum(bcx);
529 scratch.add_clean(bcx);
530 return DatumBlock {bcx: bcx, datum: scratch};
535 fn nil(bcx: @mut Block, ty: ty::t) -> DatumBlock {
536 let datum = immediate_rvalue(C_nil(), ty);
537 DatumBlock {bcx: bcx, datum: datum}
541 fn trans_rvalue_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
542 let _icx = push_ctxt("trans_rvalue_datum_unadjusted");
544 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
547 ast::expr_path(_) | ast::expr_self => {
548 return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
550 ast::expr_vstore(contents, ast::expr_vstore_box) |
551 ast::expr_vstore(contents, ast::expr_vstore_mut_box) => {
552 return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
555 ast::expr_vstore(contents, ast::expr_vstore_uniq) => {
556 let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
557 return tvec::trans_uniq_or_managed_vstore(bcx, heap,
560 ast::expr_lit(lit) => {
561 return trans_immediate_lit(bcx, expr, *lit);
563 ast::expr_binary(_, op, lhs, rhs) => {
564 // if overloaded, would be RvalueDpsExpr
565 assert!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
567 return trans_binary(bcx, expr, op, lhs, rhs);
569 ast::expr_unary(_, op, x) => {
570 return trans_unary_datum(bcx, expr, op, x);
572 ast::expr_addr_of(_, x) => {
573 return trans_addr_of(bcx, expr, x);
575 ast::expr_cast(val, _) => {
576 return trans_imm_cast(bcx, val, expr.id);
578 ast::expr_paren(e) => {
579 return trans_rvalue_datum_unadjusted(bcx, e);
582 bcx.tcx().sess.span_bug(
584 fmt!("trans_rvalue_datum_unadjusted reached \
585 fall-through case: %?",
591 fn trans_rvalue_stmt_unadjusted(bcx: @mut Block, expr: @ast::expr) -> @mut Block {
593 let _icx = push_ctxt("trans_rvalue_stmt");
599 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
602 ast::expr_break(label_opt) => {
603 return controlflow::trans_break(bcx, label_opt);
605 ast::expr_again(label_opt) => {
606 return controlflow::trans_cont(bcx, label_opt);
608 ast::expr_ret(ex) => {
609 return controlflow::trans_ret(bcx, ex);
611 ast::expr_log(lvl, a) => {
612 return controlflow::trans_log(expr, lvl, bcx, a);
614 ast::expr_while(cond, ref body) => {
615 return controlflow::trans_while(bcx, cond, body);
617 ast::expr_loop(ref body, opt_label) => {
618 return controlflow::trans_loop(bcx, body, opt_label);
620 ast::expr_assign(dst, src) => {
621 let src_datum = unpack_datum!(
622 bcx, trans_to_datum(bcx, src));
623 let dst_datum = unpack_datum!(
624 bcx, trans_lvalue(bcx, dst));
625 return src_datum.store_to_datum(
626 bcx, DROP_EXISTING, dst_datum);
628 ast::expr_assign_op(callee_id, op, dst, src) => {
629 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
631 ast::expr_paren(a) => {
632 return trans_rvalue_stmt_unadjusted(bcx, a);
634 ast::expr_inline_asm(ref a) => {
635 return asm::trans_inline_asm(bcx, a);
638 bcx.tcx().sess.span_bug(
640 fmt!("trans_rvalue_stmt_unadjusted reached \
641 fall-through case: %?",
647 fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: @ast::expr,
648 dest: Dest) -> @mut Block {
649 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
652 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
655 ast::expr_paren(e) => {
656 return trans_rvalue_dps_unadjusted(bcx, e, dest);
658 ast::expr_path(_) | ast::expr_self => {
659 return trans_def_dps_unadjusted(bcx, expr,
660 bcx.def(expr.id), dest);
662 ast::expr_if(cond, ref thn, els) => {
663 return controlflow::trans_if(bcx, cond, thn, els, dest);
665 ast::expr_match(discr, ref arms) => {
666 return _match::trans_match(bcx, expr, discr, *arms, dest);
668 ast::expr_block(ref blk) => {
669 return do base::with_scope(bcx, blk.info(),
670 "block-expr body") |bcx| {
671 controlflow::trans_block(bcx, blk, dest)
674 ast::expr_struct(_, ref fields, base) => {
675 return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
677 ast::expr_tup(ref args) => {
678 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
679 let numbered_fields: ~[(uint, @ast::expr)] =
680 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
681 return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
683 ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => {
684 return tvec::trans_lit_str(bcx, expr, s, dest);
686 ast::expr_vstore(contents, ast::expr_vstore_slice) |
687 ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
688 return tvec::trans_slice_vstore(bcx, expr, contents, dest);
690 ast::expr_vec(*) | ast::expr_repeat(*) => {
691 return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
693 ast::expr_fn_block(ref decl, ref body) => {
694 let expr_ty = expr_ty(bcx, expr);
695 let sigil = ty::ty_closure_sigil(expr_ty);
696 debug!("translating fn_block %s with type %s",
697 expr_to_str(expr, tcx.sess.intr()),
699 return closure::trans_expr_fn(bcx, sigil, decl, body,
700 expr.id, expr.id, dest);
702 ast::expr_do_body(blk) => {
703 return trans_into(bcx, blk, dest);
705 ast::expr_call(f, ref args, _) => {
706 return callee::trans_call(
707 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
709 ast::expr_method_call(callee_id, rcvr, _, _, ref args, _) => {
710 return callee::trans_method_call(bcx,
714 callee::ArgExprs(*args),
717 ast::expr_binary(callee_id, _, lhs, rhs) => {
718 // if not overloaded, would be RvalueDatumExpr
719 return trans_overloaded_op(bcx,
727 ast::expr_unary(callee_id, _, subexpr) => {
728 // if not overloaded, would be RvalueDatumExpr
729 return trans_overloaded_op(bcx,
737 ast::expr_index(callee_id, base, idx) => {
738 // if not overloaded, would be RvalueDatumExpr
739 return trans_overloaded_op(bcx,
747 ast::expr_cast(val, _) => {
748 match ty::get(node_id_type(bcx, expr.id)).sty {
749 ty::ty_trait(_, _, store, _, _) => {
750 return meth::trans_trait_cast(bcx, val, expr.id, dest,
754 bcx.tcx().sess.span_bug(expr.span,
755 "expr_cast of non-trait");
759 ast::expr_assign_op(callee_id, op, dst, src) => {
760 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
763 bcx.tcx().sess.span_bug(
765 fmt!("trans_rvalue_dps_unadjusted reached fall-through case: %?",
771 fn trans_def_dps_unadjusted(bcx: @mut Block, ref_expr: &ast::expr,
772 def: ast::def, dest: Dest) -> @mut Block {
773 let _icx = push_ctxt("trans_def_dps_unadjusted");
776 let lldest = match dest {
777 SaveIn(lldest) => lldest,
778 Ignore => { return bcx; }
782 ast::def_variant(tid, vid) => {
783 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
784 if variant_info.args.len() > 0u {
786 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
787 Store(bcx, fn_data.llfn, lldest);
791 let ty = expr_ty(bcx, ref_expr);
792 let repr = adt::represent_type(ccx, ty);
793 adt::trans_start_init(bcx, repr, lldest,
794 variant_info.disr_val);
798 ast::def_struct(def_id) => {
799 let ty = expr_ty(bcx, ref_expr);
800 match ty::get(ty).sty {
801 ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
802 let repr = adt::represent_type(ccx, ty);
803 adt::trans_start_init(bcx, repr, lldest, 0);
805 ty::ty_bare_fn(*) => {
806 let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
807 Store(bcx, fn_data.llfn, lldest);
814 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
815 "Non-DPS def %? referened by %s",
816 def, bcx.node_id_to_str(ref_expr.id)));
821 fn trans_def_datum_unadjusted(bcx: @mut Block,
822 ref_expr: &ast::expr,
823 def: ast::def) -> DatumBlock
825 let _icx = push_ctxt("trans_def_datum_unadjusted");
828 ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
829 let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
830 return fn_data_to_datum(bcx, ref_expr, did, fn_data);
832 ast::def_static_method(impl_did, Some(trait_did), _) => {
833 let fn_data = meth::trans_static_method_callee(bcx, impl_did,
836 return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
839 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
840 "Non-DPS def %? referened by %s",
841 def, bcx.node_id_to_str(ref_expr.id)));
845 fn fn_data_to_datum(bcx: @mut Block,
846 ref_expr: &ast::expr,
848 fn_data: callee::FnData) -> DatumBlock {
851 * Translates a reference to a top-level fn item into a rust
852 * value. This is just a fn pointer.
856 let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
857 ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
859 let (rust_ty, llval) = if is_extern {
860 let rust_ty = ty::mk_ptr(
863 ty: ty::mk_mach_uint(ast::ty_u8),
866 (rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
868 let fn_ty = expr_ty(bcx, ref_expr);
869 (fn_ty, fn_data.llfn)
873 datum: Datum {val: llval,
880 fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
883 * Translates an lvalue expression, always yielding a by-ref
884 * datum. Does not apply any adjustments. */
886 let _icx = push_ctxt("trans_lval");
889 debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr));
890 let _indenter = indenter();
892 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
894 return match expr.node {
895 ast::expr_paren(e) => {
896 trans_lvalue_unadjusted(bcx, e)
898 ast::expr_path(_) | ast::expr_self => {
899 trans_def_lvalue(bcx, expr, bcx.def(expr.id))
901 ast::expr_field(base, ident, _) => {
902 trans_rec_field(bcx, base, ident)
904 ast::expr_index(_, base, idx) => {
905 trans_index(bcx, expr, base, idx)
907 ast::expr_unary(_, ast::deref, base) => {
908 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
909 basedatum.deref(bcx, expr, 0)
912 bcx.tcx().sess.span_bug(
914 fmt!("trans_lvalue reached fall-through case: %?",
919 fn trans_rec_field(bcx: @mut Block,
921 field: ast::ident) -> DatumBlock {
922 //! Translates `base.field`.
925 let _icx = push_ctxt("trans_rec_field");
927 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
928 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
929 do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
930 let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
932 datum: do base_datum.get_element(bcx,
935 adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
942 fn trans_index(bcx: @mut Block,
943 index_expr: &ast::expr,
945 idx: @ast::expr) -> DatumBlock {
946 //! Translates `base[idx]`.
948 let _icx = push_ctxt("trans_index");
952 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
954 // Translate index expression and cast to a suitable LLVM integer.
955 // Rust is less strict than LLVM in this regard.
956 let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
957 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
958 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
960 if ix_size < int_size {
961 if ty::type_is_signed(expr_ty(bcx, idx)) {
962 SExt(bcx, ix_val, ccx.int_type)
963 } else { ZExt(bcx, ix_val, ccx.int_type) }
964 } else if ix_size > int_size {
965 Trunc(bcx, ix_val, ccx.int_type)
971 let vt = tvec::vec_types(bcx, base_datum.ty);
972 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
973 let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
974 base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix");
976 let (bcx, base, len) =
977 base_datum.get_vec_base_and_len(bcx, index_expr.span,
980 debug!("trans_index: base %s", bcx.val_to_str(base));
981 debug!("trans_index: len %s", bcx.val_to_str(len));
983 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
984 let bcx = do with_cond(bcx, bounds_check) |bcx| {
985 let unscaled_len = UDiv(bcx, len, vt.llunit_size);
986 controlflow::trans_fail_bounds_check(bcx, index_expr.span,
987 ix_val, unscaled_len)
989 let elt = InBoundsGEP(bcx, base, [ix_val]);
990 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
993 datum: Datum {val: elt,
995 mode: ByRef(ZeroMem)}
999 fn trans_def_lvalue(bcx: @mut Block,
1000 ref_expr: &ast::expr,
1004 //! Translates a reference to a path.
1006 let _icx = push_ctxt("trans_def_lvalue");
1008 ast::def_static(did, _) => {
1009 let const_ty = expr_ty(bcx, ref_expr);
1011 fn get_val(bcx: @mut Block, did: ast::def_id, const_ty: ty::t)
1013 // For external constants, we don't inline.
1014 if did.crate == ast::LOCAL_CRATE {
1015 // The LLVM global has the type of its initializer,
1016 // which may not be equal to the enum's type for
1017 // non-C-like enums.
1018 let val = base::get_item_val(bcx.ccx(), did.node);
1019 let pty = type_of(bcx.ccx(), const_ty).ptr_to();
1020 PointerCast(bcx, val, pty)
1023 let extern_const_values = &bcx.ccx().extern_const_values;
1024 match extern_const_values.find(&did) {
1025 None => {} // Continue.
1033 let llty = type_of(bcx.ccx(), const_ty);
1034 let symbol = csearch::get_symbol(
1035 bcx.ccx().sess.cstore,
1037 let llval = do symbol.with_c_str |buf| {
1038 llvm::LLVMAddGlobal(bcx.ccx().llmod,
1042 SetLinkage(llval, ExternalLinkage);
1043 let extern_const_values = &mut bcx.ccx().extern_const_values;
1044 extern_const_values.insert(did, llval);
1050 let val = get_val(bcx, did, const_ty);
1053 datum: Datum {val: val,
1055 mode: ByRef(ZeroMem)}
1061 datum: trans_local_var(bcx, def)
1068 pub fn trans_local_var(bcx: @mut Block, def: ast::def) -> Datum {
1069 let _icx = push_ctxt("trans_local_var");
1072 ast::def_upvar(nid, _, _, _) => {
1073 // Can't move upvars, so this is never a ZeroMemLastUse.
1074 let local_ty = node_id_type(bcx, nid);
1075 match bcx.fcx.llupvars.find(&nid) {
1080 mode: ByRef(ZeroMem)
1084 bcx.sess().bug(fmt!(
1085 "trans_local_var: no llval for upvar %? found", nid));
1089 ast::def_arg(nid, _) => {
1090 take_local(bcx, bcx.fcx.llargs, nid)
1092 ast::def_local(nid, _) | ast::def_binding(nid, _) => {
1093 take_local(bcx, bcx.fcx.lllocals, nid)
1095 ast::def_self(nid, _) => {
1096 let self_info: ValSelfData = match bcx.fcx.llself {
1097 Some(ref self_info) => *self_info,
1099 bcx.sess().bug(fmt!(
1100 "trans_local_var: reference to self \
1101 out of context with id %?", nid));
1105 debug!("def_self() reference, self_info.t=%s",
1106 self_info.t.repr(bcx.tcx()));
1111 mode: ByRef(ZeroMem)
1115 bcx.sess().unimpl(fmt!(
1116 "unsupported def type in trans_local_var: %?", def));
1120 fn take_local(bcx: @mut Block,
1121 table: &HashMap<ast::NodeId, ValueRef>,
1122 nid: ast::NodeId) -> Datum {
1123 let v = match table.find(&nid) {
1126 bcx.sess().bug(fmt!(
1127 "trans_local_var: no llval for local/arg %? found", nid));
1130 let ty = node_id_type(bcx, nid);
1131 debug!("take_local(nid=%?, v=%s, ty=%s)",
1132 nid, bcx.val_to_str(v), bcx.ty_to_str(ty));
1136 mode: ByRef(ZeroMem)
1141 // The optional node ID here is the node ID of the path identifying the enum
1142 // variant in use. If none, this cannot possibly an enum variant (so, if it
1143 // is and `node_id_opt` is none, this function fails).
1144 pub fn with_field_tys<R>(tcx: ty::ctxt,
1146 node_id_opt: Option<ast::NodeId>,
1147 op: &fn(uint, (&[ty::field])) -> R) -> R {
1148 match ty::get(ty).sty {
1149 ty::ty_struct(did, ref substs) => {
1150 op(0, struct_fields(tcx, did, substs))
1153 ty::ty_enum(_, ref substs) => {
1154 // We want the *variant* ID here, not the enum ID.
1158 "cannot get field types from the enum type %s \
1163 match tcx.def_map.get_copy(&node_id) {
1164 ast::def_variant(enum_id, variant_id) => {
1165 let variant_info = ty::enum_variant_with_id(
1166 tcx, enum_id, variant_id);
1167 op(variant_info.disr_val,
1168 struct_fields(tcx, variant_id, substs))
1171 tcx.sess.bug("resolve didn't map this expr to a \
1181 "cannot get field types from the type %s",
1187 fn trans_rec_or_struct(bcx: @mut Block,
1188 fields: &[ast::Field],
1189 base: Option<@ast::expr>,
1190 expr_span: codemap::span,
1192 dest: Dest) -> @mut Block
1194 let _icx = push_ctxt("trans_rec");
1197 let ty = node_id_type(bcx, id);
1198 let tcx = bcx.tcx();
1199 do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| {
1200 let mut need_base = vec::from_elem(field_tys.len(), true);
1202 let numbered_fields = do fields.map |field| {
1203 let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.ident);
1206 need_base[i] = false;
1210 tcx.sess.span_bug(field.span,
1211 "Couldn't find field in struct type")
1215 let optbase = match base {
1216 Some(base_expr) => {
1217 let mut leftovers = ~[];
1218 for (i, b) in need_base.iter().enumerate() {
1220 leftovers.push((i, field_tys[i].mt.ty))
1223 Some(StructBaseInfo {expr: base_expr,
1224 fields: leftovers })
1227 if need_base.iter().any(|b| *b) {
1228 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1234 let repr = adt::represent_type(bcx.ccx(), ty);
1235 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1240 * Information that `trans_adt` needs in order to fill in the fields
1241 * of a struct copied from a base struct (e.g., from an expression
1242 * like `Foo { a: b, ..base }`.
1244 * Note that `fields` may be empty; the base expression must always be
1245 * evaluated for side-effects.
1247 struct StructBaseInfo {
1248 /// The base expression; will be evaluated after all explicit fields.
1250 /// The indices of fields to copy paired with their types.
1251 fields: ~[(uint, ty::t)]
1255 * Constructs an ADT instance:
1257 * - `fields` should be a list of field indices paired with the
1258 * expression to store into that field. The initializers will be
1259 * evaluated in the order specified by `fields`.
1261 * - `optbase` contains information on the base struct (if any) from
1262 * which remaining fields are copied; see comments on `StructBaseInfo`.
1264 fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
1265 fields: &[(uint, @ast::expr)],
1266 optbase: Option<StructBaseInfo>,
1267 dest: Dest) -> @mut Block {
1268 let _icx = push_ctxt("trans_adt");
1270 let addr = match dest {
1272 for &(_i, e) in fields.iter() {
1273 bcx = trans_into(bcx, e, Ignore);
1275 for sbi in optbase.iter() {
1276 // FIXME #7261: this moves entire base, not just certain fields
1277 bcx = trans_into(bcx, sbi.expr, Ignore);
1283 let mut temp_cleanups = ~[];
1284 adt::trans_start_init(bcx, repr, addr, discr);
1285 for &(i, e) in fields.iter() {
1286 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1287 let e_ty = expr_ty(bcx, e);
1288 bcx = trans_into(bcx, e, SaveIn(dest));
1289 add_clean_temp_mem(bcx, dest, e_ty);
1290 temp_cleanups.push(dest);
1292 for base in optbase.iter() {
1293 // FIXME #6573: is it sound to use the destination's repr on the base?
1294 // And, would it ever be reasonable to be here with discr != 0?
1295 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1296 for &(i, t) in base.fields.iter() {
1297 let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| {
1298 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1300 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1301 bcx = datum.store_to(bcx, INIT, dest);
1305 for cleanup in temp_cleanups.iter() {
1306 revoke_clean(bcx, *cleanup);
1312 fn trans_immediate_lit(bcx: @mut Block, expr: @ast::expr,
1313 lit: ast::lit) -> DatumBlock {
1314 // must not be a string constant, that is a RvalueDpsExpr
1315 let _icx = push_ctxt("trans_immediate_lit");
1316 let ty = expr_ty(bcx, expr);
1317 immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1320 fn trans_unary_datum(bcx: @mut Block,
1321 un_expr: &ast::expr,
1323 sub_expr: @ast::expr) -> DatumBlock {
1324 let _icx = push_ctxt("trans_unary_datum");
1326 // if deref, would be LvalueExpr
1327 assert!(op != ast::deref);
1329 // if overloaded, would be RvalueDpsExpr
1330 assert!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1332 let un_ty = expr_ty(bcx, un_expr);
1333 let sub_ty = expr_ty(bcx, sub_expr);
1337 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1339 // If this is a boolean type, we must not use the LLVM Not
1340 // instruction, as that is a *bitwise* not and we want *logical*
1341 // not on our 8-bit boolean values.
1342 let llresult = match ty::get(un_ty).sty {
1344 let llcond = ICmp(bcx,
1348 Select(bcx, llcond, C_bool(true), C_bool(false))
1352 immediate_rvalue_bcx(bcx, llresult, un_ty)
1355 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1357 if ty::type_is_fp(un_ty) {
1363 immediate_rvalue_bcx(bcx, llneg, un_ty)
1366 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1370 let heap = heap_for_unique(bcx, un_ty);
1371 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1374 bcx.sess().bug("deref expressions should have been \
1375 translated using trans_lvalue(), not \
1376 trans_unary_datum()")
1380 fn trans_boxed_expr(bcx: @mut Block,
1382 contents: @ast::expr,
1384 heap: heap) -> DatumBlock {
1385 let _icx = push_ctxt("trans_boxed_expr");
1386 if heap == heap_exchange {
1387 let llty = type_of(bcx.ccx(), contents_ty);
1388 let size = llsize_of(bcx.ccx(), llty);
1389 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
1390 heap_exchange, size);
1391 add_clean_free(bcx, val, heap_exchange);
1392 let bcx = trans_into(bcx, contents, SaveIn(val));
1393 revoke_clean(bcx, val);
1394 return immediate_rvalue_bcx(bcx, val, box_ty);
1396 let base::MallocResult { bcx, box: bx, body } =
1397 base::malloc_general(bcx, contents_ty, heap);
1398 add_clean_free(bcx, bx, heap);
1399 let bcx = trans_into(bcx, contents, SaveIn(body));
1400 revoke_clean(bcx, bx);
1401 return immediate_rvalue_bcx(bcx, bx, box_ty);
1406 fn trans_addr_of(bcx: @mut Block, expr: &ast::expr,
1407 subexpr: @ast::expr) -> DatumBlock {
1408 let _icx = push_ctxt("trans_addr_of");
1410 let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1411 let llval = sub_datum.to_ref_llval(bcx);
1412 return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1415 // Important to get types for both lhs and rhs, because one might be _|_
1416 // and the other not.
1417 fn trans_eager_binop(bcx: @mut Block,
1418 binop_expr: &ast::expr,
1424 let _icx = push_ctxt("trans_eager_binop");
1426 let lhs = lhs_datum.to_appropriate_llval(bcx);
1427 let lhs_t = lhs_datum.ty;
1429 let rhs = rhs_datum.to_appropriate_llval(bcx);
1430 let rhs_t = rhs_datum.ty;
1433 if ty::type_is_bot(lhs_t) { rhs_t }
1436 let tcx = bcx.tcx();
1437 if ty::type_is_simd(tcx, intype) {
1438 intype = ty::simd_type(tcx, intype);
1440 let is_float = ty::type_is_fp(intype);
1441 let signed = ty::type_is_signed(intype);
1443 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1446 let val = match op {
1448 if is_float { FAdd(bcx, lhs, rhs) }
1449 else { Add(bcx, lhs, rhs) }
1452 if is_float { FSub(bcx, lhs, rhs) }
1453 else { Sub(bcx, lhs, rhs) }
1456 if is_float { FMul(bcx, lhs, rhs) }
1457 else { Mul(bcx, lhs, rhs) }
1463 // Only zero-check integers; fp /0 is NaN
1464 bcx = base::fail_if_zero(bcx, binop_expr.span,
1477 // Only zero-check integers; fp %0 is NaN
1478 bcx = base::fail_if_zero(bcx, binop_expr.span,
1487 ast::bitor => Or(bcx, lhs, rhs),
1488 ast::bitand => And(bcx, lhs, rhs),
1489 ast::bitxor => Xor(bcx, lhs, rhs),
1490 ast::shl => Shl(bcx, lhs, rhs),
1494 } else { LShr(bcx, lhs, rhs) }
1496 ast::eq | ast::ne | ast::lt | ast::ge | ast::le | ast::gt => {
1497 if ty::type_is_bot(rhs_t) {
1500 if !ty::type_is_scalar(rhs_t) {
1501 bcx.tcx().sess.span_bug(binop_expr.span,
1502 "non-scalar comparison");
1504 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1506 ZExt(bcx, cmpr.val, Type::i8())
1510 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1514 return immediate_rvalue_bcx(bcx, val, binop_ty);
1517 // refinement types would obviate the need for this
1518 enum lazy_binop_ty { lazy_and, lazy_or }
1520 fn trans_lazy_binop(bcx: @mut Block,
1521 binop_expr: &ast::expr,
1524 b: @ast::expr) -> DatumBlock {
1525 let _icx = push_ctxt("trans_lazy_binop");
1526 let binop_ty = expr_ty(bcx, binop_expr);
1529 let Result {bcx: past_lhs, val: lhs} = {
1530 do base::with_scope_result(bcx, a.info(), "lhs") |bcx| {
1531 trans_to_datum(bcx, a).to_result()
1535 if past_lhs.unreachable {
1536 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1539 let join = base::sub_block(bcx, "join");
1540 let before_rhs = base::sub_block(bcx, "rhs");
1542 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1544 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1545 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1548 let Result {bcx: past_rhs, val: rhs} = {
1549 do base::with_scope_result(before_rhs, b.info(), "rhs") |bcx| {
1550 trans_to_datum(bcx, b).to_result()
1554 if past_rhs.unreachable {
1555 return immediate_rvalue_bcx(join, lhs, binop_ty);
1558 Br(past_rhs, join.llbb);
1559 let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb,
1562 return immediate_rvalue_bcx(join, phi, binop_ty);
1565 fn trans_binary(bcx: @mut Block,
1566 binop_expr: &ast::expr,
1569 rhs: @ast::expr) -> DatumBlock
1571 let _icx = push_ctxt("trans_binary");
1575 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1578 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1582 let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1583 let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1584 let binop_ty = expr_ty(bcx, binop_expr);
1585 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1586 &lhs_datum, &rhs_datum)
1591 fn trans_overloaded_op(bcx: @mut Block,
1593 callee_id: ast::NodeId,
1595 args: ~[@ast::expr],
1599 let origin = bcx.ccx().maps.method_map.get_copy(&expr.id);
1600 let fty = node_id_type(bcx, callee_id);
1601 callee::trans_call_inner(bcx,
1606 meth::trans_method_callee(bcx,
1611 callee::ArgExprs(args),
1616 fn int_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1617 llsrc: ValueRef, signed: bool) -> ValueRef {
1618 let _icx = push_ctxt("int_cast");
1620 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1621 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1622 return if dstsz == srcsz {
1623 BitCast(bcx, llsrc, lldsttype)
1624 } else if srcsz > dstsz {
1625 TruncOrBitCast(bcx, llsrc, lldsttype)
1627 SExtOrBitCast(bcx, llsrc, lldsttype)
1629 ZExtOrBitCast(bcx, llsrc, lldsttype)
1634 fn float_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
1635 llsrc: ValueRef) -> ValueRef {
1636 let _icx = push_ctxt("float_cast");
1637 let srcsz = llsrctype.float_width();
1638 let dstsz = lldsttype.float_width();
1639 return if dstsz > srcsz {
1640 FPExt(bcx, llsrc, lldsttype)
1641 } else if srcsz > dstsz {
1642 FPTrunc(bcx, llsrc, lldsttype)
1647 pub enum cast_kind {
1655 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1656 match ty::get(t).sty {
1657 ty::ty_float(*) => cast_float,
1658 ty::ty_ptr(*) => cast_pointer,
1659 ty::ty_rptr(*) => cast_pointer,
1660 ty::ty_int(*) => cast_integral,
1661 ty::ty_uint(*) => cast_integral,
1662 ty::ty_bool => cast_integral,
1663 ty::ty_enum(*) => cast_enum,
1668 fn trans_imm_cast(bcx: @mut Block, expr: @ast::expr,
1669 id: ast::NodeId) -> DatumBlock {
1670 let _icx = push_ctxt("trans_cast");
1671 let ccx = bcx.ccx();
1673 let t_out = node_id_type(bcx, id);
1676 let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1677 let ll_t_in = val_ty(llexpr);
1678 let t_in = expr_ty(bcx, expr);
1679 let ll_t_out = type_of::type_of(ccx, t_out);
1681 let k_in = cast_type_kind(t_in);
1682 let k_out = cast_type_kind(t_out);
1683 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1686 match (k_in, k_out) {
1687 (cast_integral, cast_integral) => {
1688 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1690 (cast_float, cast_float) => {
1691 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1693 (cast_integral, cast_float) => {
1695 SIToFP(bcx, llexpr, ll_t_out)
1696 } else { UIToFP(bcx, llexpr, ll_t_out) }
1698 (cast_float, cast_integral) => {
1699 if ty::type_is_signed(t_out) {
1700 FPToSI(bcx, llexpr, ll_t_out)
1701 } else { FPToUI(bcx, llexpr, ll_t_out) }
1703 (cast_integral, cast_pointer) => {
1704 IntToPtr(bcx, llexpr, ll_t_out)
1706 (cast_pointer, cast_integral) => {
1707 PtrToInt(bcx, llexpr, ll_t_out)
1709 (cast_pointer, cast_pointer) => {
1710 PointerCast(bcx, llexpr, ll_t_out)
1712 (cast_enum, cast_integral) |
1713 (cast_enum, cast_float) => {
1715 let repr = adt::represent_type(ccx, t_in);
1716 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr);
1718 cast_integral => int_cast(bcx, ll_t_out,
1719 val_ty(lldiscrim_a),
1721 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1722 _ => ccx.sess.bug("translating unsupported cast.")
1725 _ => ccx.sess.bug("translating unsupported cast.")
1727 return immediate_rvalue_bcx(bcx, newval, t_out);
1730 fn trans_assign_op(bcx: @mut Block,
1732 callee_id: ast::NodeId,
1735 src: @ast::expr) -> @mut Block
1737 let _icx = push_ctxt("trans_assign_op");
1740 debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr));
1742 // Evaluate LHS (destination), which should be an lvalue
1743 let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1745 // A user-defined operator method
1746 if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1747 // FIXME(#2528) evaluates the receiver twice!!
1748 let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false);
1749 let bcx = trans_overloaded_op(bcx,
1755 SaveIn(scratch.val));
1756 return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1759 // Evaluate RHS (source)
1760 let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1762 // Perform computation and store the result
1766 bcx, expr, dst_datum.ty, op,
1767 &dst_datum, &src_datum));
1768 return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1771 fn shorten(x: &str) -> @str {
1772 (if x.char_len() > 60 {x.slice_chars(0, 60)} else {x}).to_managed()