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.
11 //! See the section on datums in `doc.rs` for an overview of what Datums are and how they are
12 //! intended to be used.
14 pub use self::Expr::*;
15 pub use self::RvalueMode::*;
19 use trans::build::Load;
22 use trans::cleanup::CleanupMethods;
26 use middle::ty::{mod, Ty};
27 use util::ppaux::{ty_to_string};
33 * A `Datum` encapsulates the result of evaluating an expression. It
34 * describes where the value is stored, what Rust type the value has,
35 * whether it is addressed by reference, and so forth. Please refer
36 * the section on datums in `doc.rs` for more details.
39 pub struct Datum<'tcx, K> {
40 /// The llvm value. This is either a pointer to the Rust value or
41 /// the value itself, depending on `kind` below.
44 /// The rust type of the value.
47 /// Indicates whether this is by-ref or by-value.
51 pub struct DatumBlock<'blk, 'tcx: 'blk, K> {
52 pub bcx: Block<'blk, 'tcx>,
53 pub datum: Datum<'tcx, K>,
58 /// a fresh value that was produced and which has no cleanup yet
59 /// because it has not yet "landed" into its permanent home
62 /// `val` is a pointer into memory for which a cleanup is scheduled
63 /// (and thus has type *T). If you move out of an Lvalue, you must
64 /// zero out the memory (FIXME #5016).
68 #[deriving(Clone, Show)]
77 pub fn new(m: RvalueMode) -> Rvalue {
82 // Make Datum linear for more type safety.
83 impl Drop for Rvalue {
84 fn drop(&mut self) { }
87 #[deriving(PartialEq, Eq, Hash, Show)]
89 /// `val` is a pointer to the actual value (and thus has type *T)
92 /// `val` is the actual value (*only used for immediates* like ints, ptrs)
96 pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> {
97 return Datum::new(val, ty, Rvalue::new(ByValue));
100 pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
103 -> DatumBlock<'blk, 'tcx, Rvalue> {
104 return DatumBlock::new(bcx, immediate_rvalue(val, ty))
108 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
109 /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
110 /// initialize the memory. If `zero` is true, the space will be zeroed when it is allocated; this
111 /// is not necessary unless `bcx` does not dominate the end of `scope`.
112 pub fn lvalue_scratch_datum<'blk, 'tcx, A>(bcx: Block<'blk, 'tcx>,
116 scope: cleanup::ScopeId,
118 populate: |A, Block<'blk, 'tcx>, ValueRef|
119 -> Block<'blk, 'tcx>)
120 -> DatumBlock<'blk, 'tcx, Lvalue> {
121 let scratch = if zero {
122 alloca_zeroed(bcx, ty, name)
124 let llty = type_of::type_of(bcx.ccx(), ty);
125 alloca(bcx, llty, name)
128 // Subtle. Populate the scratch memory *before* scheduling cleanup.
129 let bcx = populate(arg, bcx, scratch);
130 bcx.fcx.schedule_lifetime_end(scope, scratch);
131 bcx.fcx.schedule_drop_mem(scope, scratch, ty);
133 DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
136 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
137 /// it. If `zero` is true, the space will be zeroed when it is allocated; this is normally not
138 /// necessary, but in the case of automatic rooting in match statements it is possible to have
139 /// temporaries that may not get initialized if a certain arm is not taken, so we must zero them.
140 /// You must arrange any cleanups etc yourself!
141 pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
144 -> Datum<'tcx, Rvalue> {
145 let llty = type_of::type_of(bcx.ccx(), ty);
146 let scratch = alloca(bcx, llty, name);
147 Datum::new(scratch, ty, Rvalue::new(ByRef))
150 /// Indicates the "appropriate" mode for this value, which is either by ref or by value, depending
151 /// on whether type is immediate or not.
152 pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
153 ty: Ty<'tcx>) -> RvalueMode {
154 if type_is_immediate(ccx, ty) {
161 fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode,
162 fcx: &FunctionContext<'a, 'tcx>,
163 scope: cleanup::ScopeId,
167 ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
169 fcx.schedule_lifetime_end(scope, val);
170 fcx.schedule_drop_mem(scope, val, ty);
178 * Take appropriate action after the value in `datum` has been
179 * stored to a new location.
181 fn post_store<'blk, 'tcx>(&self,
182 bcx: Block<'blk, 'tcx>,
185 -> Block<'blk, 'tcx>;
188 * True if this mode is a reference mode, meaning that the datum's
189 * val field is a pointer to the actual value
191 fn is_by_ref(&self) -> bool;
194 * Converts to an Expr kind
196 fn to_expr_kind(self) -> Expr;
200 impl KindOps for Rvalue {
201 fn post_store<'blk, 'tcx>(&self,
202 bcx: Block<'blk, 'tcx>,
205 -> Block<'blk, 'tcx> {
206 // No cleanup is scheduled for an rvalue, so we don't have
207 // to do anything after a move to cancel or duplicate it.
211 fn is_by_ref(&self) -> bool {
215 fn to_expr_kind(self) -> Expr {
220 impl KindOps for Lvalue {
221 /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel
222 /// cleanup. If an @T lvalue is copied, we must increment the reference count.
223 fn post_store<'blk, 'tcx>(&self,
224 bcx: Block<'blk, 'tcx>,
227 -> Block<'blk, 'tcx> {
228 if ty::type_needs_drop(bcx.tcx(), ty) {
229 // cancel cleanup of affine values by zeroing out
230 let () = zero_mem(bcx, val, ty);
237 fn is_by_ref(&self) -> bool {
241 fn to_expr_kind(self) -> Expr {
246 impl KindOps for Expr {
247 fn post_store<'blk, 'tcx>(&self,
248 bcx: Block<'blk, 'tcx>,
251 -> Block<'blk, 'tcx> {
253 LvalueExpr => Lvalue.post_store(bcx, val, ty),
254 RvalueExpr(ref r) => r.post_store(bcx, val, ty),
258 fn is_by_ref(&self) -> bool {
260 LvalueExpr => Lvalue.is_by_ref(),
261 RvalueExpr(ref r) => r.is_by_ref()
265 fn to_expr_kind(self) -> Expr {
270 impl<'tcx> Datum<'tcx, Rvalue> {
271 /// Schedules a cleanup for this datum in the given scope. That means that this datum is no
272 /// longer an rvalue datum; hence, this function consumes the datum and returns the contained
274 pub fn add_clean<'a>(self,
275 fcx: &FunctionContext<'a, 'tcx>,
276 scope: cleanup::ScopeId)
278 add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty);
282 /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not
283 /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`.
284 pub fn to_lvalue_datum_in_scope<'blk>(self,
285 bcx: Block<'blk, 'tcx>,
287 scope: cleanup::ScopeId)
288 -> DatumBlock<'blk, 'tcx, Lvalue> {
291 match self.kind.mode {
293 add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
294 DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue))
298 lvalue_scratch_datum(
299 bcx, self.ty, name, false, scope, self,
300 |this, bcx, llval| this.store_to(bcx, llval))
305 pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
306 -> DatumBlock<'blk, 'tcx, Rvalue> {
308 match self.kind.mode {
309 ByRef => DatumBlock::new(bcx, self),
311 let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref");
312 bcx = self.store_to(bcx, scratch.val);
313 DatumBlock::new(bcx, scratch)
318 pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
319 -> DatumBlock<'blk, 'tcx, Rvalue> {
320 match self.appropriate_rvalue_mode(bcx.ccx()) {
322 self.to_ref_datum(bcx)
325 match self.kind.mode {
326 ByValue => DatumBlock::new(bcx, self),
328 let llval = load_ty(bcx, self.val, self.ty);
329 DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue)))
338 * Methods suitable for "expr" datums that could be either lvalues or
339 * rvalues. These include coercions into lvalues/rvalues but also a number
340 * of more general operations. (Some of those operations could be moved to
341 * the more general `impl<K> Datum<K>`, but it's convenient to have them
342 * here since we can `match self.kind` rather than having to implement
343 * generic methods in `KindOps`.)
345 impl<'tcx> Datum<'tcx, Expr> {
346 fn match_kind<R>(self,
347 if_lvalue: |Datum<'tcx, Lvalue>| -> R,
348 if_rvalue: |Datum<'tcx, Rvalue>| -> R)
350 let Datum { val, ty, kind } = self;
352 LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)),
353 RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
357 /// Asserts that this datum *is* an lvalue and returns it.
358 #[allow(dead_code)] // potentially useful
359 pub fn assert_lvalue(self, bcx: Block) -> Datum<'tcx, Lvalue> {
362 |_| bcx.sess().bug("assert_lvalue given rvalue"))
365 /// Asserts that this datum *is* an lvalue and returns it.
366 pub fn assert_rvalue(self, bcx: Block) -> Datum<'tcx, Rvalue> {
368 |_| bcx.sess().bug("assert_rvalue given lvalue"),
372 pub fn store_to_dest<'blk>(self,
373 bcx: Block<'blk, 'tcx>,
375 expr_id: ast::NodeId)
376 -> Block<'blk, 'tcx> {
379 self.add_clean_if_rvalue(bcx, expr_id);
382 expr::SaveIn(addr) => {
383 self.store_to(bcx, addr)
388 /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value
389 /// that may need drop.
390 pub fn add_clean_if_rvalue<'blk>(self,
391 bcx: Block<'blk, 'tcx>,
392 expr_id: ast::NodeId) {
394 |_| { /* Nothing to do, cleanup already arranged */ },
396 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
397 r.add_clean(bcx.fcx, scope);
401 /// Ensures that `self` will get cleaned up, if it is not an lvalue already.
402 pub fn clean<'blk>(self,
403 bcx: Block<'blk, 'tcx>,
405 expr_id: ast::NodeId)
406 -> Block<'blk, 'tcx> {
407 self.to_lvalue_datum(bcx, name, expr_id).bcx
410 pub fn to_lvalue_datum<'blk>(self,
411 bcx: Block<'blk, 'tcx>,
413 expr_id: ast::NodeId)
414 -> DatumBlock<'blk, 'tcx, Lvalue> {
415 debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
417 assert!(ty::lltype_is_sized(bcx.tcx(), self.ty),
418 "Trying to convert unsized value to lval");
420 |l| DatumBlock::new(bcx, l),
422 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
423 r.to_lvalue_datum_in_scope(bcx, name, scope)
427 /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled).
428 pub fn to_rvalue_datum<'blk>(self,
429 bcx: Block<'blk, 'tcx>,
431 -> DatumBlock<'blk, 'tcx, Rvalue> {
435 match l.appropriate_rvalue_mode(bcx.ccx()) {
437 let scratch = rvalue_scratch_datum(bcx, l.ty, name);
438 bcx = l.store_to(bcx, scratch.val);
439 DatumBlock::new(bcx, scratch)
442 let v = load_ty(bcx, l.val, l.ty);
443 bcx = l.kind.post_store(bcx, l.val, l.ty);
444 DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue)))
448 |r| DatumBlock::new(bcx, r))
454 * Methods suitable only for lvalues. These include the various
455 * operations to extract components out of compound data structures,
456 * such as extracting the field from a struct or a particular element
459 impl<'tcx> Datum<'tcx, Lvalue> {
460 /// Converts a datum into a by-ref value. The datum type must be one which is always passed by
462 pub fn to_llref(self) -> ValueRef {
466 // Extracts a component of a compound data structure (e.g., a field from a
467 // struct). Note that if self is an opened, unsized type then the returned
468 // datum may also be unsized _without the size information_. It is the
469 // callers responsibility to package the result in some way to make a valid
470 // datum in that case (e.g., by making a fat pointer or opened pair).
471 pub fn get_element<'blk>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>,
472 gep: |ValueRef| -> ValueRef)
473 -> Datum<'tcx, Lvalue> {
474 let val = match self.ty.sty {
475 _ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
477 let base = Load(bcx, expr::get_dataptr(bcx, self.val));
480 _ => bcx.tcx().sess.bug(
481 format!("Unexpected unsized type in get_element: {}",
482 bcx.ty_to_string(self.ty)).as_slice())
491 pub fn get_vec_base_and_len(&self, bcx: Block) -> (ValueRef, ValueRef) {
492 //! Converts a vector into the slice pair.
494 tvec::get_base_and_len(bcx, self.val, self.ty)
499 * Generic methods applicable to any sort of datum.
501 impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
502 pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> {
503 Datum { val: val, ty: ty, kind: kind }
506 pub fn to_expr_datum(self) -> Datum<'tcx, Expr> {
507 let Datum { val, ty, kind } = self;
508 Datum { val: val, ty: ty, kind: kind.to_expr_kind() }
511 /// Moves or copies this value into a new home, as appropriate depending on the type of the
512 /// datum. This method consumes the datum, since it would be incorrect to go on using the datum
513 /// if the value represented is affine (and hence the value is moved).
514 pub fn store_to<'blk>(self,
515 bcx: Block<'blk, 'tcx>,
517 -> Block<'blk, 'tcx> {
518 self.shallow_copy_raw(bcx, dst);
520 self.kind.post_store(bcx, self.val, self.ty)
523 /// Helper function that performs a shallow copy of this value into `dst`, which should be a
524 /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized
525 /// memory (either newly allocated, zeroed, or dropped).
527 /// This function is private to datums because it leaves memory in an unstable state, where the
528 /// source value has been copied but not zeroed. Public methods are `store_to` (if you no
529 /// longer need the source value) or `shallow_copy` (if you wish the source value to remain
531 fn shallow_copy_raw<'blk>(&self,
532 bcx: Block<'blk, 'tcx>,
534 -> Block<'blk, 'tcx> {
535 let _icx = push_ctxt("copy_to_no_check");
537 if type_is_zero_size(bcx.ccx(), self.ty) {
541 if self.kind.is_by_ref() {
542 memcpy_ty(bcx, dst, self.val, self.ty);
544 store_ty(bcx, self.val, dst, self.ty);
550 /// Copies the value into a new location. This function always preserves the existing datum as
551 /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine
552 /// values (since they must never be duplicated).
553 pub fn shallow_copy<'blk>(&self,
554 bcx: Block<'blk, 'tcx>,
556 -> Block<'blk, 'tcx> {
557 assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty));
558 self.shallow_copy_raw(bcx, dst)
561 #[allow(dead_code)] // useful for debugging
562 pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
563 format!("Datum({}, {}, {})",
564 ccx.tn().val_to_string(self.val),
565 ty_to_string(ccx.tcx(), self.ty),
569 //! See the `appropriate_rvalue_mode()` function
570 pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>)
572 appropriate_rvalue_mode(ccx, self.ty)
575 /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of
576 /// responsibility to cleanup the value). For this to work, the value must be something
577 /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
578 /// naturally passed around by value, and not by reference.
579 pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
580 assert!(!ty::type_needs_drop(bcx.tcx(), self.ty));
581 assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
582 if self.kind.is_by_ref() {
583 load_ty(bcx, self.val, self.ty)
589 pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
590 assert!(ty::type_is_bool(self.ty))
591 self.to_llscalarish(bcx)
595 impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> {
596 pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>)
597 -> DatumBlock<'blk, 'tcx, K> {
598 DatumBlock { bcx: bcx, datum: datum }
602 impl<'blk, 'tcx, K: KindOps + fmt::Show> DatumBlock<'blk, 'tcx, K> {
603 pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> {
604 DatumBlock::new(self.bcx, self.datum.to_expr_datum())
608 impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> {
609 pub fn store_to_dest(self,
611 expr_id: ast::NodeId) -> Block<'blk, 'tcx> {
612 let DatumBlock { bcx, datum } = self;
613 datum.store_to_dest(bcx, dest, expr_id)
616 pub fn to_llbool(self) -> Result<'blk, 'tcx> {
617 let DatumBlock { datum, bcx } = self;
618 Result::new(bcx, datum.to_llbool(bcx))