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 //! ## The Datum module
13 //! A `Datum` encapsulates the result of evaluating a Rust expression. It
14 //! contains a `ValueRef` indicating the result, a `Ty` describing
15 //! the Rust type, but also a *kind*. The kind indicates whether the datum
16 //! has cleanup scheduled (lvalue) or not (rvalue) and -- in the case of
17 //! rvalues -- whether or not the value is "by ref" or "by value".
19 //! The datum API is designed to try and help you avoid memory errors like
20 //! forgetting to arrange cleanup or duplicating a value. The type of the
21 //! datum incorporates the kind, and thus reflects whether it has cleanup
24 //! - `Datum<Lvalue>` -- by ref, cleanup scheduled
25 //! - `Datum<Rvalue>` -- by value or by ref, no cleanup scheduled
26 //! - `Datum<Expr>` -- either `Datum<Lvalue>` or `Datum<Rvalue>`
28 //! Rvalue and expr datums are noncopyable, and most of the methods on
29 //! datums consume the datum itself (with some notable exceptions). This
30 //! reflects the fact that datums may represent affine values which ought
31 //! to be consumed exactly once, and if you were to try to (for example)
32 //! store an affine value multiple times, you would be duplicating it,
33 //! which would certainly be a bug.
35 //! Some of the datum methods, however, are designed to work only on
36 //! copyable values such as ints or pointers. Those methods may borrow the
37 //! datum (`&self`) rather than consume it, but they always include
38 //! assertions on the type of the value represented to check that this
39 //! makes sense. An example is `shallow_copy()`, which duplicates
42 //! Translating an expression always yields a `Datum<Expr>` result, but
43 //! the methods `to_[lr]value_datum()` can be used to coerce a
44 //! `Datum<Expr>` into a `Datum<Lvalue>` or `Datum<Rvalue>` as
45 //! needed. Coercing to an lvalue is fairly common, and generally occurs
46 //! whenever it is necessary to inspect a value and pull out its
47 //! subcomponents (for example, a match, or indexing expression). Coercing
48 //! to an rvalue is more unusual; it occurs when moving values from place
49 //! to place, such as in an assignment expression or parameter passing.
51 //! ### Lvalues in detail
53 //! An lvalue datum is one for which cleanup has been scheduled. Lvalue
54 //! datums are always located in memory, and thus the `ValueRef` for an
55 //! LLVM value is always a pointer to the actual Rust value. This means
56 //! that if the Datum has a Rust type of `int`, then the LLVM type of the
57 //! `ValueRef` will be `int*` (pointer to int).
59 //! Because lvalues already have cleanups scheduled, the memory must be
60 //! zeroed to prevent the cleanup from taking place (presuming that the
61 //! Rust type needs drop in the first place, otherwise it doesn't
62 //! matter). The Datum code automatically performs this zeroing when the
63 //! value is stored to a new location, for example.
65 //! Lvalues usually result from evaluating lvalue expressions. For
66 //! example, evaluating a local variable `x` yields an lvalue, as does a
67 //! reference to a field like `x.f` or an index `x[i]`.
69 //! Lvalue datums can also arise by *converting* an rvalue into an lvalue.
70 //! This is done with the `to_lvalue_datum` method defined on
71 //! `Datum<Expr>`. Basically this method just schedules cleanup if the
72 //! datum is an rvalue, possibly storing the value into a stack slot first
73 //! if needed. Converting rvalues into lvalues occurs in constructs like
74 //! `&foo()` or `match foo() { ref x => ... }`, where the user is
75 //! implicitly requesting a temporary.
77 //! ### Rvalues in detail
79 //! Rvalues datums are values with no cleanup scheduled. One must be
80 //! careful with rvalue datums to ensure that cleanup is properly
81 //! arranged, usually by converting to an lvalue datum or by invoking the
82 //! `add_clean` method.
84 //! ### Scratch datums
86 //! Sometimes you need some temporary scratch space. The functions
87 //! `[lr]value_scratch_datum()` can be used to get temporary stack
88 //! space. As their name suggests, they yield lvalues and rvalues
89 //! respectively. That is, the slot from `lvalue_scratch_datum` will have
90 //! cleanup arranged, and the slot from `rvalue_scratch_datum` does not.
92 pub use self::Expr
::*;
93 pub use self::RvalueMode
::*;
98 use trans
::build
::{Load, Store}
;
101 use trans
::cleanup
::{CleanupMethods, DropHintDatum, DropHintMethods}
;
108 use syntax
::codemap
::DUMMY_SP
;
110 /// A `Datum` encapsulates the result of evaluating an expression. It
111 /// describes where the value is stored, what Rust type the value has,
112 /// whether it is addressed by reference, and so forth. Please refer
113 /// the section on datums in `README.md` for more details.
114 #[derive(Clone, Copy, Debug)]
115 pub struct Datum
<'tcx
, K
> {
116 /// The llvm value. This is either a pointer to the Rust value or
117 /// the value itself, depending on `kind` below.
120 /// The rust type of the value.
123 /// Indicates whether this is by-ref or by-value.
127 pub struct DatumBlock
<'blk
, 'tcx
: 'blk
, K
> {
128 pub bcx
: Block
<'blk
, 'tcx
>,
129 pub datum
: Datum
<'tcx
, K
>,
134 /// a fresh value that was produced and which has no cleanup yet
135 /// because it has not yet "landed" into its permanent home
138 /// `val` is a pointer into memory for which a cleanup is scheduled
139 /// (and thus has type *T). If you move out of an Lvalue, you must
140 /// zero out the memory (FIXME #5016).
144 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
145 pub enum DropFlagInfo
{
146 DontZeroJustUse(ast
::NodeId
),
147 ZeroAndMaintain(ast
::NodeId
),
152 pub fn must_zero(&self) -> bool
{
154 DropFlagInfo
::DontZeroJustUse(..) => false,
155 DropFlagInfo
::ZeroAndMaintain(..) => true,
156 DropFlagInfo
::None
=> true,
160 pub fn hint_datum
<'blk
, 'tcx
>(&self, bcx
: Block
<'blk
, 'tcx
>)
161 -> Option
<DropHintDatum
<'tcx
>> {
162 let id
= match *self {
163 DropFlagInfo
::None
=> return None
,
164 DropFlagInfo
::DontZeroJustUse(id
) |
165 DropFlagInfo
::ZeroAndMaintain(id
) => id
,
168 let hints
= bcx
.fcx
.lldropflag_hints
.borrow();
169 let retval
= hints
.hint_datum(id
);
170 assert
!(retval
.is_some(), "An id (={}) means must have a hint", id
);
175 // FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients
176 // may not realize that subparts of an Lvalue can have a subset of
177 // drop-flags associated with them, while this as written will just
178 // memcpy the drop_flag_info. But, it is an easier way to get `_match`
179 // off the ground to just let this be `Copy` for now.
180 #[derive(Copy, Clone, Debug)]
182 pub source
: &'
static str,
183 pub drop_flag_info
: DropFlagInfo
191 /// Classifies what action we should take when a value is moved away
192 /// with respect to its drop-flag.
194 /// Long term there will be no need for this classification: all flags
195 /// (which will be stored on the stack frame) will have the same
196 /// interpretation and maintenance code associated with them.
197 #[derive(Copy, Clone, Debug)]
199 /// When the value is moved, set the drop-flag to "dropped"
200 /// (i.e. "zero the flag", even when the specific representation
201 /// is not literally 0) and when it is reinitialized, set the
202 /// drop-flag back to "initialized".
205 /// When the value is moved, do not set the drop-flag to "dropped"
206 /// However, continue to read the drop-flag in deciding whether to
207 /// drop. (In essence, the path/fragment in question will never
208 /// need to be dropped at the points where it is moved away by
209 /// this code, but we are defending against the scenario where
210 /// some *other* code could move away (or drop) the value and thus
211 /// zero-the-flag, which is why we will still read from it.
215 impl Lvalue
{ // Constructors for various Lvalues.
216 pub fn new
<'blk
, 'tcx
>(source
: &'
static str) -> Lvalue
{
217 debug
!("Lvalue at {} no drop flag info", source
);
218 Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
221 pub fn new_dropflag_hint(source
: &'
static str) -> Lvalue
{
222 debug
!("Lvalue at {} is drop flag hint", source
);
223 Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
226 pub fn new_with_hint
<'blk
, 'tcx
>(source
: &'
static str,
227 bcx
: Block
<'blk
, 'tcx
>,
229 k
: HintKind
) -> Lvalue
{
230 let (opt_id
, info
) = {
231 let hint_available
= Lvalue
::has_dropflag_hint(bcx
, id
) &&
232 bcx
.tcx().sess
.nonzeroing_move_hints();
234 HintKind
::ZeroAndMaintain
if hint_available
=>
235 DropFlagInfo
::ZeroAndMaintain(id
),
236 HintKind
::DontZeroJustUse
if hint_available
=>
237 DropFlagInfo
::DontZeroJustUse(id
),
243 debug
!("Lvalue at {}, id: {:?} info: {:?}", source
, opt_id
, info
);
244 Lvalue { source: source, drop_flag_info: info }
246 } // end Lvalue constructor methods.
249 fn has_dropflag_hint
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
250 id
: ast
::NodeId
) -> bool
{
251 let hints
= bcx
.fcx
.lldropflag_hints
.borrow();
254 pub fn dropflag_hint
<'blk
, 'tcx
>(&self, bcx
: Block
<'blk
, 'tcx
>)
255 -> Option
<DropHintDatum
<'tcx
>> {
256 self.drop_flag_info
.hint_datum(bcx
)
261 pub fn new(m
: RvalueMode
) -> Rvalue
{
266 // Make Datum linear for more type safety.
267 impl Drop
for Rvalue
{
268 fn drop(&mut self) { }
271 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
272 pub enum RvalueMode
{
273 /// `val` is a pointer to the actual value (and thus has type *T)
276 /// `val` is the actual value (*only used for immediates* like ints, ptrs)
280 pub fn immediate_rvalue
<'tcx
>(val
: ValueRef
, ty
: Ty
<'tcx
>) -> Datum
<'tcx
, Rvalue
> {
281 return Datum
::new(val
, ty
, Rvalue
::new(ByValue
));
284 pub fn immediate_rvalue_bcx
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
287 -> DatumBlock
<'blk
, 'tcx
, Rvalue
> {
288 return DatumBlock
::new(bcx
, immediate_rvalue(val
, ty
))
291 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
292 /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
293 /// initialize the memory.
295 /// The flag `zero` indicates how the temporary space itself should be
296 /// initialized at the outset of the function; the only time that
297 /// `InitAlloca::Uninit` is a valid value for `zero` is when the
298 /// caller can prove that either (1.) the code injected by `populate`
299 /// onto `bcx` always dominates the end of `scope`, or (2.) the data
300 /// being allocated has no associated destructor.
301 pub fn lvalue_scratch_datum
<'blk
, 'tcx
, A
, F
>(bcx
: Block
<'blk
, 'tcx
>,
305 scope
: cleanup
::ScopeId
,
308 -> DatumBlock
<'blk
, 'tcx
, Lvalue
> where
309 F
: FnOnce(A
, Block
<'blk
, 'tcx
>, ValueRef
) -> Block
<'blk
, 'tcx
>,
311 // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed.
312 // (See discussion at Issue 30530.)
313 let scratch
= alloc_ty_init(bcx
, ty
, zero
, name
);
314 debug
!("lvalue_scratch_datum scope={:?} scratch={} ty={:?}",
315 scope
, bcx
.ccx().tn().val_to_string(scratch
), ty
);
317 // Subtle. Populate the scratch memory *before* scheduling cleanup.
318 let bcx
= populate(arg
, bcx
, scratch
);
319 bcx
.fcx
.schedule_drop_mem(scope
, scratch
, ty
, None
);
321 DatumBlock
::new(bcx
, Datum
::new(scratch
, ty
, Lvalue
::new("datum::lvalue_scratch_datum")))
324 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
325 /// it. If `zero` is true, the space will be zeroed when it is allocated; this is normally not
326 /// necessary, but in the case of automatic rooting in match statements it is possible to have
327 /// temporaries that may not get initialized if a certain arm is not taken, so we must zero them.
328 /// You must arrange any cleanups etc yourself!
329 pub fn rvalue_scratch_datum
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
332 -> Datum
<'tcx
, Rvalue
> {
333 let scratch
= alloc_ty(bcx
, ty
, name
);
334 call_lifetime_start(bcx
, scratch
);
335 Datum
::new(scratch
, ty
, Rvalue
::new(ByRef
))
338 /// Indicates the "appropriate" mode for this value, which is either by ref or by value, depending
339 /// on whether type is immediate or not.
340 pub fn appropriate_rvalue_mode
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
341 ty
: Ty
<'tcx
>) -> RvalueMode
{
342 if type_is_immediate(ccx
, ty
) {
349 fn add_rvalue_clean
<'a
, 'tcx
>(mode
: RvalueMode
,
350 fcx
: &FunctionContext
<'a
, 'tcx
>,
351 scope
: cleanup
::ScopeId
,
354 debug
!("add_rvalue_clean scope={:?} val={} ty={:?}",
355 scope
, fcx
.ccx
.tn().val_to_string(val
), ty
);
357 ByValue
=> { fcx.schedule_drop_immediate(scope, val, ty); }
359 fcx
.schedule_lifetime_end(scope
, val
);
360 fcx
.schedule_drop_mem(scope
, val
, ty
, None
);
367 /// Take appropriate action after the value in `datum` has been
368 /// stored to a new location.
369 fn post_store
<'blk
, 'tcx
>(&self,
370 bcx
: Block
<'blk
, 'tcx
>,
373 -> Block
<'blk
, 'tcx
>;
375 /// True if this mode is a reference mode, meaning that the datum's
376 /// val field is a pointer to the actual value
377 fn is_by_ref(&self) -> bool
;
379 /// Converts to an Expr kind
380 fn to_expr_kind(self) -> Expr
;
384 impl KindOps
for Rvalue
{
385 fn post_store
<'blk
, 'tcx
>(&self,
386 bcx
: Block
<'blk
, 'tcx
>,
389 -> Block
<'blk
, 'tcx
> {
390 // No cleanup is scheduled for an rvalue, so we don't have
391 // to do anything after a move to cancel or duplicate it.
392 if self.is_by_ref() {
393 call_lifetime_end(bcx
, _val
);
398 fn is_by_ref(&self) -> bool
{
402 fn to_expr_kind(self) -> Expr
{
407 impl KindOps
for Lvalue
{
408 /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel
409 /// cleanup. If an @T lvalue is copied, we must increment the reference count.
410 fn post_store
<'blk
, 'tcx
>(&self,
411 bcx
: Block
<'blk
, 'tcx
>,
414 -> Block
<'blk
, 'tcx
> {
415 let _icx
= push_ctxt("<Lvalue as KindOps>::post_store");
416 if bcx
.fcx
.type_needs_drop(ty
) {
417 // cancel cleanup of affine values:
418 // 1. if it has drop-hint, mark as moved; then code
419 // aware of drop-hint won't bother calling the
421 if let Some(hint_datum
) = self.drop_flag_info
.hint_datum(bcx
) {
422 let moved_hint_byte
= adt
::DTOR_MOVED_HINT
;
423 let hint_llval
= hint_datum
.to_value().value();
424 Store(bcx
, C_u8(bcx
.fcx
.ccx
, moved_hint_byte
), hint_llval
);
426 // 2. if the drop info says its necessary, drop-fill the memory.
427 if self.drop_flag_info
.must_zero() {
428 let () = drop_done_fill_mem(bcx
, val
, ty
);
432 // FIXME (#5016) would be nice to assert this, but we have
433 // to allow for e.g. DontZeroJustUse flags, for now.
435 // (The dropflag hint construction should be taking
436 // !type_needs_drop into account; earlier analysis phases
437 // may not have all the info they need to include such
438 // information properly, I think; in particular the
439 // fragments analysis works on a non-monomorphized view of
442 // assert_eq!(self.drop_flag_info, DropFlagInfo::None);
447 fn is_by_ref(&self) -> bool
{
451 fn to_expr_kind(self) -> Expr
{
456 impl KindOps
for Expr
{
457 fn post_store
<'blk
, 'tcx
>(&self,
458 bcx
: Block
<'blk
, 'tcx
>,
461 -> Block
<'blk
, 'tcx
> {
463 LvalueExpr(ref l
) => l
.post_store(bcx
, val
, ty
),
464 RvalueExpr(ref r
) => r
.post_store(bcx
, val
, ty
),
468 fn is_by_ref(&self) -> bool
{
470 LvalueExpr(ref l
) => l
.is_by_ref(),
471 RvalueExpr(ref r
) => r
.is_by_ref()
475 fn to_expr_kind(self) -> Expr
{
480 impl<'tcx
> Datum
<'tcx
, Rvalue
> {
481 /// Schedules a cleanup for this datum in the given scope. That means that this datum is no
482 /// longer an rvalue datum; hence, this function consumes the datum and returns the contained
484 pub fn add_clean
<'a
>(self,
485 fcx
: &FunctionContext
<'a
, 'tcx
>,
486 scope
: cleanup
::ScopeId
)
488 add_rvalue_clean(self.kind
.mode
, fcx
, scope
, self.val
, self.ty
);
492 /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not
493 /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`.
494 pub fn to_lvalue_datum_in_scope
<'blk
>(self,
495 bcx
: Block
<'blk
, 'tcx
>,
497 scope
: cleanup
::ScopeId
)
498 -> DatumBlock
<'blk
, 'tcx
, Lvalue
> {
501 match self.kind
.mode
{
503 add_rvalue_clean(ByRef
, fcx
, scope
, self.val
, self.ty
);
504 DatumBlock
::new(bcx
, Datum
::new(
507 Lvalue
::new("datum::to_lvalue_datum_in_scope")))
511 lvalue_scratch_datum(
512 bcx
, self.ty
, name
, InitAlloca
::Dropped
, scope
, self,
514 debug
!("populate call for Datum::to_lvalue_datum_in_scope \
515 self.ty={:?}", this
.ty
);
516 // do not call_lifetime_start here; the
517 // `InitAlloc::Dropped` will start scratch
518 // value's lifetime at open of function body.
519 let bcx
= this
.store_to(bcx
, llval
);
520 bcx
.fcx
.schedule_lifetime_end(scope
, llval
);
527 pub fn to_ref_datum
<'blk
>(self, bcx
: Block
<'blk
, 'tcx
>)
528 -> DatumBlock
<'blk
, 'tcx
, Rvalue
> {
530 match self.kind
.mode
{
531 ByRef
=> DatumBlock
::new(bcx
, self),
533 let scratch
= rvalue_scratch_datum(bcx
, self.ty
, "to_ref");
534 bcx
= self.store_to(bcx
, scratch
.val
);
535 DatumBlock
::new(bcx
, scratch
)
540 pub fn to_appropriate_datum
<'blk
>(self, bcx
: Block
<'blk
, 'tcx
>)
541 -> DatumBlock
<'blk
, 'tcx
, Rvalue
> {
542 match self.appropriate_rvalue_mode(bcx
.ccx()) {
544 self.to_ref_datum(bcx
)
547 match self.kind
.mode
{
548 ByValue
=> DatumBlock
::new(bcx
, self),
550 let llval
= load_ty(bcx
, self.val
, self.ty
);
551 call_lifetime_end(bcx
, self.val
);
552 DatumBlock
::new(bcx
, Datum
::new(llval
, self.ty
, Rvalue
::new(ByValue
)))
560 /// Methods suitable for "expr" datums that could be either lvalues or
561 /// rvalues. These include coercions into lvalues/rvalues but also a number
562 /// of more general operations. (Some of those operations could be moved to
563 /// the more general `impl<K> Datum<K>`, but it's convenient to have them
564 /// here since we can `match self.kind` rather than having to implement
565 /// generic methods in `KindOps`.)
566 impl<'tcx
> Datum
<'tcx
, Expr
> {
567 fn match_kind
<R
, F
, G
>(self, if_lvalue
: F
, if_rvalue
: G
) -> R
where
568 F
: FnOnce(Datum
<'tcx
, Lvalue
>) -> R
,
569 G
: FnOnce(Datum
<'tcx
, Rvalue
>) -> R
,
571 let Datum { val, ty, kind }
= self;
573 LvalueExpr(l
) => if_lvalue(Datum
::new(val
, ty
, l
)),
574 RvalueExpr(r
) => if_rvalue(Datum
::new(val
, ty
, r
)),
578 /// Asserts that this datum *is* an lvalue and returns it.
579 #[allow(dead_code)] // potentially useful
580 pub fn assert_lvalue(self, bcx
: Block
) -> Datum
<'tcx
, Lvalue
> {
583 |_
| bcx
.sess().bug("assert_lvalue given rvalue"))
586 pub fn store_to_dest
<'blk
>(self,
587 bcx
: Block
<'blk
, 'tcx
>,
589 expr_id
: ast
::NodeId
)
590 -> Block
<'blk
, 'tcx
> {
593 self.add_clean_if_rvalue(bcx
, expr_id
);
596 expr
::SaveIn(addr
) => {
597 self.store_to(bcx
, addr
)
602 /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value
603 /// that may need drop.
604 pub fn add_clean_if_rvalue
<'blk
>(self,
605 bcx
: Block
<'blk
, 'tcx
>,
606 expr_id
: ast
::NodeId
) {
608 |_
| { /* Nothing to do, cleanup already arranged */ }
,
610 let scope
= cleanup
::temporary_scope(bcx
.tcx(), expr_id
);
611 r
.add_clean(bcx
.fcx
, scope
);
615 pub fn to_lvalue_datum
<'blk
>(self,
616 bcx
: Block
<'blk
, 'tcx
>,
618 expr_id
: ast
::NodeId
)
619 -> DatumBlock
<'blk
, 'tcx
, Lvalue
> {
620 debug
!("to_lvalue_datum self: {}", self.to_string(bcx
.ccx()));
623 |l
| DatumBlock
::new(bcx
, l
),
625 let scope
= cleanup
::temporary_scope(bcx
.tcx(), expr_id
);
626 r
.to_lvalue_datum_in_scope(bcx
, name
, scope
)
630 /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled).
631 pub fn to_rvalue_datum
<'blk
>(self,
632 bcx
: Block
<'blk
, 'tcx
>,
634 -> DatumBlock
<'blk
, 'tcx
, Rvalue
> {
638 match l
.appropriate_rvalue_mode(bcx
.ccx()) {
640 let scratch
= rvalue_scratch_datum(bcx
, l
.ty
, name
);
641 bcx
= l
.store_to(bcx
, scratch
.val
);
642 DatumBlock
::new(bcx
, scratch
)
645 let v
= load_ty(bcx
, l
.val
, l
.ty
);
646 bcx
= l
.kind
.post_store(bcx
, l
.val
, l
.ty
);
647 DatumBlock
::new(bcx
, Datum
::new(v
, l
.ty
, Rvalue
::new(ByValue
)))
651 |r
| DatumBlock
::new(bcx
, r
))
656 /// Methods suitable only for lvalues. These include the various
657 /// operations to extract components out of compound data structures,
658 /// such as extracting the field from a struct or a particular element
660 impl<'tcx
> Datum
<'tcx
, Lvalue
> {
661 /// Converts a datum into a by-ref value. The datum type must be one which is always passed by
663 pub fn to_llref(self) -> ValueRef
{
667 // Extracts a component of a compound data structure (e.g., a field from a
668 // struct). Note that if self is an opened, unsized type then the returned
669 // datum may also be unsized _without the size information_. It is the
670 // callers responsibility to package the result in some way to make a valid
671 // datum in that case (e.g., by making a fat pointer or opened pair).
672 pub fn get_element
<'blk
, F
>(&self, bcx
: Block
<'blk
, 'tcx
>, ty
: Ty
<'tcx
>,
674 -> Datum
<'tcx
, Lvalue
> where
675 F
: FnOnce(adt
::MaybeSizedValue
) -> ValueRef
,
677 let val
= if type_is_sized(bcx
.tcx(), self.ty
) {
678 let val
= adt
::MaybeSizedValue
::sized(self.val
);
681 let val
= adt
::MaybeSizedValue
::unsized_(
682 Load(bcx
, expr
::get_dataptr(bcx
, self.val
)),
683 Load(bcx
, expr
::get_meta(bcx
, self.val
)));
688 kind
: Lvalue
::new("Datum::get_element"),
693 pub fn get_vec_base_and_len
<'blk
>(&self, bcx
: Block
<'blk
, 'tcx
>)
694 -> (ValueRef
, ValueRef
) {
695 //! Converts a vector into the slice pair.
697 tvec
::get_base_and_len(bcx
, self.val
, self.ty
)
701 /// Generic methods applicable to any sort of datum.
702 impl<'tcx
, K
: KindOps
+ fmt
::Debug
> Datum
<'tcx
, K
> {
703 pub fn new(val
: ValueRef
, ty
: Ty
<'tcx
>, kind
: K
) -> Datum
<'tcx
, K
> {
704 Datum { val: val, ty: ty, kind: kind }
707 pub fn to_expr_datum(self) -> Datum
<'tcx
, Expr
> {
708 let Datum { val, ty, kind }
= self;
709 Datum { val: val, ty: ty, kind: kind.to_expr_kind() }
712 /// Moves or copies this value into a new home, as appropriate depending on the type of the
713 /// datum. This method consumes the datum, since it would be incorrect to go on using the datum
714 /// if the value represented is affine (and hence the value is moved).
715 pub fn store_to
<'blk
>(self,
716 bcx
: Block
<'blk
, 'tcx
>,
718 -> Block
<'blk
, 'tcx
> {
719 self.shallow_copy_raw(bcx
, dst
);
721 self.kind
.post_store(bcx
, self.val
, self.ty
)
724 /// Helper function that performs a shallow copy of this value into `dst`, which should be a
725 /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized
726 /// memory (either newly allocated, zeroed, or dropped).
728 /// This function is private to datums because it leaves memory in an unstable state, where the
729 /// source value has been copied but not zeroed. Public methods are `store_to` (if you no
730 /// longer need the source value) or `shallow_copy` (if you wish the source value to remain
732 fn shallow_copy_raw
<'blk
>(&self,
733 bcx
: Block
<'blk
, 'tcx
>,
735 -> Block
<'blk
, 'tcx
> {
736 let _icx
= push_ctxt("copy_to_no_check");
738 if type_is_zero_size(bcx
.ccx(), self.ty
) {
742 if self.kind
.is_by_ref() {
743 memcpy_ty(bcx
, dst
, self.val
, self.ty
);
745 store_ty(bcx
, self.val
, dst
, self.ty
);
751 /// Copies the value into a new location. This function always preserves the existing datum as
752 /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine
753 /// values (since they must never be duplicated).
754 pub fn shallow_copy
<'blk
>(&self,
755 bcx
: Block
<'blk
, 'tcx
>,
757 -> Block
<'blk
, 'tcx
> {
759 * Copies the value into a new location. This function always
760 * preserves the existing datum as a valid value. Therefore,
761 * it does not consume `self` and, also, cannot be applied to
762 * affine values (since they must never be duplicated).
766 .moves_by_default(&bcx
.tcx().empty_parameter_environment(), DUMMY_SP
));
767 self.shallow_copy_raw(bcx
, dst
)
770 #[allow(dead_code)] // useful for debugging
771 pub fn to_string
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>) -> String
{
772 format
!("Datum({}, {:?}, {:?})",
773 ccx
.tn().val_to_string(self.val
),
778 /// See the `appropriate_rvalue_mode()` function
779 pub fn appropriate_rvalue_mode
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>)
781 appropriate_rvalue_mode(ccx
, self.ty
)
784 /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of
785 /// responsibility to cleanup the value). For this to work, the value must be something
786 /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
787 /// naturally passed around by value, and not by reference.
788 pub fn to_llscalarish
<'blk
>(self, bcx
: Block
<'blk
, 'tcx
>) -> ValueRef
{
789 assert
!(!bcx
.fcx
.type_needs_drop(self.ty
));
790 assert
!(self.appropriate_rvalue_mode(bcx
.ccx()) == ByValue
);
791 if self.kind
.is_by_ref() {
792 load_ty(bcx
, self.val
, self.ty
)
798 pub fn to_llbool
<'blk
>(self, bcx
: Block
<'blk
, 'tcx
>) -> ValueRef
{
799 assert
!(self.ty
.is_bool());
800 self.to_llscalarish(bcx
)
804 impl<'blk
, 'tcx
, K
> DatumBlock
<'blk
, 'tcx
, K
> {
805 pub fn new(bcx
: Block
<'blk
, 'tcx
>, datum
: Datum
<'tcx
, K
>)
806 -> DatumBlock
<'blk
, 'tcx
, K
> {
807 DatumBlock { bcx: bcx, datum: datum }
811 impl<'blk
, 'tcx
, K
: KindOps
+ fmt
::Debug
> DatumBlock
<'blk
, 'tcx
, K
> {
812 pub fn to_expr_datumblock(self) -> DatumBlock
<'blk
, 'tcx
, Expr
> {
813 DatumBlock
::new(self.bcx
, self.datum
.to_expr_datum())
817 impl<'blk
, 'tcx
> DatumBlock
<'blk
, 'tcx
, Expr
> {
818 pub fn store_to_dest(self,
820 expr_id
: ast
::NodeId
) -> Block
<'blk
, 'tcx
> {
821 let DatumBlock { bcx, datum }
= self;
822 datum
.store_to_dest(bcx
, dest
, expr_id
)
825 pub fn to_llbool(self) -> Result
<'blk
, 'tcx
> {
826 let DatumBlock { datum, bcx }
= self;
827 Result
::new(bcx
, datum
.to_llbool(bcx
))