1 // Copyright 2012-2014 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.
12 * # Translation of Expressions
14 * Public entry points:
16 * - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
17 * storing the result into `dest`. This is the preferred form, if you
20 * - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
21 * `Datum` with the result. You can then store the datum, inspect
22 * the value, etc. This may introduce temporaries if the datum is a
25 * - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
26 * expression and ensures that the result has a cleanup associated with it,
27 * creating a temporary stack slot if necessary.
29 * - `trans_local_var -> Datum`: looks up a local variable or upvar.
31 * See doc.rs for more comments.
34 #![allow(non_camel_case_types)]
37 use lib::llvm::{ValueRef, llvm};
39 use metadata::csearch;
41 use middle::lang_items::MallocFnLangItem;
42 use middle::mem_categorization::Typer;
43 use middle::trans::_match;
44 use middle::trans::adt;
45 use middle::trans::asm;
46 use middle::trans::base::*;
47 use middle::trans::base;
48 use middle::trans::build::*;
49 use middle::trans::callee;
50 use middle::trans::cleanup;
51 use middle::trans::cleanup::CleanupMethods;
52 use middle::trans::closure;
53 use middle::trans::common::*;
54 use middle::trans::consts;
55 use middle::trans::controlflow;
56 use middle::trans::datum::*;
57 use middle::trans::debuginfo;
58 use middle::trans::glue;
59 use middle::trans::machine;
60 use middle::trans::meth;
61 use middle::trans::inline;
62 use middle::trans::tvec;
63 use middle::trans::type_of;
64 use middle::ty::struct_fields;
65 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
66 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
68 use middle::typeck::MethodCall;
70 use util::common::indenter;
71 use util::ppaux::Repr;
72 use util::nodemap::NodeMap;
73 use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc};
74 use middle::trans::type_::Type;
78 use syntax::print::pprust::{expr_to_str};
84 // These are passed around by the code generating functions to track the
85 // destination of a computation's value.
87 #[deriving(PartialEq)]
94 pub fn to_str(&self, ccx: &CrateContext) -> String {
96 SaveIn(v) => format!("SaveIn({})", ccx.tn.val_to_str(v)),
97 Ignore => "Ignore".to_string()
102 pub fn trans_into<'a>(bcx: &'a Block<'a>,
107 * This function is equivalent to `trans(bcx, expr).store_to_dest(dest)`
108 * but it may generate better optimized LLVM code.
113 if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
114 // use trans, which may be less efficient but
115 // which will perform the adjustments:
116 let datum = unpack_datum!(bcx, trans(bcx, expr));
117 return datum.store_to_dest(bcx, dest, expr.id)
120 debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
121 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
123 bcx.fcx.push_ast_cleanup_scope(expr.id);
125 let kind = ty::expr_kind(bcx.tcx(), expr);
127 ty::LvalueExpr | ty::RvalueDatumExpr => {
128 trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
130 ty::RvalueDpsExpr => {
131 trans_rvalue_dps_unadjusted(bcx, expr, dest)
133 ty::RvalueStmtExpr => {
134 trans_rvalue_stmt_unadjusted(bcx, expr)
138 bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
141 pub fn trans<'a>(bcx: &'a Block<'a>,
143 -> DatumBlock<'a, Expr> {
145 * Translates an expression, returning a datum (and new block)
146 * encapsulating the result. When possible, it is preferred to
147 * use `trans_into`, as that may avoid creating a temporary on
151 debug!("trans(expr={})", bcx.expr_to_str(expr));
156 fcx.push_ast_cleanup_scope(expr.id);
157 let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
158 let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
159 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
160 return DatumBlock::new(bcx, datum);
163 fn apply_adjustments<'a>(bcx: &'a Block<'a>,
166 -> DatumBlock<'a, Expr> {
168 * Helper for trans that apply adjustments from `expr` to `datum`,
169 * which should be the unadjusted translation of `expr`.
173 let mut datum = datum;
174 let adjustment = match bcx.tcx().adjustments.borrow().find_copy(&expr.id) {
176 return DatumBlock::new(bcx, datum);
180 debug!("unadjusted datum for expr {}: {}",
181 expr.id, datum.to_str(bcx.ccx()));
184 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
186 AutoDerefRef(ref adj) => {
187 if adj.autoderefs > 0 {
188 datum = unpack_datum!(
189 bcx, deref_multiple(bcx, expr, datum, adj.autoderefs));
192 datum = match adj.autoref {
196 Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
197 Some(AutoPtr(..)) => {
198 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
200 Some(AutoBorrowVec(..)) => {
201 unpack_datum!(bcx, auto_slice(bcx, expr, datum))
203 Some(AutoBorrowVecRef(..)) => {
204 unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
206 Some(AutoBorrowObj(..)) => {
207 unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum))
212 let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
213 let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
214 bcx = meth::trans_trait_cast(
215 bcx, datum, expr.id, SaveIn(scratch.val));
216 datum = scratch.to_expr_datum();
219 debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
220 return DatumBlock {bcx: bcx, datum: datum};
226 -> DatumBlock<'a, Expr> {
227 // This is not the most efficient thing possible; since slices
228 // are two words it'd be better if this were compiled in
229 // 'dest' mode, but I can't find a nice way to structure the
230 // code and keep it DRY that accommodates that use case at the
235 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
237 // Arrange cleanup, if not already done. This is needed in
238 // case we are auto-slicing an owned vector or some such.
239 let datum = unpack_datum!(
240 bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id));
242 let (base, len) = datum.get_vec_base_and_len(bcx);
244 // this type may have a different region/mutability than the
245 // real one, but it will have the same runtime representation
246 let slice_ty = ty::mk_slice(tcx, ty::ReStatic,
247 ty::mt { ty: unit_ty, mutbl: ast::MutImmutable });
249 let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust");
250 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
251 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
252 DatumBlock::new(bcx, scratch.to_expr_datum())
255 fn add_env<'a>(bcx: &'a Block<'a>,
258 -> DatumBlock<'a, Expr> {
259 // This is not the most efficient thing possible; since closures
260 // are two words it'd be better if this were compiled in
261 // 'dest' mode, but I can't find a nice way to structure the
262 // code and keep it DRY that accommodates that use case at the
265 let closure_ty = expr_ty_adjusted(bcx, expr);
266 let fn_ptr = datum.to_llscalarish(bcx);
267 let def = ty::resolve_expr(bcx.tcx(), expr);
268 closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
271 fn auto_slice_and_ref<'a>(
275 -> DatumBlock<'a, Expr> {
276 let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
277 auto_ref(bcx, datum, expr)
280 fn auto_borrow_obj<'a>(bcx: &'a Block<'a>,
282 source_datum: Datum<Expr>)
283 -> DatumBlock<'a, Expr> {
285 let target_obj_ty = expr_ty_adjusted(bcx, expr);
286 debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx));
288 let mut datum = source_datum.to_expr_datum();
289 datum.ty = target_obj_ty;
290 DatumBlock::new(bcx, datum)
294 pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
297 -> DatumBlock<'a, Lvalue> {
299 * Translates an expression in "lvalue" mode -- meaning that it
300 * returns a reference to the memory that the expr represents.
302 * If this expression is an rvalue, this implies introducing a
303 * temporary. In other words, something like `x().f` is
304 * translated into roughly the equivalent of
306 * { tmp = x(); tmp.f }
310 let datum = unpack_datum!(bcx, trans(bcx, expr));
311 return datum.to_lvalue_datum(bcx, name, expr.id);
314 fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
316 -> DatumBlock<'a, Expr> {
318 * A version of `trans` that ignores adjustments. You almost
319 * certainly do not want to call this directly.
324 debug!("trans_unadjusted(expr={})", bcx.expr_to_str(expr));
325 let _indenter = indenter();
327 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
329 return match ty::expr_kind(bcx.tcx(), expr) {
330 ty::LvalueExpr | ty::RvalueDatumExpr => {
331 let datum = unpack_datum!(bcx, {
332 trans_datum_unadjusted(bcx, expr)
335 DatumBlock {bcx: bcx, datum: datum}
338 ty::RvalueStmtExpr => {
339 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
340 nil(bcx, expr_ty(bcx, expr))
343 ty::RvalueDpsExpr => {
344 let ty = expr_ty(bcx, expr);
345 if type_is_zero_size(bcx.ccx(), ty) {
346 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
349 let scratch = rvalue_scratch_datum(bcx, ty, "");
350 bcx = trans_rvalue_dps_unadjusted(
351 bcx, expr, SaveIn(scratch.val));
353 // Note: this is not obviously a good idea. It causes
354 // immediate values to be loaded immediately after a
355 // return from a call or other similar expression,
356 // which in turn leads to alloca's having shorter
357 // lifetimes and hence larger stack frames. However,
358 // in turn it can lead to more register pressure.
359 // Still, in practice it seems to increase
360 // performance, since we have fewer problems with
362 let scratch = unpack_datum!(
363 bcx, scratch.to_appropriate_datum(bcx));
365 DatumBlock::new(bcx, scratch.to_expr_datum())
370 fn nil<'a>(bcx: &'a Block<'a>, ty: ty::t) -> DatumBlock<'a, Expr> {
371 let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
372 let datum = immediate_rvalue(llval, ty);
373 DatumBlock::new(bcx, datum.to_expr_datum())
377 fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
379 -> DatumBlock<'a, Expr> {
382 let _icx = push_ctxt("trans_datum_unadjusted");
385 ast::ExprParen(ref e) => {
388 ast::ExprPath(_) => {
389 trans_def(bcx, expr, bcx.def(expr.id))
391 ast::ExprField(ref base, ident, _) => {
392 trans_rec_field(bcx, &**base, ident.node)
394 ast::ExprIndex(ref base, ref idx) => {
395 trans_index(bcx, expr, &**base, &**idx)
397 ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
398 fcx.push_ast_cleanup_scope(contents.id);
399 let datum = unpack_datum!(
400 bcx, tvec::trans_uniq_vstore(bcx, expr, &**contents));
401 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
402 DatumBlock::new(bcx, datum)
404 ast::ExprBox(_, ref contents) => {
405 // Special case for `Box<T>` and `Gc<T>`
406 let box_ty = expr_ty(bcx, expr);
407 let contents_ty = expr_ty(bcx, &**contents);
408 match ty::get(box_ty).sty {
410 trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
413 trans_managed_expr(bcx, box_ty, &**contents, contents_ty)
415 _ => bcx.sess().span_bug(expr.span,
416 "expected unique or managed box")
419 ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, (**lit).clone()),
420 ast::ExprBinary(op, ref lhs, ref rhs) => {
421 trans_binary(bcx, expr, op, &**lhs, &**rhs)
423 ast::ExprUnary(op, ref x) => {
424 trans_unary(bcx, expr, op, &**x)
426 ast::ExprAddrOf(_, ref x) => {
427 trans_addr_of(bcx, expr, &**x)
429 ast::ExprCast(ref val, _) => {
430 // Datum output mode means this is a scalar cast:
431 trans_imm_cast(bcx, &**val, expr.id)
434 bcx.tcx().sess.span_bug(
436 format!("trans_rvalue_datum_unadjusted reached \
437 fall-through case: {:?}",
438 expr.node).as_slice());
443 fn trans_rec_field<'a>(bcx: &'a Block<'a>,
446 -> DatumBlock<'a, Expr> {
447 //! Translates `base.field`.
450 let _icx = push_ctxt("trans_rec_field");
452 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
453 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
454 with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
455 let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
456 let d = base_datum.get_element(
458 |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
459 DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
463 fn trans_index<'a>(bcx: &'a Block<'a>,
464 index_expr: &ast::Expr,
467 -> DatumBlock<'a, Expr> {
468 //! Translates `base[idx]`.
470 let _icx = push_ctxt("trans_index");
474 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
476 // Translate index expression and cast to a suitable LLVM integer.
477 // Rust is less strict than LLVM in this regard.
478 let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
479 let ix_val = ix_datum.to_llscalarish(bcx);
480 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
481 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
483 if ix_size < int_size {
484 if ty::type_is_signed(expr_ty(bcx, idx)) {
485 SExt(bcx, ix_val, ccx.int_type)
486 } else { ZExt(bcx, ix_val, ccx.int_type) }
487 } else if ix_size > int_size {
488 Trunc(bcx, ix_val, ccx.int_type)
494 let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), base_datum.ty));
495 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
497 let (base, len) = base_datum.get_vec_base_and_len(bcx);
499 debug!("trans_index: base {}", bcx.val_to_str(base));
500 debug!("trans_index: len {}", bcx.val_to_str(len));
502 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
503 let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
504 let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
505 let bcx = with_cond(bcx, expected, |bcx| {
506 controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
508 let elt = InBoundsGEP(bcx, base, [ix_val]);
509 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
510 DatumBlock::new(bcx, Datum::new(elt, vt.unit_ty, LvalueExpr))
513 fn trans_def<'a>(bcx: &'a Block<'a>,
514 ref_expr: &ast::Expr,
516 -> DatumBlock<'a, Expr>
518 //! Translates a reference to a path.
520 let _icx = push_ctxt("trans_def_lvalue");
522 def::DefFn(..) | def::DefStaticMethod(..) |
523 def::DefStruct(_) | def::DefVariant(..) => {
524 trans_def_fn_unadjusted(bcx, ref_expr, def)
526 def::DefStatic(did, _) => {
527 let const_ty = expr_ty(bcx, ref_expr);
529 fn get_did(ccx: &CrateContext, did: ast::DefId)
531 if did.krate != ast::LOCAL_CRATE {
532 inline::maybe_instantiate_inline(ccx, did)
538 fn get_val<'a>(bcx: &'a Block<'a>, did: ast::DefId, const_ty: ty::t)
540 // For external constants, we don't inline.
541 if did.krate == ast::LOCAL_CRATE {
542 // The LLVM global has the type of its initializer,
543 // which may not be equal to the enum's type for
545 let val = base::get_item_val(bcx.ccx(), did.node);
546 let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
547 PointerCast(bcx, val, pty)
549 match bcx.ccx().extern_const_values.borrow().find(&did) {
550 None => {} // Continue.
557 let llty = type_of::type_of(bcx.ccx(), const_ty);
558 let symbol = csearch::get_symbol(
559 &bcx.ccx().sess().cstore,
561 let llval = symbol.as_slice().with_c_str(|buf| {
562 llvm::LLVMAddGlobal(bcx.ccx().llmod,
566 bcx.ccx().extern_const_values.borrow_mut()
573 let did = get_did(bcx.ccx(), did);
574 let val = get_val(bcx, did, const_ty);
575 DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
578 DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
583 fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
587 let _icx = push_ctxt("trans_rvalue_stmt");
589 if bcx.unreachable.get() {
594 ast::ExprParen(ref e) => {
595 trans_into(bcx, &**e, Ignore)
597 ast::ExprBreak(label_opt) => {
598 controlflow::trans_break(bcx, expr.id, label_opt)
600 ast::ExprAgain(label_opt) => {
601 controlflow::trans_cont(bcx, expr.id, label_opt)
603 ast::ExprRet(ex) => {
604 controlflow::trans_ret(bcx, ex)
606 ast::ExprWhile(ref cond, ref body) => {
607 controlflow::trans_while(bcx, expr.id, &**cond, &**body)
609 ast::ExprLoop(ref body, _) => {
610 controlflow::trans_loop(bcx, expr.id, &**body)
612 ast::ExprAssign(ref dst, ref src) => {
613 let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
614 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
616 if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
617 // If there are destructors involved, make sure we
618 // are copying from an rvalue, since that cannot possible
619 // alias an lvalue. We are concerned about code like:
627 // where e.g. a : Option<Foo> and a.b :
628 // Option<Foo>. In that case, freeing `a` before the
629 // assignment may also free `a.b`!
631 // We could avoid this intermediary with some analysis
632 // to determine whether `dst` may possibly own `src`.
633 let src_datum = unpack_datum!(
634 bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
635 bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
636 src_datum.store_to(bcx, dst_datum.val)
638 src_datum.store_to(bcx, dst_datum.val)
641 ast::ExprAssignOp(op, ref dst, ref src) => {
642 trans_assign_op(bcx, expr, op, &**dst, src.clone())
644 ast::ExprInlineAsm(ref a) => {
645 asm::trans_inline_asm(bcx, a)
648 bcx.tcx().sess.span_bug(
650 format!("trans_rvalue_stmt_unadjusted reached \
651 fall-through case: {:?}",
652 expr.node).as_slice());
657 fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
661 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
667 ast::ExprParen(ref e) => {
668 trans_into(bcx, &**e, dest)
670 ast::ExprPath(_) => {
671 trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
673 ast::ExprIf(ref cond, ref thn, els) => {
674 controlflow::trans_if(bcx, expr.id, &**cond, thn.clone(), els, dest)
676 ast::ExprMatch(ref discr, ref arms) => {
677 _match::trans_match(bcx, expr, &**discr, arms.as_slice(), dest)
679 ast::ExprBlock(ref blk) => {
680 controlflow::trans_block(bcx, &**blk, dest)
682 ast::ExprStruct(_, ref fields, base) => {
683 trans_rec_or_struct(bcx,
690 ast::ExprTup(ref args) => {
691 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
692 let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
693 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
694 trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
696 ast::ExprLit(lit) => {
698 ast::LitStr(ref s, _) => {
699 tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
705 "trans_rvalue_dps_unadjusted shouldn't be \
706 translating this type of literal")
710 ast::ExprVstore(ref contents, ast::ExprVstoreSlice) |
711 ast::ExprVstore(ref contents, ast::ExprVstoreMutSlice) => {
712 fcx.push_ast_cleanup_scope(contents.id);
713 bcx = tvec::trans_slice_vstore(bcx, expr, &**contents, dest);
714 fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
716 ast::ExprVec(..) | ast::ExprRepeat(..) => {
717 tvec::trans_fixed_vstore(bcx, expr, expr, dest)
719 ast::ExprFnBlock(ref decl, ref body) |
720 ast::ExprProc(ref decl, ref body) => {
721 let expr_ty = expr_ty(bcx, expr);
722 let store = ty::ty_closure_store(expr_ty);
723 debug!("translating block function {} with type {}",
724 expr_to_str(expr), expr_ty.repr(tcx));
725 closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
727 ast::ExprCall(ref f, ref args) => {
728 if bcx.tcx().is_method_call(expr.id) {
729 let callee_datum = unpack_datum!(bcx, trans(bcx, &**f));
730 trans_overloaded_call(bcx,
736 callee::trans_call(bcx,
739 callee::ArgExprs(args.as_slice()),
743 ast::ExprMethodCall(_, _, ref args) => {
744 callee::trans_method_call(bcx,
747 callee::ArgExprs(args.as_slice()),
750 ast::ExprBinary(_, ref lhs, ref rhs) => {
751 // if not overloaded, would be RvalueDatumExpr
752 let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
753 let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
754 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
755 Some((rhs_datum, rhs.id)), Some(dest)).bcx
757 ast::ExprUnary(_, ref subexpr) => {
758 // if not overloaded, would be RvalueDatumExpr
759 let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
760 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
761 arg, None, Some(dest)).bcx
763 ast::ExprIndex(ref base, ref idx) => {
764 // if not overloaded, would be RvalueDatumExpr
765 let base = unpack_datum!(bcx, trans(bcx, &**base));
766 let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
767 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
768 Some((idx_datum, idx.id)), Some(dest)).bcx
770 ast::ExprCast(ref val, _) => {
771 // DPS output mode means this is a trait cast:
772 if ty::type_is_trait(node_id_type(bcx, expr.id)) {
773 let datum = unpack_datum!(bcx, trans(bcx, &**val));
774 meth::trans_trait_cast(bcx, datum, expr.id, dest)
776 bcx.tcx().sess.span_bug(expr.span,
777 "expr_cast of non-trait");
780 ast::ExprAssignOp(op, ref dst, ref src) => {
781 trans_assign_op(bcx, expr, op, &**dst, src.clone())
784 bcx.tcx().sess.span_bug(
786 format!("trans_rvalue_dps_unadjusted reached fall-through \
788 expr.node).as_slice());
793 fn trans_def_dps_unadjusted<'a>(
795 ref_expr: &ast::Expr,
799 let _icx = push_ctxt("trans_def_dps_unadjusted");
801 let lldest = match dest {
802 SaveIn(lldest) => lldest,
803 Ignore => { return bcx; }
807 def::DefVariant(tid, vid, _) => {
808 let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
809 if variant_info.args.len() > 0u {
811 let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
812 Store(bcx, llfn, lldest);
816 let ty = expr_ty(bcx, ref_expr);
817 let repr = adt::represent_type(bcx.ccx(), ty);
818 adt::trans_start_init(bcx, &*repr, lldest,
819 variant_info.disr_val);
823 def::DefStruct(_) => {
824 let ty = expr_ty(bcx, ref_expr);
825 match ty::get(ty).sty {
826 ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
827 let repr = adt::represent_type(bcx.ccx(), ty);
828 adt::trans_start_init(bcx, &*repr, lldest, 0);
835 bcx.tcx().sess.span_bug(ref_expr.span, format!(
836 "Non-DPS def {:?} referened by {}",
837 def, bcx.node_id_to_str(ref_expr.id)).as_slice());
842 fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
843 ref_expr: &ast::Expr,
844 def: def::Def) -> DatumBlock<'a, Expr> {
845 let _icx = push_ctxt("trans_def_datum_unadjusted");
847 let llfn = match def {
849 def::DefStruct(did) | def::DefVariant(_, did, _) |
850 def::DefStaticMethod(did, def::FromImpl(_), _) => {
851 callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
853 def::DefStaticMethod(impl_did, def::FromTrait(trait_did), _) => {
854 meth::trans_static_method_callee(bcx, impl_did,
855 trait_did, ref_expr.id)
858 bcx.tcx().sess.span_bug(ref_expr.span, format!(
859 "trans_def_fn_unadjusted invoked on: {:?} for {}",
861 ref_expr.repr(bcx.tcx())).as_slice());
865 let fn_ty = expr_ty(bcx, ref_expr);
866 DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue))))
869 pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
873 * Translates a reference to a local variable or argument.
874 * This always results in an lvalue datum.
877 let _icx = push_ctxt("trans_local_var");
880 def::DefUpvar(nid, _, _, _) => {
881 // Can't move upvars, so this is never a ZeroMemLastUse.
882 let local_ty = node_id_type(bcx, nid);
883 match bcx.fcx.llupvars.borrow().find(&nid) {
884 Some(&val) => Datum::new(val, local_ty, Lvalue),
886 bcx.sess().bug(format!(
887 "trans_local_var: no llval for upvar {:?} found",
892 def::DefArg(nid, _) => {
893 take_local(bcx, &*bcx.fcx.llargs.borrow(), nid)
895 def::DefLocal(nid, _) | def::DefBinding(nid, _) => {
896 take_local(bcx, &*bcx.fcx.lllocals.borrow(), nid)
899 bcx.sess().unimpl(format!(
900 "unsupported def type in trans_local_var: {:?}",
905 fn take_local<'a>(bcx: &'a Block<'a>,
906 table: &NodeMap<Datum<Lvalue>>,
909 let datum = match table.find(&nid) {
912 bcx.sess().bug(format!(
913 "trans_local_var: no datum for local/arg {:?} found",
917 debug!("take_local(nid={:?}, v={}, ty={})",
918 nid, bcx.val_to_str(datum.val), bcx.ty_to_str(datum.ty));
923 pub fn with_field_tys<R>(tcx: &ty::ctxt,
925 node_id_opt: Option<ast::NodeId>,
926 op: |ty::Disr, (&[ty::field])| -> R)
929 * Helper for enumerating the field types of structs, enums, or records.
930 * The optional node ID here is the node ID of the path identifying the enum
931 * variant in use. If none, this cannot possibly an enum variant (so, if it
932 * is and `node_id_opt` is none, this function fails).
935 match ty::get(ty).sty {
936 ty::ty_struct(did, ref substs) => {
937 op(0, struct_fields(tcx, did, substs).as_slice())
940 ty::ty_enum(_, ref substs) => {
941 // We want the *variant* ID here, not the enum ID.
944 tcx.sess.bug(format!(
945 "cannot get field types from the enum type {} \
947 ty.repr(tcx)).as_slice());
950 let def = tcx.def_map.borrow().get_copy(&node_id);
952 def::DefVariant(enum_id, variant_id, _) => {
953 let variant_info = ty::enum_variant_with_id(
954 tcx, enum_id, variant_id);
955 op(variant_info.disr_val,
961 tcx.sess.bug("resolve didn't map this expr to a \
970 tcx.sess.bug(format!(
971 "cannot get field types from the type {}",
972 ty.repr(tcx)).as_slice());
977 fn trans_rec_or_struct<'a>(
979 fields: &[ast::Field],
980 base: Option<Gc<ast::Expr>>,
981 expr_span: codemap::Span,
985 let _icx = push_ctxt("trans_rec");
988 let ty = node_id_type(bcx, id);
990 with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
991 let mut need_base = Vec::from_elem(field_tys.len(), true);
993 let numbered_fields = fields.iter().map(|field| {
995 field_tys.iter().position(|field_ty|
996 field_ty.ident.name == field.ident.node.name);
999 *need_base.get_mut(i) = false;
1003 tcx.sess.span_bug(field.span,
1004 "Couldn't find field in struct type")
1007 }).collect::<Vec<_>>();
1008 let optbase = match base {
1009 Some(base_expr) => {
1010 let mut leftovers = Vec::new();
1011 for (i, b) in need_base.iter().enumerate() {
1013 leftovers.push((i, field_tys[i].mt.ty))
1016 Some(StructBaseInfo {expr: base_expr,
1017 fields: leftovers })
1020 if need_base.iter().any(|b| *b) {
1021 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1027 let repr = adt::represent_type(bcx.ccx(), ty);
1028 trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
1033 * Information that `trans_adt` needs in order to fill in the fields
1034 * of a struct copied from a base struct (e.g., from an expression
1035 * like `Foo { a: b, ..base }`.
1037 * Note that `fields` may be empty; the base expression must always be
1038 * evaluated for side-effects.
1040 struct StructBaseInfo {
1041 /// The base expression; will be evaluated after all explicit fields.
1042 expr: Gc<ast::Expr>,
1043 /// The indices of fields to copy paired with their types.
1044 fields: Vec<(uint, ty::t)> }
1047 * Constructs an ADT instance:
1049 * - `fields` should be a list of field indices paired with the
1050 * expression to store into that field. The initializers will be
1051 * evaluated in the order specified by `fields`.
1053 * - `optbase` contains information on the base struct (if any) from
1054 * which remaining fields are copied; see comments on `StructBaseInfo`.
1060 fields: &[(uint, Gc<ast::Expr>)],
1061 optbase: Option<StructBaseInfo>,
1064 let _icx = push_ctxt("trans_adt");
1067 let addr = match dest {
1069 for &(_i, ref e) in fields.iter() {
1070 bcx = trans_into(bcx, &**e, Ignore);
1072 for sbi in optbase.iter() {
1073 // FIXME #7261: this moves entire base, not just certain fields
1074 bcx = trans_into(bcx, &*sbi.expr, Ignore);
1081 // This scope holds intermediates that must be cleaned should
1082 // failure occur before the ADT as a whole is ready.
1083 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1085 adt::trans_start_init(bcx, repr, addr, discr);
1087 for &(i, ref e) in fields.iter() {
1088 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1089 let e_ty = expr_ty_adjusted(bcx, &**e);
1090 bcx = trans_into(bcx, &**e, SaveIn(dest));
1091 fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
1095 for base in optbase.iter() {
1096 // FIXME #6573: is it sound to use the destination's repr on the base?
1097 // And, would it ever be reasonable to be here with discr != 0?
1098 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
1099 for &(i, t) in base.fields.iter() {
1100 let datum = base_datum.get_element(
1102 |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i));
1103 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1104 bcx = datum.store_to(bcx, dest);
1108 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1114 fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
1117 -> DatumBlock<'a, Expr> {
1118 // must not be a string constant, that is a RvalueDpsExpr
1119 let _icx = push_ctxt("trans_immediate_lit");
1120 let ty = expr_ty(bcx, expr);
1121 let v = consts::const_lit(bcx.ccx(), expr, lit);
1122 immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
1125 fn trans_unary<'a>(bcx: &'a Block<'a>,
1128 sub_expr: &ast::Expr)
1129 -> DatumBlock<'a, Expr> {
1130 let ccx = bcx.ccx();
1132 let _icx = push_ctxt("trans_unary_datum");
1134 let method_call = MethodCall::expr(expr.id);
1136 // The only overloaded operator that is translated to a datum
1137 // is an overloaded deref, since it is always yields a `&T`.
1138 // Otherwise, we should be in the RvalueDpsExpr path.
1140 op == ast::UnDeref ||
1141 !ccx.tcx.method_map.borrow().contains_key(&method_call));
1143 let un_ty = expr_ty(bcx, expr);
1147 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1148 let llresult = if ty::type_is_bool(un_ty) {
1149 let val = datum.to_llscalarish(bcx);
1150 let llcond = ICmp(bcx,
1153 C_bool(ccx, false));
1154 Select(bcx, llcond, C_bool(ccx, true), C_bool(ccx, false))
1156 // Note: `Not` is bitwise, not suitable for logical not.
1157 Not(bcx, datum.to_llscalarish(bcx))
1159 immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1162 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1163 let val = datum.to_llscalarish(bcx);
1165 if ty::type_is_fp(un_ty) {
1171 immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1174 trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1177 trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1180 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1181 deref_once(bcx, expr, datum, 0)
1186 fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
1188 contents: &ast::Expr,
1190 -> DatumBlock<'a, Expr> {
1191 let _icx = push_ctxt("trans_uniq_expr");
1193 let llty = type_of::type_of(bcx.ccx(), contents_ty);
1194 let size = llsize_of(bcx.ccx(), llty);
1195 let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
1196 // We need to a make a pointer type because box_ty is ty_bot
1197 // if content_ty is, e.g. box fail!().
1198 let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
1199 let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
1200 // Unique boxes do not allocate for zero-size types. The standard library
1201 // may assume that `free` is never called on the pointer returned for
1202 // `Box<ZeroSizeType>`.
1203 let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
1204 trans_into(bcx, contents, SaveIn(val))
1206 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1207 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1208 val, cleanup::HeapExchange, contents_ty);
1209 let bcx = trans_into(bcx, contents, SaveIn(val));
1210 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1213 immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
1216 fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
1218 contents: &ast::Expr,
1220 -> DatumBlock<'a, Expr> {
1221 let _icx = push_ctxt("trans_managed_expr");
1223 let ty = type_of::type_of(bcx.ccx(), contents_ty);
1224 let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
1225 llsize_of(bcx.ccx(), ty));
1226 let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
1228 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1229 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1230 bx, cleanup::HeapManaged, contents_ty);
1231 let bcx = trans_into(bcx, contents, SaveIn(body));
1232 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1233 immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
1236 fn trans_addr_of<'a>(bcx: &'a Block<'a>,
1238 subexpr: &ast::Expr)
1239 -> DatumBlock<'a, Expr> {
1240 let _icx = push_ctxt("trans_addr_of");
1242 let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1243 let ty = expr_ty(bcx, expr);
1244 return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
1247 // Important to get types for both lhs and rhs, because one might be _|_
1248 // and the other not.
1249 fn trans_eager_binop<'a>(
1251 binop_expr: &ast::Expr,
1258 -> DatumBlock<'a, Expr> {
1259 let _icx = push_ctxt("trans_eager_binop");
1261 let tcx = bcx.tcx();
1262 let is_simd = ty::type_is_simd(tcx, lhs_t);
1264 if ty::type_is_bot(lhs_t) { rhs_t }
1265 else if is_simd { ty::simd_type(tcx, lhs_t) }
1268 let is_float = ty::type_is_fp(intype);
1269 let is_signed = ty::type_is_signed(intype);
1271 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1274 let val = match op {
1276 if is_float { FAdd(bcx, lhs, rhs) }
1277 else { Add(bcx, lhs, rhs) }
1280 if is_float { FSub(bcx, lhs, rhs) }
1281 else { Sub(bcx, lhs, rhs) }
1284 if is_float { FMul(bcx, lhs, rhs) }
1285 else { Mul(bcx, lhs, rhs) }
1291 // Only zero-check integers; fp /0 is NaN
1292 bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
1293 op, lhs, rhs, rhs_t);
1305 // Only zero-check integers; fp %0 is NaN
1306 bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
1307 op, lhs, rhs, rhs_t);
1315 ast::BiBitOr => Or(bcx, lhs, rhs),
1316 ast::BiBitAnd => And(bcx, lhs, rhs),
1317 ast::BiBitXor => Xor(bcx, lhs, rhs),
1318 ast::BiShl => Shl(bcx, lhs, rhs),
1322 } else { LShr(bcx, lhs, rhs) }
1324 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1325 if ty::type_is_bot(rhs_t) {
1326 C_bool(bcx.ccx(), false)
1327 } else if ty::type_is_scalar(rhs_t) {
1328 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1330 ZExt(bcx, cmpr.val, Type::i8(bcx.ccx()))
1332 base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
1334 bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
1338 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1342 immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1345 // refinement types would obviate the need for this
1346 enum lazy_binop_ty {
1351 fn trans_lazy_binop<'a>(
1353 binop_expr: &ast::Expr,
1357 -> DatumBlock<'a, Expr> {
1358 let _icx = push_ctxt("trans_lazy_binop");
1359 let binop_ty = expr_ty(bcx, binop_expr);
1362 let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
1363 let lhs = lhs.to_llscalarish(past_lhs);
1365 if past_lhs.unreachable.get() {
1366 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1369 let join = fcx.new_id_block("join", binop_expr.id);
1370 let before_rhs = fcx.new_id_block("before_rhs", b.id);
1372 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1374 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1375 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1378 let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
1379 let rhs = rhs.to_llscalarish(past_rhs);
1381 if past_rhs.unreachable.get() {
1382 return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1385 Br(past_rhs, join.llbb);
1386 let phi = Phi(join, Type::bool(bcx.ccx()), [lhs, rhs],
1387 [past_lhs.llbb, past_rhs.llbb]);
1389 return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1392 fn trans_binary<'a>(bcx: &'a Block<'a>,
1397 -> DatumBlock<'a, Expr> {
1398 let _icx = push_ctxt("trans_binary");
1399 let ccx = bcx.ccx();
1401 // if overloaded, would be RvalueDpsExpr
1402 assert!(!ccx.tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1406 trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1409 trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1413 let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
1414 let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1415 let binop_ty = expr_ty(bcx, expr);
1417 debug!("trans_binary (expr {}): lhs_datum={}",
1419 lhs_datum.to_str(ccx));
1420 let lhs_ty = lhs_datum.ty;
1421 let lhs = lhs_datum.to_llscalarish(bcx);
1423 debug!("trans_binary (expr {}): rhs_datum={}",
1425 rhs_datum.to_str(ccx));
1426 let rhs_ty = rhs_datum.ty;
1427 let rhs = rhs_datum.to_llscalarish(bcx);
1428 trans_eager_binop(bcx, expr, binop_ty, op,
1429 lhs_ty, lhs, rhs_ty, rhs)
1434 fn trans_overloaded_op<'a, 'b>(
1437 method_call: MethodCall,
1439 rhs: Option<(Datum<Expr>, ast::NodeId)>,
1442 let method_ty = bcx.tcx().method_map.borrow().get(&method_call).ty;
1443 callee::trans_call_inner(bcx,
1444 Some(expr_info(expr)),
1445 monomorphize_type(bcx, method_ty),
1446 |bcx, arg_cleanup_scope| {
1447 meth::trans_method_callee(bcx,
1452 callee::ArgOverloadedOp(lhs, rhs),
1456 fn trans_overloaded_call<'a>(
1457 mut bcx: &'a Block<'a>,
1459 callee: Datum<Expr>,
1460 args: &[Gc<ast::Expr>],
1463 // Evaluate and tuple the arguments.
1464 let tuple_type = ty::mk_tup(bcx.tcx(),
1466 .map(|e| expr_ty(bcx, &**e))
1468 let repr = adt::represent_type(bcx.ccx(), tuple_type);
1469 let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
1470 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
1471 let argument_scope = bcx.fcx.push_custom_cleanup_scope();
1474 lvalue_scratch_datum(bcx,
1478 cleanup::CustomScope(
1485 numbered_fields.as_slice(),
1490 let method_call = typeck::MethodCall::expr(expr.id);
1491 let method_type = bcx.tcx()
1496 let callee_rvalue = unpack_datum!(bcx,
1497 callee.to_rvalue_datum(bcx, "callee"));
1498 let tuple_datum = tuple_datum.to_expr_datum();
1499 let tuple_rvalue = unpack_datum!(bcx,
1500 tuple_datum.to_rvalue_datum(bcx,
1502 let argument_values = [
1503 callee_rvalue.add_clean(bcx.fcx,
1504 cleanup::CustomScope(argument_scope)),
1505 tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope))
1508 callee::trans_call_inner(bcx,
1509 Some(expr_info(expr)),
1510 monomorphize_type(bcx,
1512 |bcx, arg_cleanup_scope| {
1513 meth::trans_method_callee(
1519 callee::ArgVals(argument_values),
1522 bcx.fcx.pop_custom_cleanup_scope(argument_scope);
1526 fn int_cast(bcx: &Block,
1532 let _icx = push_ctxt("int_cast");
1534 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1535 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1536 return if dstsz == srcsz {
1537 BitCast(bcx, llsrc, lldsttype)
1538 } else if srcsz > dstsz {
1539 TruncOrBitCast(bcx, llsrc, lldsttype)
1541 SExtOrBitCast(bcx, llsrc, lldsttype)
1543 ZExtOrBitCast(bcx, llsrc, lldsttype)
1548 fn float_cast(bcx: &Block,
1553 let _icx = push_ctxt("float_cast");
1554 let srcsz = llsrctype.float_width();
1555 let dstsz = lldsttype.float_width();
1556 return if dstsz > srcsz {
1557 FPExt(bcx, llsrc, lldsttype)
1558 } else if srcsz > dstsz {
1559 FPTrunc(bcx, llsrc, lldsttype)
1563 #[deriving(PartialEq)]
1564 pub enum cast_kind {
1572 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1573 match ty::get(t).sty {
1574 ty::ty_char => cast_integral,
1575 ty::ty_float(..) => cast_float,
1576 ty::ty_ptr(..) => cast_pointer,
1577 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
1578 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other,
1581 ty::ty_bare_fn(..) => cast_pointer,
1582 ty::ty_int(..) => cast_integral,
1583 ty::ty_uint(..) => cast_integral,
1584 ty::ty_bool => cast_integral,
1585 ty::ty_enum(..) => cast_enum,
1590 fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
1593 -> DatumBlock<'a, Expr> {
1594 let _icx = push_ctxt("trans_cast");
1596 let ccx = bcx.ccx();
1598 let t_in = expr_ty(bcx, expr);
1599 let t_out = node_id_type(bcx, id);
1600 let k_in = cast_type_kind(t_in);
1601 let k_out = cast_type_kind(t_out);
1602 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1603 let ll_t_in = type_of::type_of(ccx, t_in);
1604 let ll_t_out = type_of::type_of(ccx, t_out);
1606 // Convert the value to be cast into a ValueRef, either by-ref or
1607 // by-value as appropriate given its type:
1608 let datum = unpack_datum!(bcx, trans(bcx, expr));
1609 let newval = match (k_in, k_out) {
1610 (cast_integral, cast_integral) => {
1611 let llexpr = datum.to_llscalarish(bcx);
1612 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1614 (cast_float, cast_float) => {
1615 let llexpr = datum.to_llscalarish(bcx);
1616 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1618 (cast_integral, cast_float) => {
1619 let llexpr = datum.to_llscalarish(bcx);
1621 SIToFP(bcx, llexpr, ll_t_out)
1622 } else { UIToFP(bcx, llexpr, ll_t_out) }
1624 (cast_float, cast_integral) => {
1625 let llexpr = datum.to_llscalarish(bcx);
1626 if ty::type_is_signed(t_out) {
1627 FPToSI(bcx, llexpr, ll_t_out)
1628 } else { FPToUI(bcx, llexpr, ll_t_out) }
1630 (cast_integral, cast_pointer) => {
1631 let llexpr = datum.to_llscalarish(bcx);
1632 IntToPtr(bcx, llexpr, ll_t_out)
1634 (cast_pointer, cast_integral) => {
1635 let llexpr = datum.to_llscalarish(bcx);
1636 PtrToInt(bcx, llexpr, ll_t_out)
1638 (cast_pointer, cast_pointer) => {
1639 let llexpr = datum.to_llscalarish(bcx);
1640 PointerCast(bcx, llexpr, ll_t_out)
1642 (cast_enum, cast_integral) |
1643 (cast_enum, cast_float) => {
1645 let repr = adt::represent_type(ccx, t_in);
1646 let datum = unpack_datum!(
1647 bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
1648 let llexpr_ptr = datum.to_llref();
1650 adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
1652 cast_integral => int_cast(bcx, ll_t_out,
1653 val_ty(lldiscrim_a),
1655 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1657 ccx.sess().bug(format!("translating unsupported cast: \
1658 {} ({:?}) -> {} ({:?})",
1659 t_in.repr(bcx.tcx()),
1661 t_out.repr(bcx.tcx()),
1666 _ => ccx.sess().bug(format!("translating unsupported cast: \
1667 {} ({:?}) -> {} ({:?})",
1668 t_in.repr(bcx.tcx()),
1670 t_out.repr(bcx.tcx()),
1673 return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
1676 fn trans_assign_op<'a>(
1683 let _icx = push_ctxt("trans_assign_op");
1686 debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
1688 // User-defined operator methods cannot be used with `+=` etc right now
1689 assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1691 // Evaluate LHS (destination), which should be an lvalue
1692 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1693 assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
1694 let dst_ty = dst_datum.ty;
1695 let dst = Load(bcx, dst_datum.val);
1698 let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
1699 let rhs_ty = rhs_datum.ty;
1700 let rhs = rhs_datum.to_llscalarish(bcx);
1702 // Perform computation and store the result
1703 let result_datum = unpack_datum!(
1704 bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1705 dst_ty, dst, rhs_ty, rhs));
1706 return result_datum.store_to(bcx, dst_datum.val);
1709 fn auto_ref<'a>(bcx: &'a Block<'a>,
1712 -> DatumBlock<'a, Expr> {
1715 // Ensure cleanup of `datum` if not already scheduled and obtain
1716 // a "by ref" pointer.
1717 let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
1719 // Compute final type. Note that we are loose with the region and
1720 // mutability, since those things don't matter in trans.
1721 let referent_ty = lv_datum.ty;
1722 let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
1725 let llref = lv_datum.to_llref();
1727 // Construct the resulting datum, using what was the "by ref"
1728 // ValueRef of type `referent_ty` to be the "by value" ValueRef
1729 // of type `&referent_ty`.
1730 DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(ByValue))))
1733 fn deref_multiple<'a>(bcx: &'a Block<'a>,
1737 -> DatumBlock<'a, Expr> {
1739 let mut datum = datum;
1740 for i in range(1, times+1) {
1741 datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
1743 DatumBlock { bcx: bcx, datum: datum }
1746 fn deref_once<'a>(bcx: &'a Block<'a>,
1750 -> DatumBlock<'a, Expr> {
1751 let ccx = bcx.ccx();
1753 debug!("deref_once(expr={}, datum={}, derefs={})",
1754 expr.repr(bcx.tcx()),
1760 // Check for overloaded deref.
1761 let method_call = MethodCall {
1763 autoderef: derefs as u32
1765 let method_ty = ccx.tcx.method_map.borrow()
1766 .find(&method_call).map(|method| method.ty);
1767 let datum = match method_ty {
1768 Some(method_ty) => {
1769 // Overloaded. Evaluate `trans_overloaded_op`, which will
1770 // invoke the user's deref() method, which basically
1771 // converts from the `Shaht<T>` pointer that we have into
1772 // a `&T` pointer. We can then proceed down the normal
1773 // path (below) to dereference that `&T`.
1774 let datum = if derefs == 0 {
1777 // Always perform an AutoPtr when applying an overloaded auto-deref.
1778 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
1780 let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
1781 datum, None, None));
1782 let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
1783 Datum::new(val, ref_ty, RvalueExpr(Rvalue::new(ByValue)))
1786 // Not overloaded. We already have a pointer we know how to deref.
1791 let r = match ty::get(datum.ty).sty {
1792 ty::ty_uniq(content_ty) => {
1793 match ty::get(content_ty).sty {
1794 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
1795 => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"),
1796 _ => deref_owned_pointer(bcx, expr, datum, content_ty),
1800 ty::ty_box(content_ty) => {
1801 let datum = unpack_datum!(
1802 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
1803 let llptrref = datum.to_llref();
1804 let llptr = Load(bcx, llptrref);
1805 let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
1806 DatumBlock::new(bcx, Datum::new(llbody, content_ty, LvalueExpr))
1809 ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
1810 ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
1811 match ty::get(content_ty).sty {
1812 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
1813 => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"),
1815 assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
1817 let ptr = datum.to_llscalarish(bcx);
1819 // Always generate an lvalue datum, even if datum.mode is
1820 // an rvalue. This is because datum.mode is only an
1821 // rvalue for non-owning pointers like &T or *T, in which
1822 // case cleanup *is* scheduled elsewhere, by the true
1823 // owner (or, in the case of *T, by the user).
1824 DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
1830 bcx.tcx().sess.span_bug(
1832 format!("deref invoked on expr of illegal type {}",
1833 datum.ty.repr(bcx.tcx())).as_slice());
1837 debug!("deref_once(expr={}, derefs={}, result={})",
1838 expr.id, derefs, r.datum.to_str(ccx));
1842 fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
1846 -> DatumBlock<'a, Expr> {
1848 * We microoptimize derefs of owned pointers a bit here.
1849 * Basically, the idea is to make the deref of an rvalue
1850 * result in an rvalue. This helps to avoid intermediate stack
1851 * slots in the resulting LLVM. The idea here is that, if the
1852 * `Box<T>` pointer is an rvalue, then we can schedule a *shallow*
1853 * free of the `Box<T>` pointer, and then return a ByRef rvalue
1854 * into the pointer. Because the free is shallow, it is legit
1855 * to return an rvalue, because we know that the contents are
1856 * not yet scheduled to be freed. The language rules ensure that the
1857 * contents will be used (or moved) before the free occurs.
1861 RvalueExpr(Rvalue { mode: ByRef }) => {
1862 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1863 let ptr = Load(bcx, datum.val);
1864 if !type_is_zero_size(bcx.ccx(), content_ty) {
1865 bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange, content_ty);
1868 RvalueExpr(Rvalue { mode: ByValue }) => {
1869 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1870 if !type_is_zero_size(bcx.ccx(), content_ty) {
1871 bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange,
1878 // If we had an rvalue in, we produce an rvalue out.
1879 let (llptr, kind) = match datum.kind {
1881 (Load(bcx, datum.val), LvalueExpr)
1883 RvalueExpr(Rvalue { mode: ByRef }) => {
1884 (Load(bcx, datum.val), RvalueExpr(Rvalue::new(ByRef)))
1886 RvalueExpr(Rvalue { mode: ByValue }) => {
1887 (datum.val, RvalueExpr(Rvalue::new(ByRef)))
1891 let datum = Datum { ty: content_ty, val: llptr, kind: kind };
1892 DatumBlock { bcx: bcx, datum: datum }