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};
69 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 dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
615 if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
616 // If there are destructors involved, make sure we
617 // are copying from an rvalue, since that cannot possible
618 // alias an lvalue. We are concerned about code like:
626 // where e.g. a : Option<Foo> and a.b :
627 // Option<Foo>. In that case, freeing `a` before the
628 // assignment may also free `a.b`!
630 // We could avoid this intermediary with some analysis
631 // to determine whether `dst` may possibly own `src`.
632 let src_datum = unpack_datum!(bcx, trans(bcx, &**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 trans_into(bcx, &**src, SaveIn(dst_datum.to_llref()))
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 Xor(bcx, val, C_bool(ccx, true))
1152 // Note: `Not` is bitwise, not suitable for logical not.
1153 Not(bcx, datum.to_llscalarish(bcx))
1155 immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1158 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1159 let val = datum.to_llscalarish(bcx);
1161 if ty::type_is_fp(un_ty) {
1167 immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1170 trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1173 trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1176 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1177 deref_once(bcx, expr, datum, method_call)
1182 fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
1184 contents: &ast::Expr,
1186 -> DatumBlock<'a, Expr> {
1187 let _icx = push_ctxt("trans_uniq_expr");
1189 let llty = type_of::type_of(bcx.ccx(), contents_ty);
1190 let size = llsize_of(bcx.ccx(), llty);
1191 let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
1192 // We need to a make a pointer type because box_ty is ty_bot
1193 // if content_ty is, e.g. box fail!().
1194 let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
1195 let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
1196 // Unique boxes do not allocate for zero-size types. The standard library
1197 // may assume that `free` is never called on the pointer returned for
1198 // `Box<ZeroSizeType>`.
1199 let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
1200 trans_into(bcx, contents, SaveIn(val))
1202 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1203 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1204 val, cleanup::HeapExchange, contents_ty);
1205 let bcx = trans_into(bcx, contents, SaveIn(val));
1206 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1209 immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
1212 fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
1214 contents: &ast::Expr,
1216 -> DatumBlock<'a, Expr> {
1217 let _icx = push_ctxt("trans_managed_expr");
1219 let ty = type_of::type_of(bcx.ccx(), contents_ty);
1220 let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
1221 llsize_of(bcx.ccx(), ty));
1222 let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
1224 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1225 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1226 bx, cleanup::HeapManaged, contents_ty);
1227 let bcx = trans_into(bcx, contents, SaveIn(body));
1228 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1229 immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
1232 fn trans_addr_of<'a>(bcx: &'a Block<'a>,
1234 subexpr: &ast::Expr)
1235 -> DatumBlock<'a, Expr> {
1236 let _icx = push_ctxt("trans_addr_of");
1238 let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1239 let ty = expr_ty(bcx, expr);
1240 return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
1243 // Important to get types for both lhs and rhs, because one might be _|_
1244 // and the other not.
1245 fn trans_eager_binop<'a>(
1247 binop_expr: &ast::Expr,
1254 -> DatumBlock<'a, Expr> {
1255 let _icx = push_ctxt("trans_eager_binop");
1257 let tcx = bcx.tcx();
1258 let is_simd = ty::type_is_simd(tcx, lhs_t);
1260 if ty::type_is_bot(lhs_t) { rhs_t }
1261 else if is_simd { ty::simd_type(tcx, lhs_t) }
1264 let is_float = ty::type_is_fp(intype);
1265 let is_signed = ty::type_is_signed(intype);
1267 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1270 let val = match op {
1272 if is_float { FAdd(bcx, lhs, rhs) }
1273 else { Add(bcx, lhs, rhs) }
1276 if is_float { FSub(bcx, lhs, rhs) }
1277 else { Sub(bcx, lhs, rhs) }
1280 if is_float { FMul(bcx, lhs, rhs) }
1281 else { Mul(bcx, lhs, rhs) }
1287 // Only zero-check integers; fp /0 is NaN
1288 bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
1289 op, lhs, rhs, rhs_t);
1301 // Only zero-check integers; fp %0 is NaN
1302 bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
1303 op, lhs, rhs, rhs_t);
1311 ast::BiBitOr => Or(bcx, lhs, rhs),
1312 ast::BiBitAnd => And(bcx, lhs, rhs),
1313 ast::BiBitXor => Xor(bcx, lhs, rhs),
1314 ast::BiShl => Shl(bcx, lhs, rhs),
1318 } else { LShr(bcx, lhs, rhs) }
1320 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1321 if ty::type_is_bot(rhs_t) {
1322 C_bool(bcx.ccx(), false)
1323 } else if ty::type_is_scalar(rhs_t) {
1324 unpack_result!(bcx, base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op))
1326 base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
1328 bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
1332 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1336 immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1339 // refinement types would obviate the need for this
1340 enum lazy_binop_ty {
1345 fn trans_lazy_binop<'a>(
1347 binop_expr: &ast::Expr,
1351 -> DatumBlock<'a, Expr> {
1352 let _icx = push_ctxt("trans_lazy_binop");
1353 let binop_ty = expr_ty(bcx, binop_expr);
1356 let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
1357 let lhs = lhs.to_llscalarish(past_lhs);
1359 if past_lhs.unreachable.get() {
1360 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1363 let join = fcx.new_id_block("join", binop_expr.id);
1364 let before_rhs = fcx.new_id_block("before_rhs", b.id);
1367 lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb),
1368 lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb)
1371 let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
1372 let rhs = rhs.to_llscalarish(past_rhs);
1374 if past_rhs.unreachable.get() {
1375 return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1378 Br(past_rhs, join.llbb);
1379 let phi = Phi(join, Type::bool(bcx.ccx()), [lhs, rhs],
1380 [past_lhs.llbb, past_rhs.llbb]);
1382 return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1385 fn trans_binary<'a>(bcx: &'a Block<'a>,
1390 -> DatumBlock<'a, Expr> {
1391 let _icx = push_ctxt("trans_binary");
1392 let ccx = bcx.ccx();
1394 // if overloaded, would be RvalueDpsExpr
1395 assert!(!ccx.tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1399 trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1402 trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1406 let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
1407 let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1408 let binop_ty = expr_ty(bcx, expr);
1410 debug!("trans_binary (expr {}): lhs_datum={}",
1412 lhs_datum.to_str(ccx));
1413 let lhs_ty = lhs_datum.ty;
1414 let lhs = lhs_datum.to_llscalarish(bcx);
1416 debug!("trans_binary (expr {}): rhs_datum={}",
1418 rhs_datum.to_str(ccx));
1419 let rhs_ty = rhs_datum.ty;
1420 let rhs = rhs_datum.to_llscalarish(bcx);
1421 trans_eager_binop(bcx, expr, binop_ty, op,
1422 lhs_ty, lhs, rhs_ty, rhs)
1427 fn trans_overloaded_op<'a, 'b>(
1430 method_call: MethodCall,
1432 rhs: Option<(Datum<Expr>, ast::NodeId)>,
1435 let method_ty = bcx.tcx().method_map.borrow().get(&method_call).ty;
1436 callee::trans_call_inner(bcx,
1437 Some(expr_info(expr)),
1438 monomorphize_type(bcx, method_ty),
1439 |bcx, arg_cleanup_scope| {
1440 meth::trans_method_callee(bcx,
1445 callee::ArgOverloadedOp(lhs, rhs),
1449 fn trans_overloaded_call<'a>(
1450 mut bcx: &'a Block<'a>,
1452 callee: Datum<Expr>,
1453 args: &[Gc<ast::Expr>],
1456 // Evaluate and tuple the arguments.
1457 let tuple_type = ty::mk_tup(bcx.tcx(),
1459 .map(|e| ty::expr_ty_adjusted(bcx.tcx(), &**e))
1461 let repr = adt::represent_type(bcx.ccx(), tuple_type);
1462 let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
1463 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
1464 let argument_scope = bcx.fcx.push_custom_cleanup_scope();
1467 lvalue_scratch_datum(bcx,
1471 cleanup::CustomScope(
1478 numbered_fields.as_slice(),
1483 let method_call = MethodCall::expr(expr.id);
1484 let method_type = bcx.tcx()
1489 let callee_rvalue = unpack_datum!(bcx,
1490 callee.to_rvalue_datum(bcx, "callee"));
1491 let tuple_datum = tuple_datum.to_expr_datum();
1492 let tuple_rvalue = unpack_datum!(bcx,
1493 tuple_datum.to_rvalue_datum(bcx,
1495 let argument_values = [
1496 callee_rvalue.add_clean(bcx.fcx,
1497 cleanup::CustomScope(argument_scope)),
1498 tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope))
1501 callee::trans_call_inner(bcx,
1502 Some(expr_info(expr)),
1503 monomorphize_type(bcx,
1505 |bcx, arg_cleanup_scope| {
1506 meth::trans_method_callee(
1512 callee::ArgVals(argument_values),
1515 bcx.fcx.pop_custom_cleanup_scope(argument_scope);
1519 fn int_cast(bcx: &Block,
1525 let _icx = push_ctxt("int_cast");
1527 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1528 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1529 return if dstsz == srcsz {
1530 BitCast(bcx, llsrc, lldsttype)
1531 } else if srcsz > dstsz {
1532 TruncOrBitCast(bcx, llsrc, lldsttype)
1534 SExtOrBitCast(bcx, llsrc, lldsttype)
1536 ZExtOrBitCast(bcx, llsrc, lldsttype)
1541 fn float_cast(bcx: &Block,
1546 let _icx = push_ctxt("float_cast");
1547 let srcsz = llsrctype.float_width();
1548 let dstsz = lldsttype.float_width();
1549 return if dstsz > srcsz {
1550 FPExt(bcx, llsrc, lldsttype)
1551 } else if srcsz > dstsz {
1552 FPTrunc(bcx, llsrc, lldsttype)
1556 #[deriving(PartialEq)]
1557 pub enum cast_kind {
1565 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1566 match ty::get(t).sty {
1567 ty::ty_char => cast_integral,
1568 ty::ty_float(..) => cast_float,
1569 ty::ty_ptr(..) => cast_pointer,
1570 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
1571 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other,
1574 ty::ty_bare_fn(..) => cast_pointer,
1575 ty::ty_int(..) => cast_integral,
1576 ty::ty_uint(..) => cast_integral,
1577 ty::ty_bool => cast_integral,
1578 ty::ty_enum(..) => cast_enum,
1583 fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
1586 -> DatumBlock<'a, Expr> {
1587 let _icx = push_ctxt("trans_cast");
1589 let ccx = bcx.ccx();
1591 let t_in = expr_ty(bcx, expr);
1592 let t_out = node_id_type(bcx, id);
1593 let k_in = cast_type_kind(t_in);
1594 let k_out = cast_type_kind(t_out);
1595 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1596 let ll_t_in = type_of::type_of(ccx, t_in);
1597 let ll_t_out = type_of::type_of(ccx, t_out);
1599 // Convert the value to be cast into a ValueRef, either by-ref or
1600 // by-value as appropriate given its type:
1601 let datum = unpack_datum!(bcx, trans(bcx, expr));
1602 let newval = match (k_in, k_out) {
1603 (cast_integral, cast_integral) => {
1604 let llexpr = datum.to_llscalarish(bcx);
1605 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1607 (cast_float, cast_float) => {
1608 let llexpr = datum.to_llscalarish(bcx);
1609 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1611 (cast_integral, cast_float) => {
1612 let llexpr = datum.to_llscalarish(bcx);
1614 SIToFP(bcx, llexpr, ll_t_out)
1615 } else { UIToFP(bcx, llexpr, ll_t_out) }
1617 (cast_float, cast_integral) => {
1618 let llexpr = datum.to_llscalarish(bcx);
1619 if ty::type_is_signed(t_out) {
1620 FPToSI(bcx, llexpr, ll_t_out)
1621 } else { FPToUI(bcx, llexpr, ll_t_out) }
1623 (cast_integral, cast_pointer) => {
1624 let llexpr = datum.to_llscalarish(bcx);
1625 IntToPtr(bcx, llexpr, ll_t_out)
1627 (cast_pointer, cast_integral) => {
1628 let llexpr = datum.to_llscalarish(bcx);
1629 PtrToInt(bcx, llexpr, ll_t_out)
1631 (cast_pointer, cast_pointer) => {
1632 let llexpr = datum.to_llscalarish(bcx);
1633 PointerCast(bcx, llexpr, ll_t_out)
1635 (cast_enum, cast_integral) |
1636 (cast_enum, cast_float) => {
1638 let repr = adt::represent_type(ccx, t_in);
1639 let datum = unpack_datum!(
1640 bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
1641 let llexpr_ptr = datum.to_llref();
1643 adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
1645 cast_integral => int_cast(bcx, ll_t_out,
1646 val_ty(lldiscrim_a),
1648 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1650 ccx.sess().bug(format!("translating unsupported cast: \
1651 {} ({:?}) -> {} ({:?})",
1652 t_in.repr(bcx.tcx()),
1654 t_out.repr(bcx.tcx()),
1659 _ => ccx.sess().bug(format!("translating unsupported cast: \
1660 {} ({:?}) -> {} ({:?})",
1661 t_in.repr(bcx.tcx()),
1663 t_out.repr(bcx.tcx()),
1666 return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
1669 fn trans_assign_op<'a>(
1676 let _icx = push_ctxt("trans_assign_op");
1679 debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
1681 // User-defined operator methods cannot be used with `+=` etc right now
1682 assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1684 // Evaluate LHS (destination), which should be an lvalue
1685 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1686 assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
1687 let dst_ty = dst_datum.ty;
1688 let dst = Load(bcx, dst_datum.val);
1691 let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
1692 let rhs_ty = rhs_datum.ty;
1693 let rhs = rhs_datum.to_llscalarish(bcx);
1695 // Perform computation and store the result
1696 let result_datum = unpack_datum!(
1697 bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1698 dst_ty, dst, rhs_ty, rhs));
1699 return result_datum.store_to(bcx, dst_datum.val);
1702 fn auto_ref<'a>(bcx: &'a Block<'a>,
1705 -> DatumBlock<'a, Expr> {
1708 // Ensure cleanup of `datum` if not already scheduled and obtain
1709 // a "by ref" pointer.
1710 let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
1712 // Compute final type. Note that we are loose with the region and
1713 // mutability, since those things don't matter in trans.
1714 let referent_ty = lv_datum.ty;
1715 let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
1718 let llref = lv_datum.to_llref();
1720 // Construct the resulting datum, using what was the "by ref"
1721 // ValueRef of type `referent_ty` to be the "by value" ValueRef
1722 // of type `&referent_ty`.
1723 DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(ByValue))))
1726 fn deref_multiple<'a>(bcx: &'a Block<'a>,
1730 -> DatumBlock<'a, Expr> {
1732 let mut datum = datum;
1733 for i in range(0, times) {
1734 let method_call = MethodCall::autoderef(expr.id, i);
1735 datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
1737 DatumBlock { bcx: bcx, datum: datum }
1740 fn deref_once<'a>(bcx: &'a Block<'a>,
1743 method_call: MethodCall)
1744 -> DatumBlock<'a, Expr> {
1745 let ccx = bcx.ccx();
1747 debug!("deref_once(expr={}, datum={}, method_call={})",
1748 expr.repr(bcx.tcx()),
1754 // Check for overloaded deref.
1755 let method_ty = ccx.tcx.method_map.borrow()
1756 .find(&method_call).map(|method| method.ty);
1757 let datum = match method_ty {
1758 Some(method_ty) => {
1759 // Overloaded. Evaluate `trans_overloaded_op`, which will
1760 // invoke the user's deref() method, which basically
1761 // converts from the `Shaht<T>` pointer that we have into
1762 // a `&T` pointer. We can then proceed down the normal
1763 // path (below) to dereference that `&T`.
1764 let datum = match method_call.adjustment {
1765 // Always perform an AutoPtr when applying an overloaded auto-deref
1766 typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
1769 let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
1770 datum, None, None));
1771 let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
1772 Datum::new(val, ref_ty, RvalueExpr(Rvalue::new(ByValue)))
1775 // Not overloaded. We already have a pointer we know how to deref.
1780 let r = match ty::get(datum.ty).sty {
1781 ty::ty_uniq(content_ty) => {
1782 match ty::get(content_ty).sty {
1783 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
1784 => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"),
1785 _ => deref_owned_pointer(bcx, expr, datum, content_ty),
1789 ty::ty_box(content_ty) => {
1790 let datum = unpack_datum!(
1791 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
1792 let llptrref = datum.to_llref();
1793 let llptr = Load(bcx, llptrref);
1794 let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
1795 DatumBlock::new(bcx, Datum::new(llbody, content_ty, LvalueExpr))
1798 ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
1799 ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
1800 match ty::get(content_ty).sty {
1801 ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
1802 => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"),
1804 assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
1806 let ptr = datum.to_llscalarish(bcx);
1808 // Always generate an lvalue datum, even if datum.mode is
1809 // an rvalue. This is because datum.mode is only an
1810 // rvalue for non-owning pointers like &T or *T, in which
1811 // case cleanup *is* scheduled elsewhere, by the true
1812 // owner (or, in the case of *T, by the user).
1813 DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
1819 bcx.tcx().sess.span_bug(
1821 format!("deref invoked on expr of illegal type {}",
1822 datum.ty.repr(bcx.tcx())).as_slice());
1826 debug!("deref_once(expr={}, method_call={}, result={})",
1827 expr.id, method_call, r.datum.to_str(ccx));
1831 fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
1835 -> DatumBlock<'a, Expr> {
1837 * We microoptimize derefs of owned pointers a bit here.
1838 * Basically, the idea is to make the deref of an rvalue
1839 * result in an rvalue. This helps to avoid intermediate stack
1840 * slots in the resulting LLVM. The idea here is that, if the
1841 * `Box<T>` pointer is an rvalue, then we can schedule a *shallow*
1842 * free of the `Box<T>` pointer, and then return a ByRef rvalue
1843 * into the pointer. Because the free is shallow, it is legit
1844 * to return an rvalue, because we know that the contents are
1845 * not yet scheduled to be freed. The language rules ensure that the
1846 * contents will be used (or moved) before the free occurs.
1850 RvalueExpr(Rvalue { mode: ByRef }) => {
1851 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1852 let ptr = Load(bcx, datum.val);
1853 if !type_is_zero_size(bcx.ccx(), content_ty) {
1854 bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange, content_ty);
1857 RvalueExpr(Rvalue { mode: ByValue }) => {
1858 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1859 if !type_is_zero_size(bcx.ccx(), content_ty) {
1860 bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange,
1867 // If we had an rvalue in, we produce an rvalue out.
1868 let (llptr, kind) = match datum.kind {
1870 (Load(bcx, datum.val), LvalueExpr)
1872 RvalueExpr(Rvalue { mode: ByRef }) => {
1873 (Load(bcx, datum.val), RvalueExpr(Rvalue::new(ByRef)))
1875 RvalueExpr(Rvalue { mode: ByValue }) => {
1876 (datum.val, RvalueExpr(Rvalue::new(ByRef)))
1880 let datum = Datum { ty: content_ty, val: llptr, kind: kind };
1881 DatumBlock { bcx: bcx, datum: datum }