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)];
38 use lib::llvm::{ValueRef, llvm, SetLinkage, False};
40 use metadata::csearch;
41 use middle::trans::_match;
42 use middle::trans::adt;
43 use middle::trans::asm;
44 use middle::trans::base::*;
45 use middle::trans::base;
46 use middle::trans::build::*;
47 use middle::trans::callee;
48 use middle::trans::cleanup;
49 use middle::trans::cleanup::CleanupMethods;
50 use middle::trans::closure;
51 use middle::trans::common::*;
52 use middle::trans::consts;
53 use middle::trans::controlflow;
54 use middle::trans::datum::*;
55 use middle::trans::debuginfo;
56 use middle::trans::glue;
57 use middle::trans::machine;
58 use middle::trans::meth;
59 use middle::trans::inline;
60 use middle::trans::tvec;
61 use middle::trans::type_of;
62 use middle::trans::write_guard;
63 use middle::ty::struct_fields;
64 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
65 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
67 use util::common::indenter;
68 use util::ppaux::Repr;
69 use util::nodemap::NodeMap;
70 use middle::trans::machine::llsize_of;
71 use middle::trans::type_::Type;
77 use syntax::parse::token;
78 use syntax::print::pprust::{expr_to_str};
82 // These are passed around by the code generating functions to track the
83 // destination of a computation's value.
92 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
94 SaveIn(v) => format!("SaveIn({})", ccx.tn.val_to_str(v)),
100 pub fn trans_into<'a>(bcx: &'a Block<'a>,
105 * This function is equivalent to `trans(bcx, expr).store_to_dest(dest)`
106 * but it may generate better optimized LLVM code.
112 let adjustments = bcx.tcx().adjustments.borrow();
113 adjustments.get().contains_key(&expr.id)
117 // use trans, which may be less efficient but
118 // which will perform the adjustments:
119 let datum = unpack_datum!(bcx, trans(bcx, expr));
120 return datum.store_to_dest(bcx, dest, expr.id)
123 debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
124 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
126 bcx.fcx.push_ast_cleanup_scope(expr.id);
128 let kind = ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr);
130 ty::LvalueExpr | ty::RvalueDatumExpr => {
131 trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
133 ty::RvalueDpsExpr => {
134 trans_rvalue_dps_unadjusted(bcx, expr, dest)
136 ty::RvalueStmtExpr => {
137 trans_rvalue_stmt_unadjusted(bcx, expr)
141 bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
144 pub fn trans<'a>(bcx: &'a Block<'a>,
146 -> DatumBlock<'a, Expr> {
148 * Translates an expression, returning a datum (and new block)
149 * encapsulating the result. When possible, it is preferred to
150 * use `trans_into`, as that may avoid creating a temporary on
154 debug!("trans(expr={})", bcx.expr_to_str(expr));
159 fcx.push_ast_cleanup_scope(expr.id);
160 let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
161 let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
162 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
163 return DatumBlock(bcx, datum);
166 fn apply_adjustments<'a>(bcx: &'a Block<'a>,
169 -> DatumBlock<'a, Expr> {
171 * Helper for trans that apply adjustments from `expr` to `datum`,
172 * which should be the unadjusted translation of `expr`.
176 let mut datum = datum;
178 let adjustments = bcx.tcx().adjustments.borrow();
179 match adjustments.get().find_copy(&expr.id) {
181 return DatumBlock(bcx, datum);
186 debug!("unadjusted datum for expr {}: {}",
187 expr.id, datum.to_str(bcx.ccx()));
190 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
192 AutoDerefRef(ref adj) => {
193 if adj.autoderefs > 0 {
194 datum = unpack_datum!(
195 bcx, deref_multiple(bcx, expr, datum, adj.autoderefs));
198 datum = match adj.autoref {
202 Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
203 Some(AutoPtr(..)) => {
204 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
206 Some(AutoBorrowVec(..)) => {
207 unpack_datum!(bcx, auto_slice(bcx, expr, datum))
209 Some(AutoBorrowVecRef(..)) => {
210 unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
212 Some(AutoBorrowFn(..)) => {
213 let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
214 datum.ty, Some(adjustment));
215 unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
217 Some(AutoBorrowObj(..)) => {
218 unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum))
223 let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
224 let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
225 bcx = meth::trans_trait_cast(
226 bcx, datum, expr.id, SaveIn(scratch.val));
227 datum = scratch.to_expr_datum();
230 debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
231 return DatumBlock {bcx: bcx, datum: datum};
233 fn auto_ref<'a>(bcx: &'a Block<'a>,
236 -> DatumBlock<'a, Expr> {
239 // Ensure cleanup of `datum` if not already scheduled and obtain
240 // a "by ref" pointer.
241 let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
243 // Compute final type. Note that we are loose with the region and
244 // mutability, since those things don't matter in trans.
245 let referent_ty = lv_datum.ty;
246 let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
249 let llref = lv_datum.to_llref();
251 // Construct the resulting datum, using what was the "by ref"
252 // ValueRef of type `referent_ty` to be the "by value" ValueRef
253 // of type `&referent_ty`.
254 DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
257 fn auto_borrow_fn<'a>(
261 -> DatumBlock<'a, Expr> {
262 // Currently, all closure types are represented precisely the
263 // same, so no runtime adjustment is required, but we still
264 // must patchup the type.
265 DatumBlock {bcx: bcx,
266 datum: Datum {val: datum.val,
275 -> DatumBlock<'a, Expr> {
276 // This is not the most efficient thing possible; since slices
277 // are two words it'd be better if this were compiled in
278 // 'dest' mode, but I can't find a nice way to structure the
279 // code and keep it DRY that accommodates that use case at the
284 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
286 // Arrange cleanup, if not already done. This is needed in
287 // case we are auto-slicing an owned vector or some such.
288 let datum = unpack_datum!(
289 bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id));
291 let (base, len) = datum.get_vec_base_and_len(bcx);
293 // this type may have a different region/mutability than the
294 // real one, but it will have the same runtime representation
295 let slice_ty = ty::mk_vec(tcx,
296 ty::mt { ty: unit_ty, mutbl: ast::MutImmutable },
297 ty::vstore_slice(ty::ReStatic));
299 let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust");
300 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
301 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
302 DatumBlock(bcx, scratch.to_expr_datum())
305 fn add_env<'a>(bcx: &'a Block<'a>,
308 -> DatumBlock<'a, Expr> {
309 // This is not the most efficient thing possible; since closures
310 // are two words it'd be better if this were compiled in
311 // 'dest' mode, but I can't find a nice way to structure the
312 // code and keep it DRY that accommodates that use case at the
315 let closure_ty = expr_ty_adjusted(bcx, expr);
316 let fn_ptr = datum.to_llscalarish(bcx);
317 let def = ty::resolve_expr(bcx.tcx(), expr);
318 closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
321 fn auto_slice_and_ref<'a>(
325 -> DatumBlock<'a, Expr> {
326 let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
327 auto_ref(bcx, datum, expr)
330 fn auto_borrow_obj<'a>(bcx: &'a Block<'a>,
332 source_datum: Datum<Expr>)
333 -> DatumBlock<'a, Expr> {
335 let target_obj_ty = expr_ty_adjusted(bcx, expr);
336 debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx));
338 let mut datum = source_datum.to_expr_datum();
339 datum.ty = target_obj_ty;
340 DatumBlock(bcx, datum)
344 pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
347 -> DatumBlock<'a, Lvalue> {
349 * Translates an expression in "lvalue" mode -- meaning that it
350 * returns a reference to the memory that the expr represents.
352 * If this expression is an rvalue, this implies introducing a
353 * temporary. In other words, something like `x().f` is
354 * translated into roughly the equivalent of
356 * { tmp = x(); tmp.f }
360 let datum = unpack_datum!(bcx, trans(bcx, expr));
361 return datum.to_lvalue_datum(bcx, name, expr.id);
364 fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
366 -> DatumBlock<'a, Expr> {
368 * A version of `trans` that ignores adjustments. You almost
369 * certainly do not want to call this directly.
374 debug!("trans_unadjusted(expr={})", bcx.expr_to_str(expr));
375 let _indenter = indenter();
377 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
379 return match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
380 ty::LvalueExpr | ty::RvalueDatumExpr => {
381 let datum = unpack_datum!(bcx, {
382 trans_datum_unadjusted(bcx, expr)
385 DatumBlock {bcx: bcx, datum: datum}
388 ty::RvalueStmtExpr => {
389 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
390 nil(bcx, expr_ty(bcx, expr))
393 ty::RvalueDpsExpr => {
394 let ty = expr_ty(bcx, expr);
395 if type_is_zero_size(bcx.ccx(), ty) {
396 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
399 let scratch = rvalue_scratch_datum(bcx, ty, "");
400 bcx = trans_rvalue_dps_unadjusted(
401 bcx, expr, SaveIn(scratch.val));
403 // Note: this is not obviously a good idea. It causes
404 // immediate values to be loaded immediately after a
405 // return from a call or other similar expression,
406 // which in turn leads to alloca's having shorter
407 // lifetimes and hence larger stack frames. However,
408 // in turn it can lead to more register pressure.
409 // Still, in practice it seems to increase
410 // performance, since we have fewer problems with
412 let scratch = unpack_datum!(
413 bcx, scratch.to_appropriate_datum(bcx));
415 DatumBlock(bcx, scratch.to_expr_datum())
420 fn nil<'a>(bcx: &'a Block<'a>, ty: ty::t) -> DatumBlock<'a, Expr> {
421 let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
422 let datum = immediate_rvalue(llval, ty);
423 DatumBlock(bcx, datum.to_expr_datum())
427 fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
429 -> DatumBlock<'a, Expr> {
432 let _icx = push_ctxt("trans_datum_unadjusted");
435 ast::ExprParen(e) => {
438 ast::ExprPath(_) => {
439 trans_def(bcx, expr, bcx.def(expr.id))
441 ast::ExprField(base, ident, _) => {
442 trans_rec_field(bcx, base, ident)
444 ast::ExprIndex(base, idx) => {
445 trans_index(bcx, expr, base, idx)
447 ast::ExprVstore(contents, ast::ExprVstoreUniq) => {
448 fcx.push_ast_cleanup_scope(contents.id);
449 let datum = unpack_datum!(
450 bcx, tvec::trans_uniq_vstore(bcx, expr, contents));
451 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
452 DatumBlock(bcx, datum)
454 ast::ExprBox(_, contents) => {
455 // Special case for `~T`. (The other case, for GC, is handled in
456 // `trans_rvalue_dps_unadjusted`.)
457 let box_ty = expr_ty(bcx, expr);
458 let contents_ty = expr_ty(bcx, contents);
459 let heap = heap_exchange;
460 return trans_boxed_expr(bcx, box_ty, contents, contents_ty, heap)
462 ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
463 ast::ExprBinary(op, lhs, rhs) => {
464 // if overloaded, would be RvalueDpsExpr
465 assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&expr.id));
467 trans_binary(bcx, expr, op, lhs, rhs)
469 ast::ExprUnary(op, x) => {
470 trans_unary_datum(bcx, expr, op, x)
472 ast::ExprAddrOf(_, x) => {
473 trans_addr_of(bcx, expr, x)
475 ast::ExprCast(val, _) => {
476 // Datum output mode means this is a scalar cast:
477 trans_imm_cast(bcx, val, expr.id)
479 ast::ExprLogLevel => {
483 bcx.tcx().sess.span_bug(
485 format!("trans_rvalue_datum_unadjusted reached \
486 fall-through case: {:?}",
492 fn trans_rec_field<'a>(bcx: &'a Block<'a>,
495 -> DatumBlock<'a, Expr> {
496 //! Translates `base.field`.
499 let _icx = push_ctxt("trans_rec_field");
501 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
502 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
503 with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
504 let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
505 let d = base_datum.get_element(
507 |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, ix));
508 DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
512 fn trans_index<'a>(bcx: &'a Block<'a>,
513 index_expr: &ast::Expr,
516 -> DatumBlock<'a, Expr> {
517 //! Translates `base[idx]`.
519 let _icx = push_ctxt("trans_index");
523 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
525 // Translate index expression and cast to a suitable LLVM integer.
526 // Rust is less strict than LLVM in this regard.
527 let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
528 let ix_val = ix_datum.to_llscalarish(bcx);
529 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
530 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
532 if ix_size < int_size {
533 if ty::type_is_signed(expr_ty(bcx, idx)) {
534 SExt(bcx, ix_val, ccx.int_type)
535 } else { ZExt(bcx, ix_val, ccx.int_type) }
536 } else if ix_size > int_size {
537 Trunc(bcx, ix_val, ccx.int_type)
543 let vt = tvec::vec_types(bcx, base_datum.ty);
544 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
546 let (base, len) = base_datum.get_vec_base_and_len(bcx);
548 debug!("trans_index: base {}", bcx.val_to_str(base));
549 debug!("trans_index: len {}", bcx.val_to_str(len));
551 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
552 let expect = ccx.intrinsics.get_copy(&("llvm.expect.i1"));
553 let expected = Call(bcx, expect, [bounds_check, C_i1(false)], []);
554 let bcx = with_cond(bcx, expected, |bcx| {
555 controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
557 let elt = InBoundsGEP(bcx, base, [ix_val]);
558 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
559 DatumBlock(bcx, Datum(elt, vt.unit_ty, LvalueExpr))
562 fn trans_def<'a>(bcx: &'a Block<'a>,
563 ref_expr: &ast::Expr,
565 -> DatumBlock<'a, Expr>
567 //! Translates a reference to a path.
569 let _icx = push_ctxt("trans_def_lvalue");
571 ast::DefFn(..) | ast::DefStaticMethod(..) |
572 ast::DefStruct(_) | ast::DefVariant(..) => {
573 trans_def_fn_unadjusted(bcx, ref_expr, def)
575 ast::DefStatic(did, _) => {
576 let const_ty = expr_ty(bcx, ref_expr);
578 fn get_did(ccx: @CrateContext, did: ast::DefId)
580 if did.krate != ast::LOCAL_CRATE {
581 inline::maybe_instantiate_inline(ccx, did)
587 fn get_val<'a>(bcx: &'a Block<'a>, did: ast::DefId, const_ty: ty::t)
589 // For external constants, we don't inline.
590 if did.krate == ast::LOCAL_CRATE {
591 // The LLVM global has the type of its initializer,
592 // which may not be equal to the enum's type for
594 let val = base::get_item_val(bcx.ccx(), did.node);
595 let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
596 PointerCast(bcx, val, pty)
599 let extern_const_values = bcx.ccx().extern_const_values.borrow();
600 match extern_const_values.get().find(&did) {
601 None => {} // Continue.
609 let llty = type_of::type_of(bcx.ccx(), const_ty);
610 let symbol = csearch::get_symbol(
611 bcx.ccx().sess.cstore,
613 let llval = symbol.with_c_str(|buf| {
614 llvm::LLVMAddGlobal(bcx.ccx().llmod,
618 let mut extern_const_values = bcx.ccx().extern_const_values.borrow_mut();
619 extern_const_values.get().insert(did, llval);
625 let did = get_did(bcx.ccx(), did);
626 let val = get_val(bcx, did, const_ty);
627 DatumBlock(bcx, Datum(val, const_ty, LvalueExpr))
630 DatumBlock(bcx, trans_local_var(bcx, def).to_expr_datum())
635 fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
639 let _icx = push_ctxt("trans_rvalue_stmt");
641 if bcx.unreachable.get() {
646 ast::ExprParen(e) => {
647 trans_into(bcx, e, Ignore)
649 ast::ExprBreak(label_opt) => {
650 controlflow::trans_break(bcx, expr.id, label_opt)
652 ast::ExprAgain(label_opt) => {
653 controlflow::trans_cont(bcx, expr.id, label_opt)
655 ast::ExprRet(ex) => {
656 controlflow::trans_ret(bcx, ex)
658 ast::ExprWhile(cond, body) => {
659 controlflow::trans_while(bcx, expr.id, cond, body)
661 ast::ExprLoop(body, _) => {
662 controlflow::trans_loop(bcx, expr.id, body)
664 ast::ExprAssign(dst, src) => {
665 let src_datum = unpack_datum!(bcx, trans(bcx, src));
666 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign"));
668 if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
669 // If there are destructors involved, make sure we
670 // are copying from an rvalue, since that cannot possible
671 // alias an lvalue. We are concerned about code like:
679 // where e.g. a : Option<Foo> and a.b :
680 // Option<Foo>. In that case, freeing `a` before the
681 // assignment may also free `a.b`!
683 // We could avoid this intermediary with some analysis
684 // to determine whether `dst` may possibly own `src`.
685 let src_datum = unpack_datum!(
686 bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
687 bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
688 src_datum.store_to(bcx, dst_datum.val)
690 src_datum.store_to(bcx, dst_datum.val)
693 ast::ExprAssignOp(op, dst, src) => {
694 trans_assign_op(bcx, expr, op, dst, src)
696 ast::ExprInlineAsm(ref a) => {
697 asm::trans_inline_asm(bcx, a)
700 bcx.tcx().sess.span_bug(
702 format!("trans_rvalue_stmt_unadjusted reached \
703 fall-through case: {:?}",
709 fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
713 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
719 ast::ExprParen(e) => {
720 trans_into(bcx, e, dest)
722 ast::ExprPath(_) => {
723 trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
725 ast::ExprIf(cond, thn, els) => {
726 controlflow::trans_if(bcx, expr.id, cond, thn, els, dest)
728 ast::ExprMatch(discr, ref arms) => {
729 _match::trans_match(bcx, expr, discr, arms.as_slice(), dest)
731 ast::ExprBlock(blk) => {
732 controlflow::trans_block(bcx, blk, dest)
734 ast::ExprStruct(_, ref fields, base) => {
735 trans_rec_or_struct(bcx,
742 ast::ExprTup(ref args) => {
743 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
744 let numbered_fields: Vec<(uint, @ast::Expr)> =
745 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
746 trans_adt(bcx, repr, 0, numbered_fields, None, dest)
748 ast::ExprLit(lit) => {
750 ast::LitStr(ref s, _) => {
751 tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
757 "trans_rvalue_dps_unadjusted shouldn't be \
758 translating this type of literal")
762 ast::ExprVstore(contents, ast::ExprVstoreSlice) |
763 ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
764 fcx.push_ast_cleanup_scope(contents.id);
765 bcx = tvec::trans_slice_vstore(bcx, expr, contents, dest);
766 fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
768 ast::ExprVec(..) | ast::ExprRepeat(..) => {
769 tvec::trans_fixed_vstore(bcx, expr, expr, dest)
771 ast::ExprFnBlock(decl, body) |
772 ast::ExprProc(decl, body) => {
773 let expr_ty = expr_ty(bcx, expr);
774 let sigil = ty::ty_closure_sigil(expr_ty);
775 debug!("translating block function {} with type {}",
776 expr_to_str(expr), expr_ty.repr(tcx));
777 closure::trans_expr_fn(bcx, sigil, decl, body, expr.id, dest)
779 ast::ExprCall(f, ref args) => {
780 callee::trans_call(bcx, expr, f, callee::ArgExprs(args.as_slice()), dest)
782 ast::ExprMethodCall(_, _, ref args) => {
783 callee::trans_method_call(bcx,
786 callee::ArgExprs(args.as_slice()),
789 ast::ExprBinary(_, lhs, rhs) => {
790 // if not overloaded, would be RvalueDatumExpr
791 trans_overloaded_op(bcx, expr, lhs, Some(&*rhs), Some(dest)).bcx
793 ast::ExprUnary(_, subexpr) => {
794 // if not overloaded, would be RvalueDatumExpr
795 trans_overloaded_op(bcx, expr, subexpr, None, Some(dest)).bcx
797 ast::ExprIndex(base, idx) => {
798 // if not overloaded, would be RvalueDatumExpr
799 trans_overloaded_op(bcx, expr, base, Some(&*idx), Some(dest)).bcx
801 ast::ExprCast(val, _) => {
802 // DPS output mode means this is a trait cast:
803 match ty::get(node_id_type(bcx, expr.id)).sty {
804 ty::ty_trait(..) => {
805 let datum = unpack_datum!(bcx, trans(bcx, val));
806 meth::trans_trait_cast(bcx, datum, expr.id, dest)
809 bcx.tcx().sess.span_bug(expr.span,
810 "expr_cast of non-trait");
814 ast::ExprAssignOp(op, dst, src) => {
815 trans_assign_op(bcx, expr, op, dst, src)
817 ast::ExprBox(_, contents) => {
818 // Special case for `Gc<T>` for now. The other case, for unique
819 // pointers, is handled in `trans_rvalue_datum_unadjusted`.
820 trans_gc(bcx, expr, contents, dest)
823 bcx.tcx().sess.span_bug(
825 format!("trans_rvalue_dps_unadjusted reached fall-through case: {:?}",
831 fn trans_def_dps_unadjusted<'a>(
833 ref_expr: &ast::Expr,
837 let _icx = push_ctxt("trans_def_dps_unadjusted");
840 let lldest = match dest {
841 SaveIn(lldest) => lldest,
842 Ignore => { return bcx; }
846 ast::DefVariant(tid, vid, _) => {
847 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
848 if variant_info.args.len() > 0u {
850 let llfn = callee::trans_fn_ref(bcx, vid, ref_expr.id, false);
851 Store(bcx, llfn, lldest);
855 let ty = expr_ty(bcx, ref_expr);
856 let repr = adt::represent_type(ccx, ty);
857 adt::trans_start_init(bcx, repr, lldest,
858 variant_info.disr_val);
862 ast::DefStruct(_) => {
863 let ty = expr_ty(bcx, ref_expr);
864 match ty::get(ty).sty {
865 ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
866 let repr = adt::represent_type(ccx, ty);
867 adt::trans_start_init(bcx, repr, lldest, 0);
874 bcx.tcx().sess.span_bug(ref_expr.span, format!(
875 "Non-DPS def {:?} referened by {}",
876 def, bcx.node_id_to_str(ref_expr.id)));
881 fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
882 ref_expr: &ast::Expr,
883 def: ast::Def) -> DatumBlock<'a, Expr> {
884 let _icx = push_ctxt("trans_def_datum_unadjusted");
886 let llfn = match def {
888 ast::DefStruct(did) | ast::DefVariant(_, did, _) |
889 ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
890 callee::trans_fn_ref(bcx, did, ref_expr.id, false)
892 ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
893 meth::trans_static_method_callee(bcx, impl_did,
894 trait_did, ref_expr.id)
897 bcx.tcx().sess.span_bug(ref_expr.span, format!(
898 "trans_def_fn_unadjusted invoked on: {:?} for {}",
900 ref_expr.repr(bcx.tcx())));
904 let fn_ty = expr_ty(bcx, ref_expr);
905 DatumBlock(bcx, Datum(llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
908 pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
912 * Translates a reference to a local variable or argument.
913 * This always results in an lvalue datum.
916 let _icx = push_ctxt("trans_local_var");
919 ast::DefUpvar(nid, _, _, _) => {
920 // Can't move upvars, so this is never a ZeroMemLastUse.
921 let local_ty = node_id_type(bcx, nid);
922 let llupvars = bcx.fcx.llupvars.borrow();
923 match llupvars.get().find(&nid) {
924 Some(&val) => Datum(val, local_ty, Lvalue),
926 bcx.sess().bug(format!(
927 "trans_local_var: no llval for upvar {:?} found", nid));
931 ast::DefArg(nid, _) => {
932 let llargs = bcx.fcx.llargs.borrow();
933 take_local(bcx, llargs.get(), nid)
935 ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
936 let lllocals = bcx.fcx.lllocals.borrow();
937 take_local(bcx, lllocals.get(), nid)
940 bcx.sess().unimpl(format!(
941 "unsupported def type in trans_local_var: {:?}", def));
945 fn take_local<'a>(bcx: &'a Block<'a>,
946 table: &NodeMap<Datum<Lvalue>>,
949 let datum = match table.find(&nid) {
952 bcx.sess().bug(format!(
953 "trans_local_var: no datum for local/arg {:?} found", nid));
956 debug!("take_local(nid={:?}, v={}, ty={})",
957 nid, bcx.val_to_str(datum.val), bcx.ty_to_str(datum.ty));
962 pub fn with_field_tys<R>(tcx: ty::ctxt,
964 node_id_opt: Option<ast::NodeId>,
965 op: |ty::Disr, (&[ty::field])| -> R)
968 * Helper for enumerating the field types of structs, enums, or records.
969 * The optional node ID here is the node ID of the path identifying the enum
970 * variant in use. If none, this cannot possibly an enum variant (so, if it
971 * is and `node_id_opt` is none, this function fails).
974 match ty::get(ty).sty {
975 ty::ty_struct(did, ref substs) => {
976 op(0, struct_fields(tcx, did, substs))
979 ty::ty_enum(_, ref substs) => {
980 // We want the *variant* ID here, not the enum ID.
983 tcx.sess.bug(format!(
984 "cannot get field types from the enum type {} \
990 let def_map = tcx.def_map.borrow();
991 def_map.get().get_copy(&node_id)
994 ast::DefVariant(enum_id, variant_id, _) => {
995 let variant_info = ty::enum_variant_with_id(
996 tcx, enum_id, variant_id);
997 op(variant_info.disr_val,
998 struct_fields(tcx, variant_id, substs))
1001 tcx.sess.bug("resolve didn't map this expr to a \
1010 tcx.sess.bug(format!(
1011 "cannot get field types from the type {}",
1017 fn trans_rec_or_struct<'a>(
1019 fields: &[ast::Field],
1020 base: Option<@ast::Expr>,
1021 expr_span: codemap::Span,
1025 let _icx = push_ctxt("trans_rec");
1028 let ty = node_id_type(bcx, id);
1029 let tcx = bcx.tcx();
1030 with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
1031 let mut need_base = vec::from_elem(field_tys.len(), true);
1033 let numbered_fields = fields.map(|field| {
1035 field_tys.iter().position(|field_ty|
1036 field_ty.ident.name == field.ident.node.name);
1039 need_base[i] = false;
1043 tcx.sess.span_bug(field.span,
1044 "Couldn't find field in struct type")
1048 let optbase = match base {
1049 Some(base_expr) => {
1050 let mut leftovers = Vec::new();
1051 for (i, b) in need_base.iter().enumerate() {
1053 leftovers.push((i, field_tys[i].mt.ty))
1056 Some(StructBaseInfo {expr: base_expr,
1057 fields: leftovers })
1060 if need_base.iter().any(|b| *b) {
1061 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1067 let repr = adt::represent_type(bcx.ccx(), ty);
1068 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1073 * Information that `trans_adt` needs in order to fill in the fields
1074 * of a struct copied from a base struct (e.g., from an expression
1075 * like `Foo { a: b, ..base }`.
1077 * Note that `fields` may be empty; the base expression must always be
1078 * evaluated for side-effects.
1080 struct StructBaseInfo {
1081 /// The base expression; will be evaluated after all explicit fields.
1083 /// The indices of fields to copy paired with their types.
1084 fields: Vec<(uint, ty::t)> }
1087 * Constructs an ADT instance:
1089 * - `fields` should be a list of field indices paired with the
1090 * expression to store into that field. The initializers will be
1091 * evaluated in the order specified by `fields`.
1093 * - `optbase` contains information on the base struct (if any) from
1094 * which remaining fields are copied; see comments on `StructBaseInfo`.
1100 fields: &[(uint, @ast::Expr)],
1101 optbase: Option<StructBaseInfo>,
1104 let _icx = push_ctxt("trans_adt");
1107 let addr = match dest {
1109 for &(_i, e) in fields.iter() {
1110 bcx = trans_into(bcx, e, Ignore);
1112 for sbi in optbase.iter() {
1113 // FIXME #7261: this moves entire base, not just certain fields
1114 bcx = trans_into(bcx, sbi.expr, Ignore);
1121 // This scope holds intermediates that must be cleaned should
1122 // failure occur before the ADT as a whole is ready.
1123 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1125 adt::trans_start_init(bcx, repr, addr, discr);
1127 for &(i, e) in fields.iter() {
1128 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1129 let e_ty = expr_ty_adjusted(bcx, e);
1130 bcx = trans_into(bcx, e, SaveIn(dest));
1131 fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
1135 for base in optbase.iter() {
1136 // FIXME #6573: is it sound to use the destination's repr on the base?
1137 // And, would it ever be reasonable to be here with discr != 0?
1138 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base.expr, "base"));
1139 for &(i, t) in base.fields.iter() {
1140 let datum = base_datum.get_element(
1142 |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i));
1143 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1144 bcx = datum.store_to(bcx, dest);
1148 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1154 fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
1157 -> DatumBlock<'a, Expr> {
1158 // must not be a string constant, that is a RvalueDpsExpr
1159 let _icx = push_ctxt("trans_immediate_lit");
1160 let ty = expr_ty(bcx, expr);
1161 let v = consts::const_lit(bcx.ccx(), expr, lit);
1162 immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
1165 fn trans_unary_datum<'a>(
1167 un_expr: &ast::Expr,
1169 sub_expr: &ast::Expr)
1170 -> DatumBlock<'a, Expr> {
1172 let _icx = push_ctxt("trans_unary_datum");
1175 let method_map = bcx.ccx().maps.method_map.borrow();
1176 method_map.get().contains_key(&un_expr.id)
1178 // if overloaded, would be RvalueDpsExpr
1179 assert!(!overloaded || op == ast::UnDeref);
1181 let un_ty = expr_ty(bcx, un_expr);
1185 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1186 let llresult = if ty::type_is_bool(un_ty) {
1187 let val = datum.to_llscalarish(bcx);
1188 let llcond = ICmp(bcx,
1192 Select(bcx, llcond, C_bool(true), C_bool(false))
1194 // Note: `Not` is bitwise, not suitable for logical not.
1195 Not(bcx, datum.to_llscalarish(bcx))
1197 immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1200 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1201 let val = datum.to_llscalarish(bcx);
1203 if ty::type_is_fp(un_ty) {
1209 immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1212 trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_managed)
1215 trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_exchange)
1219 let r = trans_overloaded_op(bcx, un_expr, sub_expr, None, None);
1220 DatumBlock(r.bcx, Datum(r.val, un_ty, LvalueExpr))
1222 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1223 deref_once(bcx, un_expr, datum, 0)
1229 fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
1231 contents: &ast::Expr,
1234 -> DatumBlock<'a, Expr> {
1235 let _icx = push_ctxt("trans_boxed_expr");
1237 if heap == heap_exchange {
1238 let llty = type_of::type_of(bcx.ccx(), contents_ty);
1239 let size = llsize_of(bcx.ccx(), llty);
1240 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
1241 heap_exchange, size);
1242 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1243 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1244 val, heap_exchange);
1245 let bcx = trans_into(bcx, contents, SaveIn(val));
1246 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1247 immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
1249 let base::MallocResult { bcx, smart_ptr: bx, body } =
1250 base::malloc_general(bcx, contents_ty, heap);
1251 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1252 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1254 let bcx = trans_into(bcx, contents, SaveIn(body));
1255 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1256 immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
1260 fn trans_addr_of<'a>(bcx: &'a Block<'a>,
1262 subexpr: &ast::Expr)
1263 -> DatumBlock<'a, Expr> {
1264 let _icx = push_ctxt("trans_addr_of");
1266 let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1267 let ty = expr_ty(bcx, expr);
1268 return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
1271 fn trans_gc<'a>(mut bcx: &'a Block<'a>,
1273 contents: &ast::Expr,
1276 let contents_ty = expr_ty(bcx, contents);
1277 let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
1278 let expr_ty = expr_ty(bcx, expr);
1280 let addr = match dest {
1282 return trans_boxed_expr(bcx,
1288 SaveIn(addr) => addr,
1291 let repr = adt::represent_type(bcx.ccx(), expr_ty);
1292 adt::trans_start_init(bcx, repr, addr, 0);
1293 let field_dest = adt::trans_field_ptr(bcx, repr, addr, 0, 0);
1294 let contents_datum = unpack_datum!(bcx, trans_boxed_expr(bcx,
1299 bcx = contents_datum.store_to(bcx, field_dest);
1301 // Next, wrap it up in the struct.
1305 // Important to get types for both lhs and rhs, because one might be _|_
1306 // and the other not.
1307 fn trans_eager_binop<'a>(
1309 binop_expr: &ast::Expr,
1316 -> DatumBlock<'a, Expr> {
1317 let _icx = push_ctxt("trans_eager_binop");
1320 if ty::type_is_bot(lhs_t) { rhs_t }
1323 let tcx = bcx.tcx();
1324 if ty::type_is_simd(tcx, intype) {
1325 intype = ty::simd_type(tcx, intype);
1327 let is_float = ty::type_is_fp(intype);
1328 let signed = ty::type_is_signed(intype);
1330 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1333 let val = match op {
1335 if is_float { FAdd(bcx, lhs, rhs) }
1336 else { Add(bcx, lhs, rhs) }
1339 if is_float { FSub(bcx, lhs, rhs) }
1340 else { Sub(bcx, lhs, rhs) }
1343 if is_float { FMul(bcx, lhs, rhs) }
1344 else { Mul(bcx, lhs, rhs) }
1350 // Only zero-check integers; fp /0 is NaN
1351 bcx = base::fail_if_zero(bcx, binop_expr.span,
1364 // Only zero-check integers; fp %0 is NaN
1365 bcx = base::fail_if_zero(bcx, binop_expr.span,
1374 ast::BiBitOr => Or(bcx, lhs, rhs),
1375 ast::BiBitAnd => And(bcx, lhs, rhs),
1376 ast::BiBitXor => Xor(bcx, lhs, rhs),
1377 ast::BiShl => Shl(bcx, lhs, rhs),
1381 } else { LShr(bcx, lhs, rhs) }
1383 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1384 if ty::type_is_bot(rhs_t) {
1387 if !ty::type_is_scalar(rhs_t) {
1388 bcx.tcx().sess.span_bug(binop_expr.span,
1389 "non-scalar comparison");
1391 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1393 ZExt(bcx, cmpr.val, Type::i8())
1397 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1401 immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1404 // refinement types would obviate the need for this
1405 enum lazy_binop_ty {
1410 fn trans_lazy_binop<'a>(
1412 binop_expr: &ast::Expr,
1416 -> DatumBlock<'a, Expr> {
1417 let _icx = push_ctxt("trans_lazy_binop");
1418 let binop_ty = expr_ty(bcx, binop_expr);
1421 let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
1422 let lhs = lhs.to_llscalarish(past_lhs);
1424 if past_lhs.unreachable.get() {
1425 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1428 let join = fcx.new_id_block("join", binop_expr.id);
1429 let before_rhs = fcx.new_id_block("before_rhs", b.id);
1431 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1433 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1434 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1437 let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
1438 let rhs = rhs.to_llscalarish(past_rhs);
1440 if past_rhs.unreachable.get() {
1441 return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1444 Br(past_rhs, join.llbb);
1445 let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb,
1448 return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1451 fn trans_binary<'a>(
1453 binop_expr: &ast::Expr,
1457 -> DatumBlock<'a, Expr> {
1458 let _icx = push_ctxt("trans_binary");
1459 let ccx = bcx.ccx();
1463 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1466 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1470 let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
1471 let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1472 let binop_ty = expr_ty(bcx, binop_expr);
1474 debug!("trans_binary (expr {}): lhs_datum={}",
1476 lhs_datum.to_str(ccx));
1477 let lhs_ty = lhs_datum.ty;
1478 let lhs = lhs_datum.to_llscalarish(bcx);
1480 debug!("trans_binary (expr {}): rhs_datum={}",
1482 rhs_datum.to_str(ccx));
1483 let rhs_ty = rhs_datum.ty;
1484 let rhs = rhs_datum.to_llscalarish(bcx);
1485 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1486 lhs_ty, lhs, rhs_ty, rhs)
1491 fn trans_overloaded_op<'a, 'b>(
1494 rcvr: &'b ast::Expr,
1495 arg: Option<&'b ast::Expr>,
1498 let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&expr.id).ty;
1499 callee::trans_call_inner(bcx,
1500 Some(expr_info(expr)),
1501 monomorphize_type(bcx, method_ty),
1502 |bcx, arg_cleanup_scope| {
1503 meth::trans_method_callee(bcx,
1508 callee::ArgAutorefSecond(rcvr, arg),
1512 fn int_cast(bcx: &Block,
1518 let _icx = push_ctxt("int_cast");
1520 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1521 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1522 return if dstsz == srcsz {
1523 BitCast(bcx, llsrc, lldsttype)
1524 } else if srcsz > dstsz {
1525 TruncOrBitCast(bcx, llsrc, lldsttype)
1527 SExtOrBitCast(bcx, llsrc, lldsttype)
1529 ZExtOrBitCast(bcx, llsrc, lldsttype)
1534 fn float_cast(bcx: &Block,
1539 let _icx = push_ctxt("float_cast");
1540 let srcsz = llsrctype.float_width();
1541 let dstsz = lldsttype.float_width();
1542 return if dstsz > srcsz {
1543 FPExt(bcx, llsrc, lldsttype)
1544 } else if srcsz > dstsz {
1545 FPTrunc(bcx, llsrc, lldsttype)
1550 pub enum cast_kind {
1558 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1559 match ty::get(t).sty {
1560 ty::ty_char => cast_integral,
1561 ty::ty_float(..) => cast_float,
1562 ty::ty_ptr(..) => cast_pointer,
1563 ty::ty_rptr(..) => cast_pointer,
1564 ty::ty_bare_fn(..) => cast_pointer,
1565 ty::ty_int(..) => cast_integral,
1566 ty::ty_uint(..) => cast_integral,
1567 ty::ty_bool => cast_integral,
1568 ty::ty_enum(..) => cast_enum,
1573 fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
1576 -> DatumBlock<'a, Expr> {
1577 let _icx = push_ctxt("trans_cast");
1579 let ccx = bcx.ccx();
1581 let t_in = expr_ty(bcx, expr);
1582 let t_out = node_id_type(bcx, id);
1583 let k_in = cast_type_kind(t_in);
1584 let k_out = cast_type_kind(t_out);
1585 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1586 let ll_t_in = type_of::type_of(ccx, t_in);
1587 let ll_t_out = type_of::type_of(ccx, t_out);
1589 // Convert the value to be cast into a ValueRef, either by-ref or
1590 // by-value as appropriate given its type:
1591 let datum = unpack_datum!(bcx, trans(bcx, expr));
1592 let newval = match (k_in, k_out) {
1593 (cast_integral, cast_integral) => {
1594 let llexpr = datum.to_llscalarish(bcx);
1595 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1597 (cast_float, cast_float) => {
1598 let llexpr = datum.to_llscalarish(bcx);
1599 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1601 (cast_integral, cast_float) => {
1602 let llexpr = datum.to_llscalarish(bcx);
1604 SIToFP(bcx, llexpr, ll_t_out)
1605 } else { UIToFP(bcx, llexpr, ll_t_out) }
1607 (cast_float, cast_integral) => {
1608 let llexpr = datum.to_llscalarish(bcx);
1609 if ty::type_is_signed(t_out) {
1610 FPToSI(bcx, llexpr, ll_t_out)
1611 } else { FPToUI(bcx, llexpr, ll_t_out) }
1613 (cast_integral, cast_pointer) => {
1614 let llexpr = datum.to_llscalarish(bcx);
1615 IntToPtr(bcx, llexpr, ll_t_out)
1617 (cast_pointer, cast_integral) => {
1618 let llexpr = datum.to_llscalarish(bcx);
1619 PtrToInt(bcx, llexpr, ll_t_out)
1621 (cast_pointer, cast_pointer) => {
1622 let llexpr = datum.to_llscalarish(bcx);
1623 PointerCast(bcx, llexpr, ll_t_out)
1625 (cast_enum, cast_integral) |
1626 (cast_enum, cast_float) => {
1628 let repr = adt::represent_type(ccx, t_in);
1629 let datum = unpack_datum!(
1630 bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
1631 let llexpr_ptr = datum.to_llref();
1633 adt::trans_get_discr(bcx, repr, llexpr_ptr, Some(Type::i64()));
1635 cast_integral => int_cast(bcx, ll_t_out,
1636 val_ty(lldiscrim_a),
1638 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1639 _ => ccx.sess.bug(format!("translating unsupported cast: \
1640 {} ({:?}) -> {} ({:?})",
1641 t_in.repr(ccx.tcx), k_in,
1642 t_out.repr(ccx.tcx), k_out))
1645 _ => ccx.sess.bug(format!("translating unsupported cast: \
1646 {} ({:?}) -> {} ({:?})",
1647 t_in.repr(ccx.tcx), k_in,
1648 t_out.repr(ccx.tcx), k_out))
1650 return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
1653 fn trans_assign_op<'a>(
1660 let _icx = push_ctxt("trans_assign_op");
1663 debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
1665 // User-defined operator methods cannot be used with `+=` etc right now
1667 let method_map = bcx.ccx().maps.method_map.borrow();
1668 !method_map.get().find(&expr.id).is_some()
1671 // Evaluate LHS (destination), which should be an lvalue
1672 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1673 assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
1674 let dst_ty = dst_datum.ty;
1675 let dst = Load(bcx, dst_datum.val);
1678 let rhs_datum = unpack_datum!(bcx, trans(bcx, src));
1679 let rhs_ty = rhs_datum.ty;
1680 let rhs = rhs_datum.to_llscalarish(bcx);
1682 // Perform computation and store the result
1683 let result_datum = unpack_datum!(
1684 bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1685 dst_ty, dst, rhs_ty, rhs));
1686 return result_datum.store_to(bcx, dst_datum.val);
1689 fn trans_log_level<'a>(bcx: &'a Block<'a>) -> DatumBlock<'a, Expr> {
1690 let _icx = push_ctxt("trans_log_level");
1691 let ccx = bcx.ccx();
1693 let (modpath, modname) = {
1695 let external_srcs = ccx.external_srcs.borrow();
1696 match external_srcs.get().find(&bcx.fcx.id) {
1698 ccx.sess.cstore.get_crate_data(src.krate).name.clone()
1700 None => ccx.link_meta.crateid.name.to_str(),
1703 bcx.tcx().map.with_path(bcx.fcx.id, |path| {
1704 let first = ast_map::PathMod(token::intern(srccrate));
1705 let mut path = Some(first).move_iter().chain(path).filter(|e| {
1707 ast_map::PathMod(_) => true,
1711 let modpath: Vec<ast_map::PathElem> = path.collect();
1712 let modname = ast_map::path_to_str(ast_map::Values(modpath.iter()));
1717 let module_data_exists;
1719 let module_data = ccx.module_data.borrow();
1720 module_data_exists = module_data.get().contains_key(&modname);
1723 let global = if module_data_exists {
1724 let mut module_data = ccx.module_data.borrow_mut();
1725 module_data.get().get_copy(&modname)
1727 let s = link::mangle_internal_name_by_path_and_seq(
1728 ast_map::Values(modpath.iter()).chain(None), "loglevel");
1731 global = s.with_c_str(|buf| {
1732 llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
1734 llvm::LLVMSetGlobalConstant(global, False);
1735 llvm::LLVMSetInitializer(global, C_null(Type::i32()));
1736 lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
1739 let mut module_data = ccx.module_data.borrow_mut();
1740 module_data.get().insert(modname, global);
1745 immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32()).to_expr_datumblock()
1748 fn deref_multiple<'a>(bcx: &'a Block<'a>,
1752 -> DatumBlock<'a, Expr> {
1754 let mut datum = datum;
1755 for i in range(1, times+1) {
1756 datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
1758 DatumBlock { bcx: bcx, datum: datum }
1761 fn deref_once<'a>(bcx: &'a Block<'a>,
1765 -> DatumBlock<'a, Expr> {
1766 let ccx = bcx.ccx();
1767 let bcx = write_guard::root_and_write_guard(&datum, bcx, expr.span,
1770 debug!("deref_once(expr={}, datum={}, derefs={})",
1771 expr.repr(bcx.tcx()),
1777 let r = match ty::get(datum.ty).sty {
1778 ty::ty_uniq(content_ty) => {
1779 deref_owned_pointer(bcx, expr, datum, content_ty)
1782 ty::ty_box(content_ty) => {
1783 let datum = unpack_datum!(
1784 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
1785 let llptrref = datum.to_llref();
1786 let llptr = Load(bcx, llptrref);
1787 let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
1788 DatumBlock(bcx, Datum(llbody, content_ty, LvalueExpr))
1791 ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
1792 ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
1793 assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
1795 let ptr = datum.to_llscalarish(bcx);
1797 // Always generate an lvalue datum, even if datum.mode is
1798 // an rvalue. This is because datum.mode is only an
1799 // rvalue for non-owning pointers like &T or *T, in which
1800 // case cleanup *is* scheduled elsewhere, by the true
1801 // owner (or, in the case of *T, by the user).
1802 DatumBlock(bcx, Datum(ptr, content_ty, LvalueExpr))
1806 ty::ty_struct(..) => {
1807 // Subtle efficiency note: In the case where we have a
1808 // newtype struct where the struct itself does not have a
1809 // dtor, but the contents do, we could avoid forcing the
1810 // data into Lvalue and instead return an Rvalue. But it
1811 // doesn't seem worth the trouble.
1812 let datum = unpack_datum!(bcx, ensure_cleanup(bcx, expr, datum));
1814 // Unlike the pointer case above, we generate an
1815 // rvalue datum if we are given an rvalue. There are
1816 // two reasons that this makes sense here:
1818 // 1. dereferencing a struct does not actually perform a
1819 // pointer load and hence the resulting value is not
1820 // naturally by reference, as would be required by an
1823 // 2. the struct always owns its contents, and hence and does not
1824 // itself have a dtor (else it would be in lvalue mode).
1825 let repr = adt::represent_type(ccx, datum.ty);
1826 let ty = adt::deref_ty(ccx, repr);
1827 let Datum { val, kind, .. } = datum;
1828 let r = match kind {
1831 val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
1836 RvalueExpr(Rvalue { mode: ByRef }) => {
1838 val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
1840 kind: RvalueExpr(Rvalue(ByValue))
1843 RvalueExpr(Rvalue { mode: ByValue }) => {
1845 val: ExtractValue(bcx, val, 0),
1847 kind: RvalueExpr(Rvalue(ByValue))
1855 bcx.tcx().sess.span_bug(
1857 format!("deref invoked on expr of illegal type {}",
1858 datum.ty.repr(bcx.tcx())));
1862 debug!("deref_once(expr={}, derefs={}, result={})",
1863 expr.id, derefs, r.datum.to_str(ccx));
1867 fn ensure_cleanup<'a>(mut bcx: &'a Block<'a>,
1870 -> DatumBlock<'a, Expr> {
1872 * If the datum contains data that needs to be dropped,
1873 * convert it to an lvalue, thus ensuring that cleanup
1877 if ty::type_needs_drop(bcx.tcx(), datum.ty) {
1878 let lv_datum = unpack_datum!(
1879 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
1880 DatumBlock(bcx, lv_datum.to_expr_datum())
1882 DatumBlock(bcx, datum)
1886 fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
1890 -> DatumBlock<'a, Expr> {
1892 * We microoptimize derefs of owned pointers a bit here.
1893 * Basically, the idea is to make the deref of an rvalue
1894 * result in an rvalue. This helps to avoid intermediate stack
1895 * slots in the resulting LLVM. The idea here is that, if the
1896 * `~T` pointer is an rvalue, then we can schedule a *shallow*
1897 * free of the `~T` pointer, and then return a ByRef rvalue
1898 * into the pointer. Because the free is shallow, it is legit
1899 * to return an rvalue, because we know that the contents are
1900 * not yet scheduled to be freed. The language rules ensure that the
1901 * contents will be used (or moved) before the free occurs.
1905 RvalueExpr(Rvalue { mode: ByRef }) => {
1906 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1907 let ptr = Load(bcx, datum.val);
1908 bcx.fcx.schedule_free_value(scope, ptr, heap_exchange);
1910 RvalueExpr(Rvalue { mode: ByValue }) => {
1911 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1912 bcx.fcx.schedule_free_value(scope, datum.val, heap_exchange);
1917 // If we had an rvalue in, we produce an rvalue out.
1918 let (llptr, kind) = match datum.kind {
1920 (Load(bcx, datum.val), LvalueExpr)
1922 RvalueExpr(Rvalue { mode: ByRef }) => {
1923 (Load(bcx, datum.val), RvalueExpr(Rvalue(ByRef)))
1925 RvalueExpr(Rvalue { mode: ByValue }) => {
1926 (datum.val, RvalueExpr(Rvalue(ByRef)))
1930 let datum = Datum { ty: content_ty, val: llptr, kind: kind };
1931 DatumBlock { bcx: bcx, datum: datum }