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.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12 * # Translation of Expressions
13 *
14 * Public entry points:
15 *
16 * - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
17 * storing the result into `dest`. This is the preferred form, if you
18 * can manage it.
19 *
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
23 * structural type.
24 *
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.
28 *
29 * - `trans_local_var -> Datum`: looks up a local variable or upvar.
30 *
31 * See doc.rs for more comments.
32 */
33
34 #![allow(non_camel_case_types)]
35
36 use back::abi;
37 use lib::llvm::{ValueRef, llvm};
38 use lib;
39 use metadata::csearch;
40 use middle::lang_items::MallocFnLangItem;
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::ty::struct_fields;
63 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
64 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
65 use middle::ty;
66 use middle::typeck::MethodCall;
67 use util::common::indenter;
68 use util::ppaux::Repr;
69 use util::nodemap::NodeMap;
70 use middle::trans::machine::{llsize_of, llsize_of_alloc};
71 use middle::trans::type_::Type;
72
73 use syntax::ast;
74 use syntax::codemap;
75 use syntax::print::pprust::{expr_to_str};
76
77 // Destinations
78
79 // These are passed around by the code generating functions to track the
80 // destination of a computation's value.
81
82 #[deriving(Eq)]
83 pub enum Dest {
84 SaveIn(ValueRef),
85 Ignore,
86 }
87
88 impl Dest {
89 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
90 match *self {
91 SaveIn(v) => format!("SaveIn({})", ccx.tn.val_to_str(v)),
92 Ignore => "Ignore".to_owned()
93 }
94 }
95 }
96
97 pub fn trans_into<'a>(bcx: &'a Block<'a>,
98 expr: &ast::Expr,
99 dest: Dest)
100 -> &'a Block<'a> {
101 /*!
102 * This function is equivalent to `trans(bcx, expr).store_to_dest(dest)`
103 * but it may generate better optimized LLVM code.
104 */
105
106 let mut bcx = bcx;
107
108 if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
109 // use trans, which may be less efficient but
110 // which will perform the adjustments:
111 let datum = unpack_datum!(bcx, trans(bcx, expr));
112 return datum.store_to_dest(bcx, dest, expr.id)
113 }
114
115 debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
116 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
117
118 bcx.fcx.push_ast_cleanup_scope(expr.id);
119
120 let kind = ty::expr_kind(bcx.tcx(), expr);
121 bcx = match kind {
122 ty::LvalueExpr | ty::RvalueDatumExpr => {
123 trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
124 }
125 ty::RvalueDpsExpr => {
126 trans_rvalue_dps_unadjusted(bcx, expr, dest)
127 }
128 ty::RvalueStmtExpr => {
129 trans_rvalue_stmt_unadjusted(bcx, expr)
130 }
131 };
132
133 bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
134 }
135
136 pub fn trans<'a>(bcx: &'a Block<'a>,
137 expr: &ast::Expr)
138 -> DatumBlock<'a, Expr> {
139 /*!
140 * Translates an expression, returning a datum (and new block)
141 * encapsulating the result. When possible, it is preferred to
142 * use `trans_into`, as that may avoid creating a temporary on
143 * the stack.
144 */
145
146 debug!("trans(expr={})", bcx.expr_to_str(expr));
147
148 let mut bcx = bcx;
149 let fcx = bcx.fcx;
150
151 fcx.push_ast_cleanup_scope(expr.id);
152 let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
153 let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
154 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
155 return DatumBlock(bcx, datum);
156 }
157
158 fn apply_adjustments<'a>(bcx: &'a Block<'a>,
159 expr: &ast::Expr,
160 datum: Datum<Expr>)
161 -> DatumBlock<'a, Expr> {
162 /*!
163 * Helper for trans that apply adjustments from `expr` to `datum`,
164 * which should be the unadjusted translation of `expr`.
165 */
166
167 let mut bcx = bcx;
168 let mut datum = datum;
169 let adjustment = match bcx.tcx().adjustments.borrow().find_copy(&expr.id) {
170 None => {
171 return DatumBlock(bcx, datum);
172 }
173 Some(adj) => { adj }
174 };
175 debug!("unadjusted datum for expr {}: {}",
176 expr.id, datum.to_str(bcx.ccx()));
177 match adjustment {
178 AutoAddEnv(..) => {
179 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
180 }
181 AutoDerefRef(ref adj) => {
182 if adj.autoderefs > 0 {
183 datum = unpack_datum!(
184 bcx, deref_multiple(bcx, expr, datum, adj.autoderefs));
185 }
186
187 datum = match adj.autoref {
188 None => {
189 datum
190 }
191 Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
192 Some(AutoPtr(..)) => {
193 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
194 }
195 Some(AutoBorrowVec(..)) => {
196 unpack_datum!(bcx, auto_slice(bcx, expr, datum))
197 }
198 Some(AutoBorrowVecRef(..)) => {
199 unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
200 }
201 Some(AutoBorrowObj(..)) => {
202 unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum))
203 }
204 };
205 }
206 AutoObject(..) => {
207 let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
208 let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
209 bcx = meth::trans_trait_cast(
210 bcx, datum, expr.id, SaveIn(scratch.val));
211 datum = scratch.to_expr_datum();
212 }
213 }
214 debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
215 return DatumBlock {bcx: bcx, datum: datum};
216
217 fn auto_slice<'a>(
218 bcx: &'a Block<'a>,
219 expr: &ast::Expr,
220 datum: Datum<Expr>)
221 -> DatumBlock<'a, Expr> {
222 // This is not the most efficient thing possible; since slices
223 // are two words it'd be better if this were compiled in
224 // 'dest' mode, but I can't find a nice way to structure the
225 // code and keep it DRY that accommodates that use case at the
226 // moment.
227
228 let mut bcx = bcx;
229 let tcx = bcx.tcx();
230 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
231
232 // Arrange cleanup, if not already done. This is needed in
233 // case we are auto-slicing an owned vector or some such.
234 let datum = unpack_datum!(
235 bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id));
236
237 let (base, len) = datum.get_vec_base_and_len(bcx);
238
239 // this type may have a different region/mutability than the
240 // real one, but it will have the same runtime representation
241 let slice_ty = ty::mk_slice(tcx, ty::ReStatic,
242 ty::mt { ty: unit_ty, mutbl: ast::MutImmutable });
243
244 let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust");
245 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
246 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
247 DatumBlock(bcx, scratch.to_expr_datum())
248 }
249
250 fn add_env<'a>(bcx: &'a Block<'a>,
251 expr: &ast::Expr,
252 datum: Datum<Expr>)
253 -> DatumBlock<'a, Expr> {
254 // This is not the most efficient thing possible; since closures
255 // are two words it'd be better if this were compiled in
256 // 'dest' mode, but I can't find a nice way to structure the
257 // code and keep it DRY that accommodates that use case at the
258 // moment.
259
260 let closure_ty = expr_ty_adjusted(bcx, expr);
261 let fn_ptr = datum.to_llscalarish(bcx);
262 let def = ty::resolve_expr(bcx.tcx(), expr);
263 closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
264 }
265
266 fn auto_slice_and_ref<'a>(
267 bcx: &'a Block<'a>,
268 expr: &ast::Expr,
269 datum: Datum<Expr>)
270 -> DatumBlock<'a, Expr> {
271 let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
272 auto_ref(bcx, datum, expr)
273 }
274
275 fn auto_borrow_obj<'a>(bcx: &'a Block<'a>,
276 expr: &ast::Expr,
277 source_datum: Datum<Expr>)
278 -> DatumBlock<'a, Expr> {
279 let tcx = bcx.tcx();
280 let target_obj_ty = expr_ty_adjusted(bcx, expr);
281 debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx));
282
283 let mut datum = source_datum.to_expr_datum();
284 datum.ty = target_obj_ty;
285 DatumBlock(bcx, datum)
286 }
287 }
288
289 pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
290 expr: &ast::Expr,
291 name: &str)
292 -> DatumBlock<'a, Lvalue> {
293 /*!
294 * Translates an expression in "lvalue" mode -- meaning that it
295 * returns a reference to the memory that the expr represents.
296 *
297 * If this expression is an rvalue, this implies introducing a
298 * temporary. In other words, something like `x().f` is
299 * translated into roughly the equivalent of
300 *
301 * { tmp = x(); tmp.f }
302 */
303
304 let mut bcx = bcx;
305 let datum = unpack_datum!(bcx, trans(bcx, expr));
306 return datum.to_lvalue_datum(bcx, name, expr.id);
307 }
308
309 fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
310 expr: &ast::Expr)
311 -> DatumBlock<'a, Expr> {
312 /*!
313 * A version of `trans` that ignores adjustments. You almost
314 * certainly do not want to call this directly.
315 */
316
317 let mut bcx = bcx;
318
319 debug!("trans_unadjusted(expr={})", bcx.expr_to_str(expr));
320 let _indenter = indenter();
321
322 debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
323
324 return match ty::expr_kind(bcx.tcx(), expr) {
325 ty::LvalueExpr | ty::RvalueDatumExpr => {
326 let datum = unpack_datum!(bcx, {
327 trans_datum_unadjusted(bcx, expr)
328 });
329
330 DatumBlock {bcx: bcx, datum: datum}
331 }
332
333 ty::RvalueStmtExpr => {
334 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
335 nil(bcx, expr_ty(bcx, expr))
336 }
337
338 ty::RvalueDpsExpr => {
339 let ty = expr_ty(bcx, expr);
340 if type_is_zero_size(bcx.ccx(), ty) {
341 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
342 nil(bcx, ty)
343 } else {
344 let scratch = rvalue_scratch_datum(bcx, ty, "");
345 bcx = trans_rvalue_dps_unadjusted(
346 bcx, expr, SaveIn(scratch.val));
347
348 // Note: this is not obviously a good idea. It causes
349 // immediate values to be loaded immediately after a
350 // return from a call or other similar expression,
351 // which in turn leads to alloca's having shorter
352 // lifetimes and hence larger stack frames. However,
353 // in turn it can lead to more register pressure.
354 // Still, in practice it seems to increase
355 // performance, since we have fewer problems with
356 // morestack churn.
357 let scratch = unpack_datum!(
358 bcx, scratch.to_appropriate_datum(bcx));
359
360 DatumBlock(bcx, scratch.to_expr_datum())
361 }
362 }
363 };
364
365 fn nil<'a>(bcx: &'a Block<'a>, ty: ty::t) -> DatumBlock<'a, Expr> {
366 let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
367 let datum = immediate_rvalue(llval, ty);
368 DatumBlock(bcx, datum.to_expr_datum())
369 }
370 }
371
372 fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
373 expr: &ast::Expr)
374 -> DatumBlock<'a, Expr> {
375 let mut bcx = bcx;
376 let fcx = bcx.fcx;
377 let _icx = push_ctxt("trans_datum_unadjusted");
378
379 match expr.node {
380 ast::ExprParen(e) => {
381 trans(bcx, e)
382 }
383 ast::ExprPath(_) => {
384 trans_def(bcx, expr, bcx.def(expr.id))
385 }
386 ast::ExprField(base, ident, _) => {
387 trans_rec_field(bcx, base, ident)
388 }
389 ast::ExprIndex(base, idx) => {
390 trans_index(bcx, expr, base, idx)
391 }
392 ast::ExprVstore(contents, ast::ExprVstoreUniq) => {
393 fcx.push_ast_cleanup_scope(contents.id);
394 let datum = unpack_datum!(
395 bcx, tvec::trans_uniq_vstore(bcx, expr, contents));
396 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
397 DatumBlock(bcx, datum)
398 }
399 ast::ExprBox(_, contents) => {
400 // Special case for `box T`. (The other case, for GC, is handled
401 // in `trans_rvalue_dps_unadjusted`.)
402 let box_ty = expr_ty(bcx, expr);
403 let contents_ty = expr_ty(bcx, contents);
404 trans_uniq_expr(bcx, box_ty, contents, contents_ty)
405 }
406 ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
407 ast::ExprBinary(op, lhs, rhs) => {
408 trans_binary(bcx, expr, op, lhs, rhs)
409 }
410 ast::ExprUnary(op, x) => {
411 trans_unary(bcx, expr, op, x)
412 }
413 ast::ExprAddrOf(_, x) => {
414 trans_addr_of(bcx, expr, x)
415 }
416 ast::ExprCast(val, _) => {
417 // Datum output mode means this is a scalar cast:
418 trans_imm_cast(bcx, val, expr.id)
419 }
420 _ => {
421 bcx.tcx().sess.span_bug(
422 expr.span,
423 format!("trans_rvalue_datum_unadjusted reached \
424 fall-through case: {:?}",
425 expr.node));
426 }
427 }
428 }
429
430 fn trans_rec_field<'a>(bcx: &'a Block<'a>,
431 base: &ast::Expr,
432 field: ast::Ident)
433 -> DatumBlock<'a, Expr> {
434 //! Translates `base.field`.
435
436 let mut bcx = bcx;
437 let _icx = push_ctxt("trans_rec_field");
438
439 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
440 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
441 with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
442 let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
443 let d = base_datum.get_element(
444 field_tys[ix].mt.ty,
445 |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
446 DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
447 })
448 }
449
450 fn trans_index<'a>(bcx: &'a Block<'a>,
451 index_expr: &ast::Expr,
452 base: &ast::Expr,
453 idx: &ast::Expr)
454 -> DatumBlock<'a, Expr> {
455 //! Translates `base[idx]`.
456
457 let _icx = push_ctxt("trans_index");
458 let ccx = bcx.ccx();
459 let mut bcx = bcx;
460
461 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
462
463 // Translate index expression and cast to a suitable LLVM integer.
464 // Rust is less strict than LLVM in this regard.
465 let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
466 let ix_val = ix_datum.to_llscalarish(bcx);
467 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
468 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
469 let ix_val = {
470 if ix_size < int_size {
471 if ty::type_is_signed(expr_ty(bcx, idx)) {
472 SExt(bcx, ix_val, ccx.int_type)
473 } else { ZExt(bcx, ix_val, ccx.int_type) }
474 } else if ix_size > int_size {
475 Trunc(bcx, ix_val, ccx.int_type)
476 } else {
477 ix_val
478 }
479 };
480
481 let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), base_datum.ty));
482 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
483
484 let (base, len) = base_datum.get_vec_base_and_len(bcx);
485
486 debug!("trans_index: base {}", bcx.val_to_str(base));
487 debug!("trans_index: len {}", bcx.val_to_str(len));
488
489 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
490 let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
491 let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
492 let bcx = with_cond(bcx, expected, |bcx| {
493 controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
494 });
495 let elt = InBoundsGEP(bcx, base, [ix_val]);
496 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
497 DatumBlock(bcx, Datum(elt, vt.unit_ty, LvalueExpr))
498 }
499
500 fn trans_def<'a>(bcx: &'a Block<'a>,
501 ref_expr: &ast::Expr,
502 def: ast::Def)
503 -> DatumBlock<'a, Expr>
504 {
505 //! Translates a reference to a path.
506
507 let _icx = push_ctxt("trans_def_lvalue");
508 match def {
509 ast::DefFn(..) | ast::DefStaticMethod(..) |
510 ast::DefStruct(_) | ast::DefVariant(..) => {
511 trans_def_fn_unadjusted(bcx, ref_expr, def)
512 }
513 ast::DefStatic(did, _) => {
514 let const_ty = expr_ty(bcx, ref_expr);
515
516 fn get_did(ccx: &CrateContext, did: ast::DefId)
517 -> ast::DefId {
518 if did.krate != ast::LOCAL_CRATE {
519 inline::maybe_instantiate_inline(ccx, did)
520 } else {
521 did
522 }
523 }
524
525 fn get_val<'a>(bcx: &'a Block<'a>, did: ast::DefId, const_ty: ty::t)
526 -> ValueRef {
527 // For external constants, we don't inline.
528 if did.krate == ast::LOCAL_CRATE {
529 // The LLVM global has the type of its initializer,
530 // which may not be equal to the enum's type for
531 // non-C-like enums.
532 let val = base::get_item_val(bcx.ccx(), did.node);
533 let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
534 PointerCast(bcx, val, pty)
535 } else {
536 match bcx.ccx().extern_const_values.borrow().find(&did) {
537 None => {} // Continue.
538 Some(llval) => {
539 return *llval;
540 }
541 }
542
543 unsafe {
544 let llty = type_of::type_of(bcx.ccx(), const_ty);
545 let symbol = csearch::get_symbol(
546 &bcx.ccx().sess().cstore,
547 did);
548 let llval = symbol.with_c_str(|buf| {
549 llvm::LLVMAddGlobal(bcx.ccx().llmod,
550 llty.to_ref(),
551 buf)
552 });
553 bcx.ccx().extern_const_values.borrow_mut()
554 .insert(did, llval);
555 llval
556 }
557 }
558 }
559
560 let did = get_did(bcx.ccx(), did);
561 let val = get_val(bcx, did, const_ty);
562 DatumBlock(bcx, Datum(val, const_ty, LvalueExpr))
563 }
564 _ => {
565 DatumBlock(bcx, trans_local_var(bcx, def).to_expr_datum())
566 }
567 }
568 }
569
570 fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
571 expr: &ast::Expr)
572 -> &'a Block<'a> {
573 let mut bcx = bcx;
574 let _icx = push_ctxt("trans_rvalue_stmt");
575
576 if bcx.unreachable.get() {
577 return bcx;
578 }
579
580 match expr.node {
581 ast::ExprParen(e) => {
582 trans_into(bcx, e, Ignore)
583 }
584 ast::ExprBreak(label_opt) => {
585 controlflow::trans_break(bcx, expr.id, label_opt)
586 }
587 ast::ExprAgain(label_opt) => {
588 controlflow::trans_cont(bcx, expr.id, label_opt)
589 }
590 ast::ExprRet(ex) => {
591 controlflow::trans_ret(bcx, ex)
592 }
593 ast::ExprWhile(cond, body) => {
594 controlflow::trans_while(bcx, expr.id, cond, body)
595 }
596 ast::ExprLoop(body, _) => {
597 controlflow::trans_loop(bcx, expr.id, body)
598 }
599 ast::ExprAssign(dst, src) => {
600 let src_datum = unpack_datum!(bcx, trans(bcx, src));
601 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign"));
602
603 if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
604 // If there are destructors involved, make sure we
605 // are copying from an rvalue, since that cannot possible
606 // alias an lvalue. We are concerned about code like:
607 //
608 // a = a
609 //
610 // but also
611 //
612 // a = a.b
613 //
614 // where e.g. a : Option<Foo> and a.b :
615 // Option<Foo>. In that case, freeing `a` before the
616 // assignment may also free `a.b`!
617 //
618 // We could avoid this intermediary with some analysis
619 // to determine whether `dst` may possibly own `src`.
620 let src_datum = unpack_datum!(
621 bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
622 bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
623 src_datum.store_to(bcx, dst_datum.val)
624 } else {
625 src_datum.store_to(bcx, dst_datum.val)
626 }
627 }
628 ast::ExprAssignOp(op, dst, src) => {
629 trans_assign_op(bcx, expr, op, dst, src)
630 }
631 ast::ExprInlineAsm(ref a) => {
632 asm::trans_inline_asm(bcx, a)
633 }
634 _ => {
635 bcx.tcx().sess.span_bug(
636 expr.span,
637 format!("trans_rvalue_stmt_unadjusted reached \
638 fall-through case: {:?}",
639 expr.node));
640 }
641 }
642 }
643
644 fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
645 expr: &ast::Expr,
646 dest: Dest)
647 -> &'a Block<'a> {
648 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
649 let mut bcx = bcx;
650 let tcx = bcx.tcx();
651 let fcx = bcx.fcx;
652
653 match expr.node {
654 ast::ExprParen(e) => {
655 trans_into(bcx, e, dest)
656 }
657 ast::ExprPath(_) => {
658 trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
659 }
660 ast::ExprIf(cond, thn, els) => {
661 controlflow::trans_if(bcx, expr.id, cond, thn, els, dest)
662 }
663 ast::ExprMatch(discr, ref arms) => {
664 _match::trans_match(bcx, expr, discr, arms.as_slice(), dest)
665 }
666 ast::ExprBlock(blk) => {
667 controlflow::trans_block(bcx, blk, dest)
668 }
669 ast::ExprStruct(_, ref fields, base) => {
670 trans_rec_or_struct(bcx,
671 fields.as_slice(),
672 base,
673 expr.span,
674 expr.id,
675 dest)
676 }
677 ast::ExprTup(ref args) => {
678 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
679 let numbered_fields: Vec<(uint, @ast::Expr)> =
680 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
681 trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
682 }
683 ast::ExprLit(lit) => {
684 match lit.node {
685 ast::LitStr(ref s, _) => {
686 tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
687 }
688 _ => {
689 bcx.tcx()
690 .sess
691 .span_bug(expr.span,
692 "trans_rvalue_dps_unadjusted shouldn't be \
693 translating this type of literal")
694 }
695 }
696 }
697 ast::ExprVstore(contents, ast::ExprVstoreSlice) |
698 ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
699 fcx.push_ast_cleanup_scope(contents.id);
700 bcx = tvec::trans_slice_vstore(bcx, expr, contents, dest);
701 fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
702 }
703 ast::ExprVec(..) | ast::ExprRepeat(..) => {
704 tvec::trans_fixed_vstore(bcx, expr, expr, dest)
705 }
706 ast::ExprFnBlock(decl, body) |
707 ast::ExprProc(decl, body) => {
708 let expr_ty = expr_ty(bcx, expr);
709 let store = ty::ty_closure_store(expr_ty);
710 debug!("translating block function {} with type {}",
711 expr_to_str(expr), expr_ty.repr(tcx));
712 closure::trans_expr_fn(bcx, store, decl, body, expr.id, dest)
713 }
714 ast::ExprCall(f, ref args) => {
715 callee::trans_call(bcx, expr, f, callee::ArgExprs(args.as_slice()), dest)
716 }
717 ast::ExprMethodCall(_, _, ref args) => {
718 callee::trans_method_call(bcx,
719 expr,
720 *args.get(0),
721 callee::ArgExprs(args.as_slice()),
722 dest)
723 }
724 ast::ExprBinary(_, lhs, rhs) => {
725 // if not overloaded, would be RvalueDatumExpr
726 let lhs = unpack_datum!(bcx, trans(bcx, lhs));
727 let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
728 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
729 Some((rhs_datum, rhs.id)), Some(dest)).bcx
730 }
731 ast::ExprUnary(_, subexpr) => {
732 // if not overloaded, would be RvalueDatumExpr
733 let arg = unpack_datum!(bcx, trans(bcx, subexpr));
734 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
735 arg, None, Some(dest)).bcx
736 }
737 ast::ExprIndex(base, idx) => {
738 // if not overloaded, would be RvalueDatumExpr
739 let base = unpack_datum!(bcx, trans(bcx, base));
740 let idx_datum = unpack_datum!(bcx, trans(bcx, idx));
741 trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
742 Some((idx_datum, idx.id)), Some(dest)).bcx
743 }
744 ast::ExprCast(val, _) => {
745 // DPS output mode means this is a trait cast:
746 match ty::get(node_id_type(bcx, expr.id)).sty {
747 ty::ty_trait(..) => {
748 let datum = unpack_datum!(bcx, trans(bcx, val));
749 meth::trans_trait_cast(bcx, datum, expr.id, dest)
750 }
751 _ => {
752 bcx.tcx().sess.span_bug(expr.span,
753 "expr_cast of non-trait");
754 }
755 }
756 }
757 ast::ExprAssignOp(op, dst, src) => {
758 trans_assign_op(bcx, expr, op, dst, src)
759 }
760 ast::ExprBox(_, contents) => {
761 // Special case for `Gc<T>` for now. The other case, for unique
762 // pointers, is handled in `trans_rvalue_datum_unadjusted`.
763 trans_gc(bcx, expr, contents, dest)
764 }
765 _ => {
766 bcx.tcx().sess.span_bug(
767 expr.span,
768 format!("trans_rvalue_dps_unadjusted reached fall-through case: {:?}",
769 expr.node));
770 }
771 }
772 }
773
774 fn trans_def_dps_unadjusted<'a>(
775 bcx: &'a Block<'a>,
776 ref_expr: &ast::Expr,
777 def: ast::Def,
778 dest: Dest)
779 -> &'a Block<'a> {
780 let _icx = push_ctxt("trans_def_dps_unadjusted");
781
782 let lldest = match dest {
783 SaveIn(lldest) => lldest,
784 Ignore => { return bcx; }
785 };
786
787 match def {
788 ast::DefVariant(tid, vid, _) => {
789 let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
790 if variant_info.args.len() > 0u {
791 // N-ary variant.
792 let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
793 Store(bcx, llfn, lldest);
794 return bcx;
795 } else {
796 // Nullary variant.
797 let ty = expr_ty(bcx, ref_expr);
798 let repr = adt::represent_type(bcx.ccx(), ty);
799 adt::trans_start_init(bcx, &*repr, lldest,
800 variant_info.disr_val);
801 return bcx;
802 }
803 }
804 ast::DefStruct(_) => {
805 let ty = expr_ty(bcx, ref_expr);
806 match ty::get(ty).sty {
807 ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
808 let repr = adt::represent_type(bcx.ccx(), ty);
809 adt::trans_start_init(bcx, &*repr, lldest, 0);
810 }
811 _ => {}
812 }
813 bcx
814 }
815 _ => {
816 bcx.tcx().sess.span_bug(ref_expr.span, format!(
817 "Non-DPS def {:?} referened by {}",
818 def, bcx.node_id_to_str(ref_expr.id)));
819 }
820 }
821 }
822
823 fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
824 ref_expr: &ast::Expr,
825 def: ast::Def) -> DatumBlock<'a, Expr> {
826 let _icx = push_ctxt("trans_def_datum_unadjusted");
827
828 let llfn = match def {
829 ast::DefFn(did, _) |
830 ast::DefStruct(did) | ast::DefVariant(_, did, _) |
831 ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
832 callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
833 }
834 ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
835 meth::trans_static_method_callee(bcx, impl_did,
836 trait_did, ref_expr.id)
837 }
838 _ => {
839 bcx.tcx().sess.span_bug(ref_expr.span, format!(
840 "trans_def_fn_unadjusted invoked on: {:?} for {}",
841 def,
842 ref_expr.repr(bcx.tcx())));
843 }
844 };
845
846 let fn_ty = expr_ty(bcx, ref_expr);
847 DatumBlock(bcx, Datum(llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
848 }
849
850 pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
851 def: ast::Def)
852 -> Datum<Lvalue> {
853 /*!
854 * Translates a reference to a local variable or argument.
855 * This always results in an lvalue datum.
856 */
857
858 let _icx = push_ctxt("trans_local_var");
859
860 return match def {
861 ast::DefUpvar(nid, _, _, _) => {
862 // Can't move upvars, so this is never a ZeroMemLastUse.
863 let local_ty = node_id_type(bcx, nid);
864 match bcx.fcx.llupvars.borrow().find(&nid) {
865 Some(&val) => Datum(val, local_ty, Lvalue),
866 None => {
867 bcx.sess().bug(format!(
868 "trans_local_var: no llval for upvar {:?} found", nid));
869 }
870 }
871 }
872 ast::DefArg(nid, _) => {
873 take_local(bcx, &*bcx.fcx.llargs.borrow(), nid)
874 }
875 ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
876 take_local(bcx, &*bcx.fcx.lllocals.borrow(), nid)
877 }
878 _ => {
879 bcx.sess().unimpl(format!(
880 "unsupported def type in trans_local_var: {:?}", def));
881 }
882 };
883
884 fn take_local<'a>(bcx: &'a Block<'a>,
885 table: &NodeMap<Datum<Lvalue>>,
886 nid: ast::NodeId)
887 -> Datum<Lvalue> {
888 let datum = match table.find(&nid) {
889 Some(&v) => v,
890 None => {
891 bcx.sess().bug(format!(
892 "trans_local_var: no datum for local/arg {:?} found", nid));
893 }
894 };
895 debug!("take_local(nid={:?}, v={}, ty={})",
896 nid, bcx.val_to_str(datum.val), bcx.ty_to_str(datum.ty));
897 datum
898 }
899 }
900
901 pub fn with_field_tys<R>(tcx: &ty::ctxt,
902 ty: ty::t,
903 node_id_opt: Option<ast::NodeId>,
904 op: |ty::Disr, (&[ty::field])| -> R)
905 -> R {
906 /*!
907 * Helper for enumerating the field types of structs, enums, or records.
908 * The optional node ID here is the node ID of the path identifying the enum
909 * variant in use. If none, this cannot possibly an enum variant (so, if it
910 * is and `node_id_opt` is none, this function fails).
911 */
912
913 match ty::get(ty).sty {
914 ty::ty_struct(did, ref substs) => {
915 op(0, struct_fields(tcx, did, substs).as_slice())
916 }
917
918 ty::ty_enum(_, ref substs) => {
919 // We want the *variant* ID here, not the enum ID.
920 match node_id_opt {
921 None => {
922 tcx.sess.bug(format!(
923 "cannot get field types from the enum type {} \
924 without a node ID",
925 ty.repr(tcx)));
926 }
927 Some(node_id) => {
928 let def = tcx.def_map.borrow().get_copy(&node_id);
929 match def {
930 ast::DefVariant(enum_id, variant_id, _) => {
931 let variant_info = ty::enum_variant_with_id(
932 tcx, enum_id, variant_id);
933 op(variant_info.disr_val,
934 struct_fields(tcx,
935 variant_id,
936 substs).as_slice())
937 }
938 _ => {
939 tcx.sess.bug("resolve didn't map this expr to a \
940 variant ID")
941 }
942 }
943 }
944 }
945 }
946
947 _ => {
948 tcx.sess.bug(format!(
949 "cannot get field types from the type {}",
950 ty.repr(tcx)));
951 }
952 }
953 }
954
955 fn trans_rec_or_struct<'a>(
956 bcx: &'a Block<'a>,
957 fields: &[ast::Field],
958 base: Option<@ast::Expr>,
959 expr_span: codemap::Span,
960 id: ast::NodeId,
961 dest: Dest)
962 -> &'a Block<'a> {
963 let _icx = push_ctxt("trans_rec");
964 let bcx = bcx;
965
966 let ty = node_id_type(bcx, id);
967 let tcx = bcx.tcx();
968 with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
969 let mut need_base = Vec::from_elem(field_tys.len(), true);
970
971 let numbered_fields = fields.iter().map(|field| {
972 let opt_pos =
973 field_tys.iter().position(|field_ty|
974 field_ty.ident.name == field.ident.node.name);
975 match opt_pos {
976 Some(i) => {
977 *need_base.get_mut(i) = false;
978 (i, field.expr)
979 }
980 None => {
981 tcx.sess.span_bug(field.span,
982 "Couldn't find field in struct type")
983 }
984 }
985 }).collect::<Vec<_>>();
986 let optbase = match base {
987 Some(base_expr) => {
988 let mut leftovers = Vec::new();
989 for (i, b) in need_base.iter().enumerate() {
990 if *b {
991 leftovers.push((i, field_tys[i].mt.ty))
992 }
993 }
994 Some(StructBaseInfo {expr: base_expr,
995 fields: leftovers })
996 }
997 None => {
998 if need_base.iter().any(|b| *b) {
999 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1000 }
1001 None
1002 }
1003 };
1004
1005 let repr = adt::represent_type(bcx.ccx(), ty);
1006 trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
1007 })
1008 }
1009
1010 /**
1011 * Information that `trans_adt` needs in order to fill in the fields
1012 * of a struct copied from a base struct (e.g., from an expression
1013 * like `Foo { a: b, ..base }`.
1014 *
1015 * Note that `fields` may be empty; the base expression must always be
1016 * evaluated for side-effects.
1017 */
1018 struct StructBaseInfo {
1019 /// The base expression; will be evaluated after all explicit fields.
1020 expr: @ast::Expr,
1021 /// The indices of fields to copy paired with their types.
1022 fields: Vec<(uint, ty::t)> }
1023
1024 /**
1025 * Constructs an ADT instance:
1026 *
1027 * - `fields` should be a list of field indices paired with the
1028 * expression to store into that field. The initializers will be
1029 * evaluated in the order specified by `fields`.
1030 *
1031 * - `optbase` contains information on the base struct (if any) from
1032 * which remaining fields are copied; see comments on `StructBaseInfo`.
1033 */
1034 fn trans_adt<'a>(
1035 bcx: &'a Block<'a>,
1036 repr: &adt::Repr,
1037 discr: ty::Disr,
1038 fields: &[(uint, @ast::Expr)],
1039 optbase: Option<StructBaseInfo>,
1040 dest: Dest)
1041 -> &'a Block<'a> {
1042 let _icx = push_ctxt("trans_adt");
1043 let fcx = bcx.fcx;
1044 let mut bcx = bcx;
1045 let addr = match dest {
1046 Ignore => {
1047 for &(_i, e) in fields.iter() {
1048 bcx = trans_into(bcx, e, Ignore);
1049 }
1050 for sbi in optbase.iter() {
1051 // FIXME #7261: this moves entire base, not just certain fields
1052 bcx = trans_into(bcx, sbi.expr, Ignore);
1053 }
1054 return bcx;
1055 }
1056 SaveIn(pos) => pos
1057 };
1058
1059 // This scope holds intermediates that must be cleaned should
1060 // failure occur before the ADT as a whole is ready.
1061 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1062
1063 adt::trans_start_init(bcx, repr, addr, discr);
1064
1065 for &(i, e) in fields.iter() {
1066 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1067 let e_ty = expr_ty_adjusted(bcx, e);
1068 bcx = trans_into(bcx, e, SaveIn(dest));
1069 fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
1070 dest, e_ty);
1071 }
1072
1073 for base in optbase.iter() {
1074 // FIXME #6573: is it sound to use the destination's repr on the base?
1075 // And, would it ever be reasonable to be here with discr != 0?
1076 let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base.expr, "base"));
1077 for &(i, t) in base.fields.iter() {
1078 let datum = base_datum.get_element(
1079 t,
1080 |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i));
1081 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1082 bcx = datum.store_to(bcx, dest);
1083 }
1084 }
1085
1086 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1087
1088 return bcx;
1089 }
1090
1091
1092 fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
1093 expr: &ast::Expr,
1094 lit: ast::Lit)
1095 -> DatumBlock<'a, Expr> {
1096 // must not be a string constant, that is a RvalueDpsExpr
1097 let _icx = push_ctxt("trans_immediate_lit");
1098 let ty = expr_ty(bcx, expr);
1099 let v = consts::const_lit(bcx.ccx(), expr, lit);
1100 immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
1101 }
1102
1103 fn trans_unary<'a>(bcx: &'a Block<'a>,
1104 expr: &ast::Expr,
1105 op: ast::UnOp,
1106 sub_expr: &ast::Expr)
1107 -> DatumBlock<'a, Expr> {
1108 let ccx = bcx.ccx();
1109 let mut bcx = bcx;
1110 let _icx = push_ctxt("trans_unary_datum");
1111
1112 let method_call = MethodCall::expr(expr.id);
1113
1114 // The only overloaded operator that is translated to a datum
1115 // is an overloaded deref, since it is always yields a `&T`.
1116 // Otherwise, we should be in the RvalueDpsExpr path.
1117 assert!(
1118 op == ast::UnDeref ||
1119 !ccx.tcx.method_map.borrow().contains_key(&method_call));
1120
1121 let un_ty = expr_ty(bcx, expr);
1122
1123 match op {
1124 ast::UnNot => {
1125 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1126 let llresult = if ty::type_is_bool(un_ty) {
1127 let val = datum.to_llscalarish(bcx);
1128 let llcond = ICmp(bcx,
1129 lib::llvm::IntEQ,
1130 val,
1131 C_bool(ccx, false));
1132 Select(bcx, llcond, C_bool(ccx, true), C_bool(ccx, false))
1133 } else {
1134 // Note: `Not` is bitwise, not suitable for logical not.
1135 Not(bcx, datum.to_llscalarish(bcx))
1136 };
1137 immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
1138 }
1139 ast::UnNeg => {
1140 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1141 let val = datum.to_llscalarish(bcx);
1142 let llneg = {
1143 if ty::type_is_fp(un_ty) {
1144 FNeg(bcx, val)
1145 } else {
1146 Neg(bcx, val)
1147 }
1148 };
1149 immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
1150 }
1151 ast::UnBox => {
1152 trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1153 }
1154 ast::UnUniq => {
1155 trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1156 }
1157 ast::UnDeref => {
1158 let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
1159 deref_once(bcx, expr, datum, 0)
1160 }
1161 }
1162 }
1163
1164 fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
1165 box_ty: ty::t,
1166 contents: &ast::Expr,
1167 contents_ty: ty::t)
1168 -> DatumBlock<'a, Expr> {
1169 let _icx = push_ctxt("trans_uniq_expr");
1170 let fcx = bcx.fcx;
1171 let llty = type_of::type_of(bcx.ccx(), contents_ty);
1172 let size = llsize_of(bcx.ccx(), llty);
1173 // We need to a make a pointer type because box_ty is ty_bot
1174 // if content_ty is, e.g. box fail!().
1175 let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
1176 let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size);
1177 // Unique boxes do not allocate for zero-size types. The standard library
1178 // may assume that `free` is never called on the pointer returned for
1179 // `Box<ZeroSizeType>`.
1180 let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
1181 trans_into(bcx, contents, SaveIn(val))
1182 } else {
1183 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1184 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1185 val, cleanup::HeapExchange);
1186 let bcx = trans_into(bcx, contents, SaveIn(val));
1187 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1188 bcx
1189 };
1190 immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
1191 }
1192
1193 fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
1194 box_ty: ty::t,
1195 contents: &ast::Expr,
1196 contents_ty: ty::t)
1197 -> DatumBlock<'a, Expr> {
1198 let _icx = push_ctxt("trans_managed_expr");
1199 let fcx = bcx.fcx;
1200 let ty = type_of::type_of(bcx.ccx(), contents_ty);
1201 let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
1202 llsize_of(bcx.ccx(), ty));
1203 let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
1204
1205 let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
1206 fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
1207 bx, cleanup::HeapManaged);
1208 let bcx = trans_into(bcx, contents, SaveIn(body));
1209 fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
1210 immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
1211 }
1212
1213 fn trans_addr_of<'a>(bcx: &'a Block<'a>,
1214 expr: &ast::Expr,
1215 subexpr: &ast::Expr)
1216 -> DatumBlock<'a, Expr> {
1217 let _icx = push_ctxt("trans_addr_of");
1218 let mut bcx = bcx;
1219 let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1220 let ty = expr_ty(bcx, expr);
1221 return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
1222 }
1223
1224 fn trans_gc<'a>(mut bcx: &'a Block<'a>,
1225 expr: &ast::Expr,
1226 contents: &ast::Expr,
1227 dest: Dest)
1228 -> &'a Block<'a> {
1229 let contents_ty = expr_ty(bcx, contents);
1230 let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
1231
1232 let contents_datum = unpack_datum!(bcx, trans_managed_expr(bcx,
1233 box_ty,
1234 contents,
1235 contents_ty));
1236
1237 match dest {
1238 Ignore => bcx,
1239 SaveIn(addr) => {
1240 let expr_ty = expr_ty(bcx, expr);
1241 let repr = adt::represent_type(bcx.ccx(), expr_ty);
1242 adt::trans_start_init(bcx, &*repr, addr, 0);
1243 let field_dest = adt::trans_field_ptr(bcx, &*repr, addr, 0, 0);
1244 contents_datum.store_to(bcx, field_dest)
1245 }
1246 }
1247 }
1248
1249 // Important to get types for both lhs and rhs, because one might be _|_
1250 // and the other not.
1251 fn trans_eager_binop<'a>(
1252 bcx: &'a Block<'a>,
1253 binop_expr: &ast::Expr,
1254 binop_ty: ty::t,
1255 op: ast::BinOp,
1256 lhs_t: ty::t,
1257 lhs: ValueRef,
1258 rhs_t: ty::t,
1259 rhs: ValueRef)
1260 -> DatumBlock<'a, Expr> {
1261 let _icx = push_ctxt("trans_eager_binop");
1262
1263 let tcx = bcx.tcx();
1264 let is_simd = ty::type_is_simd(tcx, lhs_t);
1265 let intype = {
1266 if ty::type_is_bot(lhs_t) { rhs_t }
1267 else if is_simd { ty::simd_type(tcx, lhs_t) }
1268 else { lhs_t }
1269 };
1270 let is_float = ty::type_is_fp(intype);
1271 let is_signed = ty::type_is_signed(intype);
1272
1273 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1274
1275 let mut bcx = bcx;
1276 let val = match op {
1277 ast::BiAdd => {
1278 if is_float { FAdd(bcx, lhs, rhs) }
1279 else { Add(bcx, lhs, rhs) }
1280 }
1281 ast::BiSub => {
1282 if is_float { FSub(bcx, lhs, rhs) }
1283 else { Sub(bcx, lhs, rhs) }
1284 }
1285 ast::BiMul => {
1286 if is_float { FMul(bcx, lhs, rhs) }
1287 else { Mul(bcx, lhs, rhs) }
1288 }
1289 ast::BiDiv => {
1290 if is_float {
1291 FDiv(bcx, lhs, rhs)
1292 } else {
1293 // Only zero-check integers; fp /0 is NaN
1294 bcx = base::fail_if_zero(bcx, binop_expr.span,
1295 op, rhs, rhs_t);
1296 if is_signed {
1297 SDiv(bcx, lhs, rhs)
1298 } else {
1299 UDiv(bcx, lhs, rhs)
1300 }
1301 }
1302 }
1303 ast::BiRem => {
1304 if is_float {
1305 FRem(bcx, lhs, rhs)
1306 } else {
1307 // Only zero-check integers; fp %0 is NaN
1308 bcx = base::fail_if_zero(bcx, binop_expr.span,
1309 op, rhs, rhs_t);
1310 if is_signed {
1311 SRem(bcx, lhs, rhs)
1312 } else {
1313 URem(bcx, lhs, rhs)
1314 }
1315 }
1316 }
1317 ast::BiBitOr => Or(bcx, lhs, rhs),
1318 ast::BiBitAnd => And(bcx, lhs, rhs),
1319 ast::BiBitXor => Xor(bcx, lhs, rhs),
1320 ast::BiShl => Shl(bcx, lhs, rhs),
1321 ast::BiShr => {
1322 if is_signed {
1323 AShr(bcx, lhs, rhs)
1324 } else { LShr(bcx, lhs, rhs) }
1325 }
1326 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
1327 if ty::type_is_bot(rhs_t) {
1328 C_bool(bcx.ccx(), false)
1329 } else if ty::type_is_scalar(rhs_t) {
1330 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1331 bcx = cmpr.bcx;
1332 ZExt(bcx, cmpr.val, Type::i8(bcx.ccx()))
1333 } else if is_simd {
1334 base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
1335 } else {
1336 bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
1337 }
1338 }
1339 _ => {
1340 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1341 }
1342 };
1343
1344 immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1345 }
1346
1347 // refinement types would obviate the need for this
1348 enum lazy_binop_ty {
1349 lazy_and,
1350 lazy_or,
1351 }
1352
1353 fn trans_lazy_binop<'a>(
1354 bcx: &'a Block<'a>,
1355 binop_expr: &ast::Expr,
1356 op: lazy_binop_ty,
1357 a: &ast::Expr,
1358 b: &ast::Expr)
1359 -> DatumBlock<'a, Expr> {
1360 let _icx = push_ctxt("trans_lazy_binop");
1361 let binop_ty = expr_ty(bcx, binop_expr);
1362 let fcx = bcx.fcx;
1363
1364 let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
1365 let lhs = lhs.to_llscalarish(past_lhs);
1366
1367 if past_lhs.unreachable.get() {
1368 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
1369 }
1370
1371 let join = fcx.new_id_block("join", binop_expr.id);
1372 let before_rhs = fcx.new_id_block("before_rhs", b.id);
1373
1374 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1375 match op {
1376 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1377 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1378 }
1379
1380 let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
1381 let rhs = rhs.to_llscalarish(past_rhs);
1382
1383 if past_rhs.unreachable.get() {
1384 return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
1385 }
1386
1387 Br(past_rhs, join.llbb);
1388 let phi = Phi(join, Type::bool(bcx.ccx()), [lhs, rhs],
1389 [past_lhs.llbb, past_rhs.llbb]);
1390
1391 return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
1392 }
1393
1394 fn trans_binary<'a>(bcx: &'a Block<'a>,
1395 expr: &ast::Expr,
1396 op: ast::BinOp,
1397 lhs: &ast::Expr,
1398 rhs: &ast::Expr)
1399 -> DatumBlock<'a, Expr> {
1400 let _icx = push_ctxt("trans_binary");
1401 let ccx = bcx.ccx();
1402
1403 // if overloaded, would be RvalueDpsExpr
1404 assert!(!ccx.tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1405
1406 match op {
1407 ast::BiAnd => {
1408 trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1409 }
1410 ast::BiOr => {
1411 trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1412 }
1413 _ => {
1414 let mut bcx = bcx;
1415 let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
1416 let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
1417 let binop_ty = expr_ty(bcx, expr);
1418
1419 debug!("trans_binary (expr {}): lhs_datum={}",
1420 expr.id,
1421 lhs_datum.to_str(ccx));
1422 let lhs_ty = lhs_datum.ty;
1423 let lhs = lhs_datum.to_llscalarish(bcx);
1424
1425 debug!("trans_binary (expr {}): rhs_datum={}",
1426 expr.id,
1427 rhs_datum.to_str(ccx));
1428 let rhs_ty = rhs_datum.ty;
1429 let rhs = rhs_datum.to_llscalarish(bcx);
1430 trans_eager_binop(bcx, expr, binop_ty, op,
1431 lhs_ty, lhs, rhs_ty, rhs)
1432 }
1433 }
1434 }
1435
1436 fn trans_overloaded_op<'a, 'b>(
1437 bcx: &'a Block<'a>,
1438 expr: &ast::Expr,
1439 method_call: MethodCall,
1440 lhs: Datum<Expr>,
1441 rhs: Option<(Datum<Expr>, ast::NodeId)>,
1442 dest: Option<Dest>)
1443 -> Result<'a> {
1444 let method_ty = bcx.tcx().method_map.borrow().get(&method_call).ty;
1445 callee::trans_call_inner(bcx,
1446 Some(expr_info(expr)),
1447 monomorphize_type(bcx, method_ty),
1448 |bcx, arg_cleanup_scope| {
1449 meth::trans_method_callee(bcx,
1450 method_call,
1451 None,
1452 arg_cleanup_scope)
1453 },
1454 callee::ArgOverloadedOp(lhs, rhs),
1455 dest)
1456 }
1457
1458 fn int_cast(bcx: &Block,
1459 lldsttype: Type,
1460 llsrctype: Type,
1461 llsrc: ValueRef,
1462 signed: bool)
1463 -> ValueRef {
1464 let _icx = push_ctxt("int_cast");
1465 unsafe {
1466 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1467 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1468 return if dstsz == srcsz {
1469 BitCast(bcx, llsrc, lldsttype)
1470 } else if srcsz > dstsz {
1471 TruncOrBitCast(bcx, llsrc, lldsttype)
1472 } else if signed {
1473 SExtOrBitCast(bcx, llsrc, lldsttype)
1474 } else {
1475 ZExtOrBitCast(bcx, llsrc, lldsttype)
1476 };
1477 }
1478 }
1479
1480 fn float_cast(bcx: &Block,
1481 lldsttype: Type,
1482 llsrctype: Type,
1483 llsrc: ValueRef)
1484 -> ValueRef {
1485 let _icx = push_ctxt("float_cast");
1486 let srcsz = llsrctype.float_width();
1487 let dstsz = lldsttype.float_width();
1488 return if dstsz > srcsz {
1489 FPExt(bcx, llsrc, lldsttype)
1490 } else if srcsz > dstsz {
1491 FPTrunc(bcx, llsrc, lldsttype)
1492 } else { llsrc };
1493 }
1494
1495 #[deriving(Eq)]
1496 pub enum cast_kind {
1497 cast_pointer,
1498 cast_integral,
1499 cast_float,
1500 cast_enum,
1501 cast_other,
1502 }
1503
1504 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1505 match ty::get(t).sty {
1506 ty::ty_char => cast_integral,
1507 ty::ty_float(..) => cast_float,
1508 ty::ty_ptr(..) => cast_pointer,
1509 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
1510 ty::ty_vec(_, None) | ty::ty_str => cast_other,
1511 _ => cast_pointer,
1512 },
1513 ty::ty_bare_fn(..) => cast_pointer,
1514 ty::ty_int(..) => cast_integral,
1515 ty::ty_uint(..) => cast_integral,
1516 ty::ty_bool => cast_integral,
1517 ty::ty_enum(..) => cast_enum,
1518 _ => cast_other
1519 }
1520 }
1521
1522 fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
1523 expr: &ast::Expr,
1524 id: ast::NodeId)
1525 -> DatumBlock<'a, Expr> {
1526 let _icx = push_ctxt("trans_cast");
1527 let mut bcx = bcx;
1528 let ccx = bcx.ccx();
1529
1530 let t_in = expr_ty(bcx, expr);
1531 let t_out = node_id_type(bcx, id);
1532 let k_in = cast_type_kind(t_in);
1533 let k_out = cast_type_kind(t_out);
1534 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1535 let ll_t_in = type_of::type_of(ccx, t_in);
1536 let ll_t_out = type_of::type_of(ccx, t_out);
1537
1538 // Convert the value to be cast into a ValueRef, either by-ref or
1539 // by-value as appropriate given its type:
1540 let datum = unpack_datum!(bcx, trans(bcx, expr));
1541 let newval = match (k_in, k_out) {
1542 (cast_integral, cast_integral) => {
1543 let llexpr = datum.to_llscalarish(bcx);
1544 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1545 }
1546 (cast_float, cast_float) => {
1547 let llexpr = datum.to_llscalarish(bcx);
1548 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1549 }
1550 (cast_integral, cast_float) => {
1551 let llexpr = datum.to_llscalarish(bcx);
1552 if s_in {
1553 SIToFP(bcx, llexpr, ll_t_out)
1554 } else { UIToFP(bcx, llexpr, ll_t_out) }
1555 }
1556 (cast_float, cast_integral) => {
1557 let llexpr = datum.to_llscalarish(bcx);
1558 if ty::type_is_signed(t_out) {
1559 FPToSI(bcx, llexpr, ll_t_out)
1560 } else { FPToUI(bcx, llexpr, ll_t_out) }
1561 }
1562 (cast_integral, cast_pointer) => {
1563 let llexpr = datum.to_llscalarish(bcx);
1564 IntToPtr(bcx, llexpr, ll_t_out)
1565 }
1566 (cast_pointer, cast_integral) => {
1567 let llexpr = datum.to_llscalarish(bcx);
1568 PtrToInt(bcx, llexpr, ll_t_out)
1569 }
1570 (cast_pointer, cast_pointer) => {
1571 let llexpr = datum.to_llscalarish(bcx);
1572 PointerCast(bcx, llexpr, ll_t_out)
1573 }
1574 (cast_enum, cast_integral) |
1575 (cast_enum, cast_float) => {
1576 let mut bcx = bcx;
1577 let repr = adt::represent_type(ccx, t_in);
1578 let datum = unpack_datum!(
1579 bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
1580 let llexpr_ptr = datum.to_llref();
1581 let lldiscrim_a =
1582 adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
1583 match k_out {
1584 cast_integral => int_cast(bcx, ll_t_out,
1585 val_ty(lldiscrim_a),
1586 lldiscrim_a, true),
1587 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1588 _ => ccx.sess().bug(format!("translating unsupported cast: \
1589 {} ({:?}) -> {} ({:?})",
1590 t_in.repr(bcx.tcx()), k_in,
1591 t_out.repr(bcx.tcx()), k_out))
1592 }
1593 }
1594 _ => ccx.sess().bug(format!("translating unsupported cast: \
1595 {} ({:?}) -> {} ({:?})",
1596 t_in.repr(bcx.tcx()), k_in,
1597 t_out.repr(bcx.tcx()), k_out))
1598 };
1599 return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
1600 }
1601
1602 fn trans_assign_op<'a>(
1603 bcx: &'a Block<'a>,
1604 expr: &ast::Expr,
1605 op: ast::BinOp,
1606 dst: &ast::Expr,
1607 src: @ast::Expr)
1608 -> &'a Block<'a> {
1609 let _icx = push_ctxt("trans_assign_op");
1610 let mut bcx = bcx;
1611
1612 debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
1613
1614 // User-defined operator methods cannot be used with `+=` etc right now
1615 assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
1616
1617 // Evaluate LHS (destination), which should be an lvalue
1618 let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1619 assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
1620 let dst_ty = dst_datum.ty;
1621 let dst = Load(bcx, dst_datum.val);
1622
1623 // Evaluate RHS
1624 let rhs_datum = unpack_datum!(bcx, trans(bcx, src));
1625 let rhs_ty = rhs_datum.ty;
1626 let rhs = rhs_datum.to_llscalarish(bcx);
1627
1628 // Perform computation and store the result
1629 let result_datum = unpack_datum!(
1630 bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1631 dst_ty, dst, rhs_ty, rhs));
1632 return result_datum.store_to(bcx, dst_datum.val);
1633 }
1634
1635 fn auto_ref<'a>(bcx: &'a Block<'a>,
1636 datum: Datum<Expr>,
1637 expr: &ast::Expr)
1638 -> DatumBlock<'a, Expr> {
1639 let mut bcx = bcx;
1640
1641 // Ensure cleanup of `datum` if not already scheduled and obtain
1642 // a "by ref" pointer.
1643 let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
1644
1645 // Compute final type. Note that we are loose with the region and
1646 // mutability, since those things don't matter in trans.
1647 let referent_ty = lv_datum.ty;
1648 let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
1649
1650 // Get the pointer.
1651 let llref = lv_datum.to_llref();
1652
1653 // Construct the resulting datum, using what was the "by ref"
1654 // ValueRef of type `referent_ty` to be the "by value" ValueRef
1655 // of type `&referent_ty`.
1656 DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
1657 }
1658
1659 fn deref_multiple<'a>(bcx: &'a Block<'a>,
1660 expr: &ast::Expr,
1661 datum: Datum<Expr>,
1662 times: uint)
1663 -> DatumBlock<'a, Expr> {
1664 let mut bcx = bcx;
1665 let mut datum = datum;
1666 for i in range(1, times+1) {
1667 datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
1668 }
1669 DatumBlock { bcx: bcx, datum: datum }
1670 }
1671
1672 fn deref_once<'a>(bcx: &'a Block<'a>,
1673 expr: &ast::Expr,
1674 datum: Datum<Expr>,
1675 derefs: uint)
1676 -> DatumBlock<'a, Expr> {
1677 let ccx = bcx.ccx();
1678
1679 debug!("deref_once(expr={}, datum={}, derefs={})",
1680 expr.repr(bcx.tcx()),
1681 datum.to_str(ccx),
1682 derefs);
1683
1684 let mut bcx = bcx;
1685
1686 // Check for overloaded deref.
1687 let method_call = MethodCall {
1688 expr_id: expr.id,
1689 autoderef: derefs as u32
1690 };
1691 let method_ty = ccx.tcx.method_map.borrow()
1692 .find(&method_call).map(|method| method.ty);
1693 let datum = match method_ty {
1694 Some(method_ty) => {
1695 // Overloaded. Evaluate `trans_overloaded_op`, which will
1696 // invoke the user's deref() method, which basically
1697 // converts from the `Shaht<T>` pointer that we have into
1698 // a `&T` pointer. We can then proceed down the normal
1699 // path (below) to dereference that `&T`.
1700 let datum = if derefs == 0 {
1701 datum
1702 } else {
1703 // Always perform an AutoPtr when applying an overloaded auto-deref.
1704 unpack_datum!(bcx, auto_ref(bcx, datum, expr))
1705 };
1706 let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
1707 datum, None, None));
1708 let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
1709 Datum(val, ref_ty, RvalueExpr(Rvalue(ByValue)))
1710 }
1711 None => {
1712 // Not overloaded. We already have a pointer we know how to deref.
1713 datum
1714 }
1715 };
1716
1717 let r = match ty::get(datum.ty).sty {
1718 ty::ty_uniq(content_ty) => {
1719 match ty::get(content_ty).sty {
1720 ty::ty_vec(_, None) | ty::ty_str
1721 => bcx.tcx().sess.span_bug(expr.span, "unexpected ~[T]"),
1722 _ => deref_owned_pointer(bcx, expr, datum, content_ty),
1723 }
1724 }
1725
1726 ty::ty_box(content_ty) => {
1727 let datum = unpack_datum!(
1728 bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
1729 let llptrref = datum.to_llref();
1730 let llptr = Load(bcx, llptrref);
1731 let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
1732 DatumBlock(bcx, Datum(llbody, content_ty, LvalueExpr))
1733 }
1734
1735 ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
1736 ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
1737 match ty::get(content_ty).sty {
1738 ty::ty_vec(_, None) | ty::ty_str
1739 => bcx.tcx().sess.span_bug(expr.span, "unexpected &[T]"),
1740 _ => {
1741 assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
1742
1743 let ptr = datum.to_llscalarish(bcx);
1744
1745 // Always generate an lvalue datum, even if datum.mode is
1746 // an rvalue. This is because datum.mode is only an
1747 // rvalue for non-owning pointers like &T or *T, in which
1748 // case cleanup *is* scheduled elsewhere, by the true
1749 // owner (or, in the case of *T, by the user).
1750 DatumBlock(bcx, Datum(ptr, content_ty, LvalueExpr))
1751 }
1752 }
1753 }
1754
1755 _ => {
1756 bcx.tcx().sess.span_bug(
1757 expr.span,
1758 format!("deref invoked on expr of illegal type {}",
1759 datum.ty.repr(bcx.tcx())));
1760 }
1761 };
1762
1763 debug!("deref_once(expr={}, derefs={}, result={})",
1764 expr.id, derefs, r.datum.to_str(ccx));
1765
1766 return r;
1767
1768 fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
1769 expr: &ast::Expr,
1770 datum: Datum<Expr>,
1771 content_ty: ty::t)
1772 -> DatumBlock<'a, Expr> {
1773 /*!
1774 * We microoptimize derefs of owned pointers a bit here.
1775 * Basically, the idea is to make the deref of an rvalue
1776 * result in an rvalue. This helps to avoid intermediate stack
1777 * slots in the resulting LLVM. The idea here is that, if the
1778 * `Box<T>` pointer is an rvalue, then we can schedule a *shallow*
1779 * free of the `Box<T>` pointer, and then return a ByRef rvalue
1780 * into the pointer. Because the free is shallow, it is legit
1781 * to return an rvalue, because we know that the contents are
1782 * not yet scheduled to be freed. The language rules ensure that the
1783 * contents will be used (or moved) before the free occurs.
1784 */
1785
1786 match datum.kind {
1787 RvalueExpr(Rvalue { mode: ByRef }) => {
1788 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1789 let ptr = Load(bcx, datum.val);
1790 if !type_is_zero_size(bcx.ccx(), content_ty) {
1791 bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange);
1792 }
1793 }
1794 RvalueExpr(Rvalue { mode: ByValue }) => {
1795 let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
1796 if !type_is_zero_size(bcx.ccx(), content_ty) {
1797 bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange);
1798 }
1799 }
1800 LvalueExpr => { }
1801 }
1802
1803 // If we had an rvalue in, we produce an rvalue out.
1804 let (llptr, kind) = match datum.kind {
1805 LvalueExpr => {
1806 (Load(bcx, datum.val), LvalueExpr)
1807 }
1808 RvalueExpr(Rvalue { mode: ByRef }) => {
1809 (Load(bcx, datum.val), RvalueExpr(Rvalue(ByRef)))
1810 }
1811 RvalueExpr(Rvalue { mode: ByValue }) => {
1812 (datum.val, RvalueExpr(Rvalue(ByRef)))
1813 }
1814 };
1815
1816 let datum = Datum { ty: content_ty, val: llptr, kind: kind };
1817 DatumBlock { bcx: bcx, datum: datum }
1818 }
1819 }
librustc/middle/trans/expr.rs:1033:4-1033:4 -fn- definition:
*/
fn trans_adt<'a>(
bcx: &'a Block<'a>,
references:- 2680: args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
681: trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
682: }
--
1005: let repr = adt::represent_type(bcx.ccx(), ty);
1006: trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
1007: })
librustc/middle/trans/expr.rs:1163:1-1163:1 -fn- definition:
fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
box_ty: ty::t,
contents: &ast::Expr,
references:- 21154: ast::UnUniq => {
1155: trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
1156: }
librustc/middle/trans/expr.rs:217:4-217:4 -fn- definition:
fn auto_slice<'a>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
references:- 2270: -> DatumBlock<'a, Expr> {
271: let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
272: auto_ref(bcx, datum, expr)
librustc/middle/trans/expr.rs:1352:1-1352:1 -fn- definition:
fn trans_lazy_binop<'a>(
bcx: &'a Block<'a>,
binop_expr: &ast::Expr,
references:- 21407: ast::BiAnd => {
1408: trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
1409: }
1410: ast::BiOr => {
1411: trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
1412: }
librustc/middle/trans/expr.rs:1601:1-1601:1 -fn- definition:
fn trans_assign_op<'a>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
references:- 2628: ast::ExprAssignOp(op, dst, src) => {
629: trans_assign_op(bcx, expr, op, dst, src)
630: }
--
757: ast::ExprAssignOp(op, dst, src) => {
758: trans_assign_op(bcx, expr, op, dst, src)
759: }
librustc/middle/trans/expr.rs:900:1-900:1 -fn- definition:
pub fn with_field_tys<R>(tcx: &ty::ctxt,
ty: ty::t,
node_id_opt: Option<ast::NodeId>,
references:- 7440: let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
441: with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
442: let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
--
967: let tcx = bcx.tcx();
968: with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
969: let mut need_base = Vec::from_elem(field_tys.len(), true);
librustc/middle/trans/consts.rs:
418: let (bv, inlineable) = const_expr(cx, base, is_local);
419: expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
420: let ix = ty::field_idx_strict(cx.tcx(), field.name, field_tys);
--
541: expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
542: let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
librustc/middle/trans/base.rs:
691: let repr = adt::represent_type(cx.ccx(), t);
692: expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| {
693: for (i, field_ty) in field_tys.iter().enumerate() {
librustc/middle/trans/_match.rs:
1504: let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
1505: expr::with_field_tys(tcx, pat_ty, Some(pat_id), |discr, field_tys| {
1506: let rec_vals = rec_fields.iter().map(|field_name| {
--
2244: let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
2245: expr::with_field_tys(tcx, pat_ty, Some(pat.id), |discr, field_tys| {
2246: for f in fields.iter() {
librustc/middle/trans/expr.rs:1435:1-1435:1 -fn- definition:
fn trans_overloaded_op<'a, 'b>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
references:- 41705: };
1706: let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
1707: datum, None, None));
librustc/middle/trans/expr.rs:308:1-308:1 -fn- definition:
fn trans_unadjusted<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr)
-> DatumBlock<'a, Expr> {
references:- 2122: ty::LvalueExpr | ty::RvalueDatumExpr => {
123: trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
124: }
--
151: fcx.push_ast_cleanup_scope(expr.id);
152: let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
153: let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
librustc/middle/trans/expr.rs:96:1-96:1 -fn- definition:
pub fn trans_into<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
dest: Dest)
references:- 18581: ast::ExprParen(e) => {
582: trans_into(bcx, e, Ignore)
583: }
--
1051: // FIXME #7261: this moves entire base, not just certain fields
1052: bcx = trans_into(bcx, sbi.expr, Ignore);
1053: }
--
1067: let e_ty = expr_ty_adjusted(bcx, e);
1068: bcx = trans_into(bcx, e, SaveIn(dest));
1069: fcx.schedule_drop_mem(cleanup::CustomScope(custom_cleanup_scope),
--
1207: bx, cleanup::HeapManaged);
1208: let bcx = trans_into(bcx, contents, SaveIn(body));
1209: fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
librustc/middle/trans/_match.rs:
2000: bcx, pat.id, path, BindLocal, var_scope, (),
2001: |(), bcx, v, _| expr::trans_into(bcx, init_expr,
2002: expr::SaveIn(v)));
librustc/middle/trans/tvec.rs:
373: Ignore => {
374: return expr::trans_into(bcx, element, Ignore);
375: }
librustc/middle/trans/controlflow.rs:
154: Some(elexpr) => {
155: bcx = expr::trans_into(bcx, elexpr, dest);
156: debuginfo::clear_source_location(bcx.fcx);
--
328: Some(x) => {
329: bcx = expr::trans_into(bcx, x, dest);
330: }
librustc/middle/trans/expr.rs:82:16-82:16 -enum- definition:
pub enum Dest {
SaveIn(ValueRef),
Ignore,
references:- 27645: expr: &ast::Expr,
646: dest: Dest)
647: -> &'a Block<'a> {
--
1441: rhs: Option<(Datum<Expr>, ast::NodeId)>,
1442: dest: Option<Dest>)
1443: -> Result<'a> {
librustc/middle/trans/_match.rs:
1826: arms: &[ast::Arm],
1827: dest: Dest)
1828: -> &'a Block<'a> {
--
1876: arms: &[ast::Arm],
1877: dest: Dest) -> &'a Block<'a> {
1878: let _icx = push_ctxt("match::trans_match_inner");
librustc/middle/trans/closure.rs:
317: id: ast::NodeId,
318: dest: expr::Dest)
319: -> &'a Block<'a> {
librustc/middle/trans/tvec.rs:
118: content_expr: &ast::Expr,
119: dest: expr::Dest)
120: -> &'a Block<'a> {
--
308: content_expr: &ast::Expr,
309: dest: Dest)
310: -> &'a Block<'a> {
librustc/middle/trans/meth.rs:
526: id: ast::NodeId,
527: dest: expr::Dest)
528: -> &'a Block<'a> {
librustc/middle/trans/controlflow.rs:
86: b: &ast::Block,
87: mut dest: expr::Dest)
88: -> &'a Block<'a> {
--
124: els: Option<@ast::Expr>,
125: dest: expr::Dest)
126: -> &'a Block<'a> {
librustc/middle/trans/datum.rs:
408: bcx: &'a Block<'a>,
409: dest: expr::Dest,
410: expr_id: ast::NodeId)
--
673: pub fn store_to_dest(self,
674: dest: expr::Dest,
675: expr_id: ast::NodeId) -> &'a Block<'a> {
librustc/middle/trans/callee.rs:
477: args: CallArgs,
478: dest: expr::Dest)
479: -> &'a Block<'a> {
--
498: args: &[ValueRef],
499: dest: Option<expr::Dest>)
500: -> Result<'a> {
--
527: args: CallArgs,
528: dest: Option<expr::Dest>)
529: -> Result<'a> {
librustc/middle/trans/expr.rs:
83: pub enum Dest {
librustc/middle/trans/expr.rs:1495:16-1495:16 -enum- definition:
pub enum cast_kind {
cast_pointer,
cast_integral,
references:- 41496: pub enum cast_kind {
--
1504: pub fn cast_type_kind(t: ty::t) -> cast_kind {
1505: match ty::get(t).sty {
librustc/middle/trans/expr.rs:569:1-569:1 -fn- definition:
fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr)
-> &'a Block<'a> {
references:- 2333: ty::RvalueStmtExpr => {
334: bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
335: nil(bcx, expr_ty(bcx, expr))
librustc/middle/trans/expr.rs:1192:1-1192:1 -fn- definition:
fn trans_managed_expr<'a>(bcx: &'a Block<'a>,
box_ty: ty::t,
contents: &ast::Expr,
references:- 21232: let contents_datum = unpack_datum!(bcx, trans_managed_expr(bcx,
1233: box_ty,
librustc/middle/trans/expr.rs:135:1-135:1 -fn- definition:
pub fn trans<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr)
-> DatumBlock<'a, Expr> {
references:- 30librustc/middle/trans/_match.rs:
librustc/middle/trans/tvec.rs:
librustc/middle/trans/meth.rs:
librustc/middle/trans/asm.rs:
librustc/middle/trans/controlflow.rs:
librustc/middle/trans/callee.rs:
librustc/middle/trans/expr.rs:1457:1-1457:1 -fn- definition:
fn int_cast(bcx: &Block,
lldsttype: Type,
llsrctype: Type,
references:- 21583: match k_out {
1584: cast_integral => int_cast(bcx, ll_t_out,
1585: val_ty(lldiscrim_a),
librustc/middle/trans/expr.rs:288:1-288:1 -fn- definition:
pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
name: &str)
references:- 9461: let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
--
1075: // And, would it ever be reasonable to be here with discr != 0?
1076: let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base.expr, "base"));
1077: for &(i, t) in base.fields.iter() {
--
1218: let mut bcx = bcx;
1219: let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
1220: let ty = expr_ty(bcx, expr);
--
1617: // Evaluate LHS (destination), which should be an lvalue
1618: let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
1619: assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
librustc/middle/trans/_match.rs:
2009: let init_datum =
2010: unpack_datum!(bcx, expr::trans_to_lvalue(bcx, init_expr, "let"));
2011: if ty::type_is_bot(expr_ty(bcx, init_expr)) {
librustc/middle/trans/controlflow.rs:
78: if ty::type_needs_drop(cx.tcx(), ty) {
79: expr::trans_to_lvalue(cx, e, "stmt").bcx
80: } else {
librustc/middle/trans/expr.rs:
439: let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
440: let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
librustc/middle/trans/expr.rs:1017:4-1017:4 -struct- definition:
*/
struct StructBaseInfo {
/// The base expression; will be evaluated after all explicit fields.
references:- 2993: }
994: Some(StructBaseInfo {expr: base_expr,
995: fields: leftovers })
--
1038: fields: &[(uint, @ast::Expr)],
1039: optbase: Option<StructBaseInfo>,
1040: dest: Dest)
librustc/middle/trans/expr.rs:1250:22-1250:22 -fn- definition:
// and the other not.
fn trans_eager_binop<'a>(
bcx: &'a Block<'a>,
references:- 21429: let rhs = rhs_datum.to_llscalarish(bcx);
1430: trans_eager_binop(bcx, expr, binop_ty, op,
1431: lhs_ty, lhs, rhs_ty, rhs)
--
1629: let result_datum = unpack_datum!(
1630: bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
1631: dst_ty, dst, rhs_ty, rhs));
librustc/middle/trans/expr.rs:643:1-643:1 -fn- definition:
fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
dest: Dest)
references:- 3340: if type_is_zero_size(bcx.ccx(), ty) {
341: bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
342: nil(bcx, ty)
--
344: let scratch = rvalue_scratch_datum(bcx, ty, "");
345: bcx = trans_rvalue_dps_unadjusted(
346: bcx, expr, SaveIn(scratch.val));
librustc/middle/trans/expr.rs:1634:1-1634:1 -fn- definition:
fn auto_ref<'a>(bcx: &'a Block<'a>,
datum: Datum<Expr>,
expr: &ast::Expr)
references:- 31703: // Always perform an AutoPtr when applying an overloaded auto-deref.
1704: unpack_datum!(bcx, auto_ref(bcx, datum, expr))
1705: };
librustc/middle/trans/expr.rs:884:4-884:4 -fn- definition:
fn take_local<'a>(bcx: &'a Block<'a>,
table: &NodeMap<Datum<Lvalue>>,
nid: ast::NodeId)
references:- 2875: ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
876: take_local(bcx, &*bcx.fcx.lllocals.borrow(), nid)
877: }
librustc/middle/trans/expr.rs:849:1-849:1 -fn- definition:
pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
def: ast::Def)
-> Datum<Lvalue> {
references:- 2librustc/middle/trans/closure.rs:
241: for freevar in freevars.iter() {
242: let datum = expr::trans_local_var(bcx, freevar.def);
243: env_vals.push(EnvValue {action: freevar_mode, datum: datum});
librustc/middle/trans/expr.rs:
564: _ => {
565: DatumBlock(bcx, trans_local_var(bcx, def).to_expr_datum())
566: }
librustc/middle/trans/expr.rs:1671:1-1671:1 -fn- definition:
fn deref_once<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>,
references:- 21666: for i in range(1, times+1) {
1667: datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
1668: }
librustc/middle/trans/expr.rs:365:4-365:4 -fn- definition:
fn nil<'a>(bcx: &'a Block<'a>, ty: ty::t) -> DatumBlock<'a, Expr> {
let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
let datum = immediate_rvalue(llval, ty);
references:- 2334: bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
335: nil(bcx, expr_ty(bcx, expr))
336: }
--
341: bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
342: nil(bcx, ty)
343: } else {
librustc/middle/trans/expr.rs:1503:1-1503:1 -fn- definition:
pub fn cast_type_kind(t: ty::t) -> cast_kind {
match ty::get(t).sty {
ty::ty_char => cast_integral,
references:- 51531: let t_out = node_id_type(bcx, id);
1532: let k_in = cast_type_kind(t_in);
1533: let k_out = cast_type_kind(t_out);
1534: let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
librustc/middle/trans/consts.rs:
471: let (v, inlineable) = const_expr(cx, base, is_local);
472: return (match (expr::cast_type_kind(basety),
473: expr::cast_type_kind(ety)) {
--
497: let iv = C_integral(cx.int_type, discr, false);
498: let ety_cast = expr::cast_type_kind(ety);
499: match ety_cast {