]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/datum.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / trans / datum.rs
CommitLineData
1a4d82fc
JJ
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
85aaf69f
SL
11//! ## The Datum module
12//!
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".
18//!
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
22//! scheduled:
23//!
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>`
27//!
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.
34//!
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
40//! a datum value.
41//!
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.
50//!
51//! ### Lvalues in detail
52//!
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).
58//!
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.
64//!
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]`.
68//!
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.
76//!
85aaf69f
SL
77//! ### Rvalues in detail
78//!
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.
83//!
84//! ### Scratch datums
85//!
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.
1a4d82fc
JJ
91
92pub use self::Expr::*;
93pub use self::RvalueMode::*;
94
95use llvm::ValueRef;
c1a9b12d 96use trans::adt;
1a4d82fc 97use trans::base::*;
c1a9b12d 98use trans::build::{Load, Store};
1a4d82fc
JJ
99use trans::common::*;
100use trans::cleanup;
c1a9b12d 101use trans::cleanup::{CleanupMethods, DropHintDatum, DropHintMethods};
1a4d82fc
JJ
102use trans::expr;
103use trans::tvec;
c1a9b12d 104use middle::ty::Ty;
1a4d82fc
JJ
105
106use std::fmt;
107use syntax::ast;
108use syntax::codemap::DUMMY_SP;
109
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
c34b1796 113/// the section on datums in `README.md` for more details.
c1a9b12d 114#[derive(Clone, Copy, Debug)]
1a4d82fc
JJ
115pub 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.
118 pub val: ValueRef,
119
120 /// The rust type of the value.
121 pub ty: Ty<'tcx>,
122
123 /// Indicates whether this is by-ref or by-value.
124 pub kind: K,
125}
126
127pub struct DatumBlock<'blk, 'tcx: 'blk, K> {
128 pub bcx: Block<'blk, 'tcx>,
129 pub datum: Datum<'tcx, K>,
130}
131
85aaf69f 132#[derive(Debug)]
1a4d82fc
JJ
133pub enum Expr {
134 /// a fresh value that was produced and which has no cleanup yet
135 /// because it has not yet "landed" into its permanent home
136 RvalueExpr(Rvalue),
137
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).
c1a9b12d 141 LvalueExpr(Lvalue),
1a4d82fc
JJ
142}
143
c1a9b12d
SL
144#[derive(Copy, Clone, PartialEq, Eq, Debug)]
145pub enum DropFlagInfo {
146 DontZeroJustUse(ast::NodeId),
147 ZeroAndMaintain(ast::NodeId),
148 None,
149}
150
151impl DropFlagInfo {
152 pub fn must_zero(&self) -> bool {
153 match *self {
154 DropFlagInfo::DontZeroJustUse(..) => false,
155 DropFlagInfo::ZeroAndMaintain(..) => true,
156 DropFlagInfo::None => true,
157 }
158 }
159
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,
166 };
167
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);
171 retval
172 }
173}
174
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)]
181pub struct Lvalue {
182 pub source: &'static str,
183 pub drop_flag_info: DropFlagInfo
184}
1a4d82fc 185
85aaf69f 186#[derive(Debug)]
1a4d82fc
JJ
187pub struct Rvalue {
188 pub mode: RvalueMode
189}
190
c1a9b12d
SL
191/// Classifies what action we should take when a value is moved away
192/// with respect to its drop-flag.
193///
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)]
198pub enum HintKind {
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".
203 ZeroAndMaintain,
204
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.
212 DontZeroJustUse,
213}
214
215impl 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 }
219 }
220
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 }
224 }
225
226 pub fn new_with_hint<'blk, 'tcx>(source: &'static str,
227 bcx: Block<'blk, 'tcx>,
228 id: ast::NodeId,
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();
233 let info = match k {
234 HintKind::ZeroAndMaintain if hint_available =>
235 DropFlagInfo::ZeroAndMaintain(id),
236 HintKind::DontZeroJustUse if hint_available =>
237 DropFlagInfo::DontZeroJustUse(id),
238 _ =>
239 DropFlagInfo::None,
240 };
241 (Some(id), info)
242 };
243 debug!("Lvalue at {}, id: {:?} info: {:?}", source, opt_id, info);
244 Lvalue { source: source, drop_flag_info: info }
245 }
246} // end Lvalue constructor methods.
247
248impl Lvalue {
249 fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
250 id: ast::NodeId) -> bool {
251 let hints = bcx.fcx.lldropflag_hints.borrow();
252 hints.has_hint(id)
253 }
254 pub fn dropflag_hint<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>)
255 -> Option<DropHintDatum<'tcx>> {
256 self.drop_flag_info.hint_datum(bcx)
257 }
258}
259
1a4d82fc
JJ
260impl Rvalue {
261 pub fn new(m: RvalueMode) -> Rvalue {
262 Rvalue { mode: m }
263 }
264}
265
266// Make Datum linear for more type safety.
267impl Drop for Rvalue {
268 fn drop(&mut self) { }
269}
270
c34b1796 271#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1a4d82fc
JJ
272pub enum RvalueMode {
273 /// `val` is a pointer to the actual value (and thus has type *T)
274 ByRef,
275
276 /// `val` is the actual value (*only used for immediates* like ints, ptrs)
277 ByValue,
278}
279
280pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> {
281 return Datum::new(val, ty, Rvalue::new(ByValue));
282}
283
284pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
285 val: ValueRef,
286 ty: Ty<'tcx>)
287 -> DatumBlock<'blk, 'tcx, Rvalue> {
288 return DatumBlock::new(bcx, immediate_rvalue(val, ty))
289}
290
1a4d82fc
JJ
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
c34b1796 293/// initialize the memory.
9cc50fc6
SL
294///
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.
1a4d82fc
JJ
301pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
302 ty: Ty<'tcx>,
303 name: &str,
9cc50fc6 304 zero: InitAlloca,
1a4d82fc
JJ
305 scope: cleanup::ScopeId,
306 arg: A,
307 populate: F)
308 -> DatumBlock<'blk, 'tcx, Lvalue> where
309 F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
310{
9cc50fc6
SL
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);
1a4d82fc
JJ
316
317 // Subtle. Populate the scratch memory *before* scheduling cleanup.
318 let bcx = populate(arg, bcx, scratch);
c1a9b12d 319 bcx.fcx.schedule_drop_mem(scope, scratch, ty, None);
1a4d82fc 320
c1a9b12d 321 DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
1a4d82fc
JJ
322}
323
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!
329pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
330 ty: Ty<'tcx>,
331 name: &str)
332 -> Datum<'tcx, Rvalue> {
e9174d1e
SL
333 let scratch = alloc_ty(bcx, ty, name);
334 call_lifetime_start(bcx, scratch);
1a4d82fc
JJ
335 Datum::new(scratch, ty, Rvalue::new(ByRef))
336}
337
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.
340pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
341 ty: Ty<'tcx>) -> RvalueMode {
342 if type_is_immediate(ccx, ty) {
343 ByValue
344 } else {
345 ByRef
346 }
347}
348
349fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode,
350 fcx: &FunctionContext<'a, 'tcx>,
351 scope: cleanup::ScopeId,
352 val: ValueRef,
353 ty: Ty<'tcx>) {
9cc50fc6
SL
354 debug!("add_rvalue_clean scope={:?} val={} ty={:?}",
355 scope, fcx.ccx.tn().val_to_string(val), ty);
1a4d82fc
JJ
356 match mode {
357 ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
358 ByRef => {
359 fcx.schedule_lifetime_end(scope, val);
c1a9b12d 360 fcx.schedule_drop_mem(scope, val, ty, None);
1a4d82fc
JJ
361 }
362 }
363}
364
365pub trait KindOps {
366
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>,
371 val: ValueRef,
372 ty: Ty<'tcx>)
373 -> Block<'blk, 'tcx>;
374
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;
378
379 /// Converts to an Expr kind
380 fn to_expr_kind(self) -> Expr;
381
382}
383
384impl KindOps for Rvalue {
385 fn post_store<'blk, 'tcx>(&self,
386 bcx: Block<'blk, 'tcx>,
387 _val: ValueRef,
388 _ty: Ty<'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.
85aaf69f
SL
392 if self.is_by_ref() {
393 call_lifetime_end(bcx, _val);
394 }
1a4d82fc
JJ
395 bcx
396 }
397
398 fn is_by_ref(&self) -> bool {
399 self.mode == ByRef
400 }
401
402 fn to_expr_kind(self) -> Expr {
403 RvalueExpr(self)
404 }
405}
406
407impl 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>,
412 val: ValueRef,
413 ty: Ty<'tcx>)
414 -> Block<'blk, 'tcx> {
c34b1796
AL
415 let _icx = push_ctxt("<Lvalue as KindOps>::post_store");
416 if bcx.fcx.type_needs_drop(ty) {
c1a9b12d
SL
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
420 // drop-glue itself.
421 if let Some(hint_datum) = self.drop_flag_info.hint_datum(bcx) {
e9174d1e 422 let moved_hint_byte = adt::DTOR_MOVED_HINT;
c1a9b12d
SL
423 let hint_llval = hint_datum.to_value().value();
424 Store(bcx, C_u8(bcx.fcx.ccx, moved_hint_byte), hint_llval);
425 }
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);
429 }
1a4d82fc
JJ
430 bcx
431 } else {
c1a9b12d
SL
432 // FIXME (#5016) would be nice to assert this, but we have
433 // to allow for e.g. DontZeroJustUse flags, for now.
434 //
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
440 // the code.)
441 //
442 // assert_eq!(self.drop_flag_info, DropFlagInfo::None);
1a4d82fc
JJ
443 bcx
444 }
445 }
446
447 fn is_by_ref(&self) -> bool {
448 true
449 }
450
451 fn to_expr_kind(self) -> Expr {
c1a9b12d 452 LvalueExpr(self)
1a4d82fc
JJ
453 }
454}
455
456impl KindOps for Expr {
457 fn post_store<'blk, 'tcx>(&self,
458 bcx: Block<'blk, 'tcx>,
459 val: ValueRef,
460 ty: Ty<'tcx>)
461 -> Block<'blk, 'tcx> {
462 match *self {
c1a9b12d 463 LvalueExpr(ref l) => l.post_store(bcx, val, ty),
1a4d82fc
JJ
464 RvalueExpr(ref r) => r.post_store(bcx, val, ty),
465 }
466 }
467
468 fn is_by_ref(&self) -> bool {
469 match *self {
c1a9b12d 470 LvalueExpr(ref l) => l.is_by_ref(),
1a4d82fc
JJ
471 RvalueExpr(ref r) => r.is_by_ref()
472 }
473 }
474
475 fn to_expr_kind(self) -> Expr {
476 self
477 }
478}
479
480impl<'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
483 /// ValueRef.
484 pub fn add_clean<'a>(self,
485 fcx: &FunctionContext<'a, 'tcx>,
486 scope: cleanup::ScopeId)
487 -> ValueRef {
488 add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty);
489 self.val
490 }
491
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>,
496 name: &str,
497 scope: cleanup::ScopeId)
498 -> DatumBlock<'blk, 'tcx, Lvalue> {
499 let fcx = bcx.fcx;
500
501 match self.kind.mode {
502 ByRef => {
503 add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
c1a9b12d
SL
504 DatumBlock::new(bcx, Datum::new(
505 self.val,
506 self.ty,
507 Lvalue::new("datum::to_lvalue_datum_in_scope")))
1a4d82fc
JJ
508 }
509
510 ByValue => {
511 lvalue_scratch_datum(
9cc50fc6 512 bcx, self.ty, name, InitAlloca::Dropped, scope, self,
e9174d1e 513 |this, bcx, llval| {
9cc50fc6
SL
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.
e9174d1e
SL
519 let bcx = this.store_to(bcx, llval);
520 bcx.fcx.schedule_lifetime_end(scope, llval);
521 bcx
522 })
1a4d82fc
JJ
523 }
524 }
525 }
526
527 pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
528 -> DatumBlock<'blk, 'tcx, Rvalue> {
529 let mut bcx = bcx;
530 match self.kind.mode {
531 ByRef => DatumBlock::new(bcx, self),
532 ByValue => {
533 let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref");
534 bcx = self.store_to(bcx, scratch.val);
535 DatumBlock::new(bcx, scratch)
536 }
537 }
538 }
539
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()) {
543 ByRef => {
544 self.to_ref_datum(bcx)
545 }
546 ByValue => {
547 match self.kind.mode {
548 ByValue => DatumBlock::new(bcx, self),
549 ByRef => {
550 let llval = load_ty(bcx, self.val, self.ty);
85aaf69f 551 call_lifetime_end(bcx, self.val);
1a4d82fc
JJ
552 DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue)))
553 }
554 }
555 }
556 }
557 }
558}
559
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`.)
566impl<'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,
570 {
571 let Datum { val, ty, kind } = self;
572 match kind {
c1a9b12d 573 LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)),
1a4d82fc
JJ
574 RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
575 }
576 }
577
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> {
581 self.match_kind(
582 |d| d,
583 |_| bcx.sess().bug("assert_lvalue given rvalue"))
584 }
585
586 pub fn store_to_dest<'blk>(self,
587 bcx: Block<'blk, 'tcx>,
588 dest: expr::Dest,
589 expr_id: ast::NodeId)
590 -> Block<'blk, 'tcx> {
591 match dest {
592 expr::Ignore => {
593 self.add_clean_if_rvalue(bcx, expr_id);
594 bcx
595 }
596 expr::SaveIn(addr) => {
597 self.store_to(bcx, addr)
598 }
599 }
600 }
601
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) {
607 self.match_kind(
608 |_| { /* Nothing to do, cleanup already arranged */ },
609 |r| {
610 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
611 r.add_clean(bcx.fcx, scope);
612 })
613 }
614
1a4d82fc
JJ
615 pub fn to_lvalue_datum<'blk>(self,
616 bcx: Block<'blk, 'tcx>,
617 name: &str,
618 expr_id: ast::NodeId)
619 -> DatumBlock<'blk, 'tcx, Lvalue> {
620 debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
621
1a4d82fc
JJ
622 self.match_kind(
623 |l| DatumBlock::new(bcx, l),
624 |r| {
625 let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
626 r.to_lvalue_datum_in_scope(bcx, name, scope)
627 })
628 }
629
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>,
633 name: &'static str)
634 -> DatumBlock<'blk, 'tcx, Rvalue> {
635 self.match_kind(
636 |l| {
637 let mut bcx = bcx;
638 match l.appropriate_rvalue_mode(bcx.ccx()) {
639 ByRef => {
640 let scratch = rvalue_scratch_datum(bcx, l.ty, name);
641 bcx = l.store_to(bcx, scratch.val);
642 DatumBlock::new(bcx, scratch)
643 }
644 ByValue => {
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)))
648 }
649 }
650 },
651 |r| DatumBlock::new(bcx, r))
652 }
653
654}
655
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
659/// from an array.
660impl<'tcx> Datum<'tcx, Lvalue> {
661 /// Converts a datum into a by-ref value. The datum type must be one which is always passed by
662 /// reference.
663 pub fn to_llref(self) -> ValueRef {
664 self.val
665 }
666
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>,
673 gep: F)
674 -> Datum<'tcx, Lvalue> where
92a42be0 675 F: FnOnce(adt::MaybeSizedValue) -> ValueRef,
1a4d82fc 676 {
c34b1796 677 let val = if type_is_sized(bcx.tcx(), self.ty) {
92a42be0
SL
678 let val = adt::MaybeSizedValue::sized(self.val);
679 gep(val)
c34b1796 680 } else {
92a42be0
SL
681 let val = adt::MaybeSizedValue::unsized_(
682 Load(bcx, expr::get_dataptr(bcx, self.val)),
683 Load(bcx, expr::get_meta(bcx, self.val)));
684 gep(val)
1a4d82fc
JJ
685 };
686 Datum {
687 val: val,
c1a9b12d 688 kind: Lvalue::new("Datum::get_element"),
1a4d82fc
JJ
689 ty: ty,
690 }
691 }
692
c34b1796
AL
693 pub fn get_vec_base_and_len<'blk>(&self, bcx: Block<'blk, 'tcx>)
694 -> (ValueRef, ValueRef) {
1a4d82fc
JJ
695 //! Converts a vector into the slice pair.
696
697 tvec::get_base_and_len(bcx, self.val, self.ty)
698 }
699}
700
701/// Generic methods applicable to any sort of datum.
85aaf69f 702impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> {
1a4d82fc
JJ
703 pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> {
704 Datum { val: val, ty: ty, kind: kind }
705 }
706
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() }
710 }
711
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>,
717 dst: ValueRef)
718 -> Block<'blk, 'tcx> {
719 self.shallow_copy_raw(bcx, dst);
720
721 self.kind.post_store(bcx, self.val, self.ty)
722 }
723
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).
727 ///
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
731 /// valid).
732 fn shallow_copy_raw<'blk>(&self,
733 bcx: Block<'blk, 'tcx>,
734 dst: ValueRef)
735 -> Block<'blk, 'tcx> {
736 let _icx = push_ctxt("copy_to_no_check");
737
738 if type_is_zero_size(bcx.ccx(), self.ty) {
739 return bcx;
740 }
741
742 if self.kind.is_by_ref() {
743 memcpy_ty(bcx, dst, self.val, self.ty);
744 } else {
745 store_ty(bcx, self.val, dst, self.ty);
746 }
747
748 return bcx;
749 }
750
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>,
756 dst: ValueRef)
757 -> Block<'blk, 'tcx> {
758 /*!
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).
763 */
764
c1a9b12d
SL
765 assert!(!self.ty
766 .moves_by_default(&bcx.tcx().empty_parameter_environment(), DUMMY_SP));
1a4d82fc
JJ
767 self.shallow_copy_raw(bcx, dst)
768 }
769
770 #[allow(dead_code)] // useful for debugging
771 pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
62682a34 772 format!("Datum({}, {:?}, {:?})",
1a4d82fc 773 ccx.tn().val_to_string(self.val),
62682a34 774 self.ty,
1a4d82fc
JJ
775 self.kind)
776 }
777
778 /// See the `appropriate_rvalue_mode()` function
779 pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>)
780 -> RvalueMode {
781 appropriate_rvalue_mode(ccx, self.ty)
782 }
783
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 {
c34b1796 789 assert!(!bcx.fcx.type_needs_drop(self.ty));
1a4d82fc
JJ
790 assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
791 if self.kind.is_by_ref() {
792 load_ty(bcx, self.val, self.ty)
793 } else {
794 self.val
795 }
796 }
797
798 pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
c1a9b12d 799 assert!(self.ty.is_bool());
1a4d82fc
JJ
800 self.to_llscalarish(bcx)
801 }
802}
803
804impl<'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 }
808 }
809}
810
85aaf69f 811impl<'blk, 'tcx, K: KindOps + fmt::Debug> DatumBlock<'blk, 'tcx, K> {
1a4d82fc
JJ
812 pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> {
813 DatumBlock::new(self.bcx, self.datum.to_expr_datum())
814 }
815}
816
817impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> {
818 pub fn store_to_dest(self,
819 dest: expr::Dest,
820 expr_id: ast::NodeId) -> Block<'blk, 'tcx> {
821 let DatumBlock { bcx, datum } = self;
822 datum.store_to_dest(bcx, dest, expr_id)
823 }
824
825 pub fn to_llbool(self) -> Result<'blk, 'tcx> {
826 let DatumBlock { datum, bcx } = self;
827 Result::new(bcx, datum.to_llbool(bcx))
828 }
829}