]>
Commit | Line | Data |
---|---|---|
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 | ||
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. | |
13 | ||
14 | pub use self::Expr::*; | |
15 | pub use self::RvalueMode::*; | |
16 | ||
17 | use llvm::ValueRef; | |
18 | use trans::base::*; | |
19 | use trans::build::Load; | |
20 | use trans::common::*; | |
21 | use trans::cleanup; | |
22 | use trans::cleanup::CleanupMethods; | |
23 | use trans::expr; | |
24 | use trans::tvec; | |
25 | use trans::type_of; | |
26 | use middle::ty::{self, Ty}; | |
27 | use util::ppaux::{ty_to_string}; | |
28 | ||
29 | use std::fmt; | |
30 | use syntax::ast; | |
31 | use syntax::codemap::DUMMY_SP; | |
32 | ||
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. | |
37 | #[derive(Clone, Copy)] | |
38 | pub struct Datum<'tcx, K> { | |
39 | /// The llvm value. This is either a pointer to the Rust value or | |
40 | /// the value itself, depending on `kind` below. | |
41 | pub val: ValueRef, | |
42 | ||
43 | /// The rust type of the value. | |
44 | pub ty: Ty<'tcx>, | |
45 | ||
46 | /// Indicates whether this is by-ref or by-value. | |
47 | pub kind: K, | |
48 | } | |
49 | ||
50 | pub struct DatumBlock<'blk, 'tcx: 'blk, K> { | |
51 | pub bcx: Block<'blk, 'tcx>, | |
52 | pub datum: Datum<'tcx, K>, | |
53 | } | |
54 | ||
55 | #[derive(Show)] | |
56 | pub enum Expr { | |
57 | /// a fresh value that was produced and which has no cleanup yet | |
58 | /// because it has not yet "landed" into its permanent home | |
59 | RvalueExpr(Rvalue), | |
60 | ||
61 | /// `val` is a pointer into memory for which a cleanup is scheduled | |
62 | /// (and thus has type *T). If you move out of an Lvalue, you must | |
63 | /// zero out the memory (FIXME #5016). | |
64 | LvalueExpr, | |
65 | } | |
66 | ||
67 | #[derive(Clone, Copy, Show)] | |
68 | pub struct Lvalue; | |
69 | ||
70 | #[derive(Show)] | |
71 | pub struct Rvalue { | |
72 | pub mode: RvalueMode | |
73 | } | |
74 | ||
75 | impl Rvalue { | |
76 | pub fn new(m: RvalueMode) -> Rvalue { | |
77 | Rvalue { mode: m } | |
78 | } | |
79 | } | |
80 | ||
81 | // Make Datum linear for more type safety. | |
82 | impl Drop for Rvalue { | |
83 | fn drop(&mut self) { } | |
84 | } | |
85 | ||
86 | #[derive(Copy, PartialEq, Eq, Hash, Show)] | |
87 | pub enum RvalueMode { | |
88 | /// `val` is a pointer to the actual value (and thus has type *T) | |
89 | ByRef, | |
90 | ||
91 | /// `val` is the actual value (*only used for immediates* like ints, ptrs) | |
92 | ByValue, | |
93 | } | |
94 | ||
95 | pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> { | |
96 | return Datum::new(val, ty, Rvalue::new(ByValue)); | |
97 | } | |
98 | ||
99 | pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
100 | val: ValueRef, | |
101 | ty: Ty<'tcx>) | |
102 | -> DatumBlock<'blk, 'tcx, Rvalue> { | |
103 | return DatumBlock::new(bcx, immediate_rvalue(val, ty)) | |
104 | } | |
105 | ||
106 | ||
107 | /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to | |
108 | /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should | |
109 | /// initialize the memory. If `zero` is true, the space will be zeroed when it is allocated; this | |
110 | /// is not necessary unless `bcx` does not dominate the end of `scope`. | |
111 | pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, | |
112 | ty: Ty<'tcx>, | |
113 | name: &str, | |
114 | zero: bool, | |
115 | scope: cleanup::ScopeId, | |
116 | arg: A, | |
117 | populate: F) | |
118 | -> DatumBlock<'blk, 'tcx, Lvalue> where | |
119 | F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>, | |
120 | { | |
121 | let scratch = if zero { | |
122 | alloca_zeroed(bcx, ty, name) | |
123 | } else { | |
124 | let llty = type_of::type_of(bcx.ccx(), ty); | |
125 | alloca(bcx, llty, name) | |
126 | }; | |
127 | ||
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); | |
132 | ||
133 | DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue)) | |
134 | } | |
135 | ||
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>, | |
142 | ty: Ty<'tcx>, | |
143 | name: &str) | |
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)) | |
148 | } | |
149 | ||
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) { | |
155 | ByValue | |
156 | } else { | |
157 | ByRef | |
158 | } | |
159 | } | |
160 | ||
161 | fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode, | |
162 | fcx: &FunctionContext<'a, 'tcx>, | |
163 | scope: cleanup::ScopeId, | |
164 | val: ValueRef, | |
165 | ty: Ty<'tcx>) { | |
166 | match mode { | |
167 | ByValue => { fcx.schedule_drop_immediate(scope, val, ty); } | |
168 | ByRef => { | |
169 | fcx.schedule_lifetime_end(scope, val); | |
170 | fcx.schedule_drop_mem(scope, val, ty); | |
171 | } | |
172 | } | |
173 | } | |
174 | ||
175 | pub trait KindOps { | |
176 | ||
177 | /// Take appropriate action after the value in `datum` has been | |
178 | /// stored to a new location. | |
179 | fn post_store<'blk, 'tcx>(&self, | |
180 | bcx: Block<'blk, 'tcx>, | |
181 | val: ValueRef, | |
182 | ty: Ty<'tcx>) | |
183 | -> Block<'blk, 'tcx>; | |
184 | ||
185 | /// True if this mode is a reference mode, meaning that the datum's | |
186 | /// val field is a pointer to the actual value | |
187 | fn is_by_ref(&self) -> bool; | |
188 | ||
189 | /// Converts to an Expr kind | |
190 | fn to_expr_kind(self) -> Expr; | |
191 | ||
192 | } | |
193 | ||
194 | impl KindOps for Rvalue { | |
195 | fn post_store<'blk, 'tcx>(&self, | |
196 | bcx: Block<'blk, 'tcx>, | |
197 | _val: ValueRef, | |
198 | _ty: Ty<'tcx>) | |
199 | -> Block<'blk, 'tcx> { | |
200 | // No cleanup is scheduled for an rvalue, so we don't have | |
201 | // to do anything after a move to cancel or duplicate it. | |
202 | bcx | |
203 | } | |
204 | ||
205 | fn is_by_ref(&self) -> bool { | |
206 | self.mode == ByRef | |
207 | } | |
208 | ||
209 | fn to_expr_kind(self) -> Expr { | |
210 | RvalueExpr(self) | |
211 | } | |
212 | } | |
213 | ||
214 | impl KindOps for Lvalue { | |
215 | /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel | |
216 | /// cleanup. If an @T lvalue is copied, we must increment the reference count. | |
217 | fn post_store<'blk, 'tcx>(&self, | |
218 | bcx: Block<'blk, 'tcx>, | |
219 | val: ValueRef, | |
220 | ty: Ty<'tcx>) | |
221 | -> Block<'blk, 'tcx> { | |
222 | if type_needs_drop(bcx.tcx(), ty) { | |
223 | // cancel cleanup of affine values by zeroing out | |
224 | let () = zero_mem(bcx, val, ty); | |
225 | bcx | |
226 | } else { | |
227 | bcx | |
228 | } | |
229 | } | |
230 | ||
231 | fn is_by_ref(&self) -> bool { | |
232 | true | |
233 | } | |
234 | ||
235 | fn to_expr_kind(self) -> Expr { | |
236 | LvalueExpr | |
237 | } | |
238 | } | |
239 | ||
240 | impl KindOps for Expr { | |
241 | fn post_store<'blk, 'tcx>(&self, | |
242 | bcx: Block<'blk, 'tcx>, | |
243 | val: ValueRef, | |
244 | ty: Ty<'tcx>) | |
245 | -> Block<'blk, 'tcx> { | |
246 | match *self { | |
247 | LvalueExpr => Lvalue.post_store(bcx, val, ty), | |
248 | RvalueExpr(ref r) => r.post_store(bcx, val, ty), | |
249 | } | |
250 | } | |
251 | ||
252 | fn is_by_ref(&self) -> bool { | |
253 | match *self { | |
254 | LvalueExpr => Lvalue.is_by_ref(), | |
255 | RvalueExpr(ref r) => r.is_by_ref() | |
256 | } | |
257 | } | |
258 | ||
259 | fn to_expr_kind(self) -> Expr { | |
260 | self | |
261 | } | |
262 | } | |
263 | ||
264 | impl<'tcx> Datum<'tcx, Rvalue> { | |
265 | /// Schedules a cleanup for this datum in the given scope. That means that this datum is no | |
266 | /// longer an rvalue datum; hence, this function consumes the datum and returns the contained | |
267 | /// ValueRef. | |
268 | pub fn add_clean<'a>(self, | |
269 | fcx: &FunctionContext<'a, 'tcx>, | |
270 | scope: cleanup::ScopeId) | |
271 | -> ValueRef { | |
272 | add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty); | |
273 | self.val | |
274 | } | |
275 | ||
276 | /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not | |
277 | /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`. | |
278 | pub fn to_lvalue_datum_in_scope<'blk>(self, | |
279 | bcx: Block<'blk, 'tcx>, | |
280 | name: &str, | |
281 | scope: cleanup::ScopeId) | |
282 | -> DatumBlock<'blk, 'tcx, Lvalue> { | |
283 | let fcx = bcx.fcx; | |
284 | ||
285 | match self.kind.mode { | |
286 | ByRef => { | |
287 | add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty); | |
288 | DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue)) | |
289 | } | |
290 | ||
291 | ByValue => { | |
292 | lvalue_scratch_datum( | |
293 | bcx, self.ty, name, false, scope, self, | |
294 | |this, bcx, llval| this.store_to(bcx, llval)) | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
299 | pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>) | |
300 | -> DatumBlock<'blk, 'tcx, Rvalue> { | |
301 | let mut bcx = bcx; | |
302 | match self.kind.mode { | |
303 | ByRef => DatumBlock::new(bcx, self), | |
304 | ByValue => { | |
305 | let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref"); | |
306 | bcx = self.store_to(bcx, scratch.val); | |
307 | DatumBlock::new(bcx, scratch) | |
308 | } | |
309 | } | |
310 | } | |
311 | ||
312 | pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>) | |
313 | -> DatumBlock<'blk, 'tcx, Rvalue> { | |
314 | match self.appropriate_rvalue_mode(bcx.ccx()) { | |
315 | ByRef => { | |
316 | self.to_ref_datum(bcx) | |
317 | } | |
318 | ByValue => { | |
319 | match self.kind.mode { | |
320 | ByValue => DatumBlock::new(bcx, self), | |
321 | ByRef => { | |
322 | let llval = load_ty(bcx, self.val, self.ty); | |
323 | DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue))) | |
324 | } | |
325 | } | |
326 | } | |
327 | } | |
328 | } | |
329 | } | |
330 | ||
331 | /// Methods suitable for "expr" datums that could be either lvalues or | |
332 | /// rvalues. These include coercions into lvalues/rvalues but also a number | |
333 | /// of more general operations. (Some of those operations could be moved to | |
334 | /// the more general `impl<K> Datum<K>`, but it's convenient to have them | |
335 | /// here since we can `match self.kind` rather than having to implement | |
336 | /// generic methods in `KindOps`.) | |
337 | impl<'tcx> Datum<'tcx, Expr> { | |
338 | fn match_kind<R, F, G>(self, if_lvalue: F, if_rvalue: G) -> R where | |
339 | F: FnOnce(Datum<'tcx, Lvalue>) -> R, | |
340 | G: FnOnce(Datum<'tcx, Rvalue>) -> R, | |
341 | { | |
342 | let Datum { val, ty, kind } = self; | |
343 | match kind { | |
344 | LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)), | |
345 | RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)), | |
346 | } | |
347 | } | |
348 | ||
349 | /// Asserts that this datum *is* an lvalue and returns it. | |
350 | #[allow(dead_code)] // potentially useful | |
351 | pub fn assert_lvalue(self, bcx: Block) -> Datum<'tcx, Lvalue> { | |
352 | self.match_kind( | |
353 | |d| d, | |
354 | |_| bcx.sess().bug("assert_lvalue given rvalue")) | |
355 | } | |
356 | ||
357 | pub fn store_to_dest<'blk>(self, | |
358 | bcx: Block<'blk, 'tcx>, | |
359 | dest: expr::Dest, | |
360 | expr_id: ast::NodeId) | |
361 | -> Block<'blk, 'tcx> { | |
362 | match dest { | |
363 | expr::Ignore => { | |
364 | self.add_clean_if_rvalue(bcx, expr_id); | |
365 | bcx | |
366 | } | |
367 | expr::SaveIn(addr) => { | |
368 | self.store_to(bcx, addr) | |
369 | } | |
370 | } | |
371 | } | |
372 | ||
373 | /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value | |
374 | /// that may need drop. | |
375 | pub fn add_clean_if_rvalue<'blk>(self, | |
376 | bcx: Block<'blk, 'tcx>, | |
377 | expr_id: ast::NodeId) { | |
378 | self.match_kind( | |
379 | |_| { /* Nothing to do, cleanup already arranged */ }, | |
380 | |r| { | |
381 | let scope = cleanup::temporary_scope(bcx.tcx(), expr_id); | |
382 | r.add_clean(bcx.fcx, scope); | |
383 | }) | |
384 | } | |
385 | ||
386 | /// Ensures that `self` will get cleaned up, if it is not an lvalue already. | |
387 | pub fn clean<'blk>(self, | |
388 | bcx: Block<'blk, 'tcx>, | |
389 | name: &'static str, | |
390 | expr_id: ast::NodeId) | |
391 | -> Block<'blk, 'tcx> { | |
392 | self.to_lvalue_datum(bcx, name, expr_id).bcx | |
393 | } | |
394 | ||
395 | pub fn to_lvalue_datum<'blk>(self, | |
396 | bcx: Block<'blk, 'tcx>, | |
397 | name: &str, | |
398 | expr_id: ast::NodeId) | |
399 | -> DatumBlock<'blk, 'tcx, Lvalue> { | |
400 | debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx())); | |
401 | ||
402 | assert!(lltype_is_sized(bcx.tcx(), self.ty), | |
403 | "Trying to convert unsized value to lval"); | |
404 | self.match_kind( | |
405 | |l| DatumBlock::new(bcx, l), | |
406 | |r| { | |
407 | let scope = cleanup::temporary_scope(bcx.tcx(), expr_id); | |
408 | r.to_lvalue_datum_in_scope(bcx, name, scope) | |
409 | }) | |
410 | } | |
411 | ||
412 | /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled). | |
413 | pub fn to_rvalue_datum<'blk>(self, | |
414 | bcx: Block<'blk, 'tcx>, | |
415 | name: &'static str) | |
416 | -> DatumBlock<'blk, 'tcx, Rvalue> { | |
417 | self.match_kind( | |
418 | |l| { | |
419 | let mut bcx = bcx; | |
420 | match l.appropriate_rvalue_mode(bcx.ccx()) { | |
421 | ByRef => { | |
422 | let scratch = rvalue_scratch_datum(bcx, l.ty, name); | |
423 | bcx = l.store_to(bcx, scratch.val); | |
424 | DatumBlock::new(bcx, scratch) | |
425 | } | |
426 | ByValue => { | |
427 | let v = load_ty(bcx, l.val, l.ty); | |
428 | bcx = l.kind.post_store(bcx, l.val, l.ty); | |
429 | DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue))) | |
430 | } | |
431 | } | |
432 | }, | |
433 | |r| DatumBlock::new(bcx, r)) | |
434 | } | |
435 | ||
436 | } | |
437 | ||
438 | /// Methods suitable only for lvalues. These include the various | |
439 | /// operations to extract components out of compound data structures, | |
440 | /// such as extracting the field from a struct or a particular element | |
441 | /// from an array. | |
442 | impl<'tcx> Datum<'tcx, Lvalue> { | |
443 | /// Converts a datum into a by-ref value. The datum type must be one which is always passed by | |
444 | /// reference. | |
445 | pub fn to_llref(self) -> ValueRef { | |
446 | self.val | |
447 | } | |
448 | ||
449 | // Extracts a component of a compound data structure (e.g., a field from a | |
450 | // struct). Note that if self is an opened, unsized type then the returned | |
451 | // datum may also be unsized _without the size information_. It is the | |
452 | // callers responsibility to package the result in some way to make a valid | |
453 | // datum in that case (e.g., by making a fat pointer or opened pair). | |
454 | pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>, | |
455 | gep: F) | |
456 | -> Datum<'tcx, Lvalue> where | |
457 | F: FnOnce(ValueRef) -> ValueRef, | |
458 | { | |
459 | let val = match self.ty.sty { | |
460 | _ if type_is_sized(bcx.tcx(), self.ty) => gep(self.val), | |
461 | ty::ty_open(_) => { | |
462 | let base = Load(bcx, expr::get_dataptr(bcx, self.val)); | |
463 | gep(base) | |
464 | } | |
465 | _ => bcx.tcx().sess.bug( | |
466 | &format!("Unexpected unsized type in get_element: {}", | |
467 | bcx.ty_to_string(self.ty))[]) | |
468 | }; | |
469 | Datum { | |
470 | val: val, | |
471 | kind: Lvalue, | |
472 | ty: ty, | |
473 | } | |
474 | } | |
475 | ||
476 | pub fn get_vec_base_and_len(&self, bcx: Block) -> (ValueRef, ValueRef) { | |
477 | //! Converts a vector into the slice pair. | |
478 | ||
479 | tvec::get_base_and_len(bcx, self.val, self.ty) | |
480 | } | |
481 | } | |
482 | ||
483 | /// Generic methods applicable to any sort of datum. | |
484 | impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { | |
485 | pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> { | |
486 | Datum { val: val, ty: ty, kind: kind } | |
487 | } | |
488 | ||
489 | pub fn to_expr_datum(self) -> Datum<'tcx, Expr> { | |
490 | let Datum { val, ty, kind } = self; | |
491 | Datum { val: val, ty: ty, kind: kind.to_expr_kind() } | |
492 | } | |
493 | ||
494 | /// Moves or copies this value into a new home, as appropriate depending on the type of the | |
495 | /// datum. This method consumes the datum, since it would be incorrect to go on using the datum | |
496 | /// if the value represented is affine (and hence the value is moved). | |
497 | pub fn store_to<'blk>(self, | |
498 | bcx: Block<'blk, 'tcx>, | |
499 | dst: ValueRef) | |
500 | -> Block<'blk, 'tcx> { | |
501 | self.shallow_copy_raw(bcx, dst); | |
502 | ||
503 | self.kind.post_store(bcx, self.val, self.ty) | |
504 | } | |
505 | ||
506 | /// Helper function that performs a shallow copy of this value into `dst`, which should be a | |
507 | /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized | |
508 | /// memory (either newly allocated, zeroed, or dropped). | |
509 | /// | |
510 | /// This function is private to datums because it leaves memory in an unstable state, where the | |
511 | /// source value has been copied but not zeroed. Public methods are `store_to` (if you no | |
512 | /// longer need the source value) or `shallow_copy` (if you wish the source value to remain | |
513 | /// valid). | |
514 | fn shallow_copy_raw<'blk>(&self, | |
515 | bcx: Block<'blk, 'tcx>, | |
516 | dst: ValueRef) | |
517 | -> Block<'blk, 'tcx> { | |
518 | let _icx = push_ctxt("copy_to_no_check"); | |
519 | ||
520 | if type_is_zero_size(bcx.ccx(), self.ty) { | |
521 | return bcx; | |
522 | } | |
523 | ||
524 | if self.kind.is_by_ref() { | |
525 | memcpy_ty(bcx, dst, self.val, self.ty); | |
526 | } else { | |
527 | store_ty(bcx, self.val, dst, self.ty); | |
528 | } | |
529 | ||
530 | return bcx; | |
531 | } | |
532 | ||
533 | /// Copies the value into a new location. This function always preserves the existing datum as | |
534 | /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine | |
535 | /// values (since they must never be duplicated). | |
536 | pub fn shallow_copy<'blk>(&self, | |
537 | bcx: Block<'blk, 'tcx>, | |
538 | dst: ValueRef) | |
539 | -> Block<'blk, 'tcx> { | |
540 | /*! | |
541 | * Copies the value into a new location. This function always | |
542 | * preserves the existing datum as a valid value. Therefore, | |
543 | * it does not consume `self` and, also, cannot be applied to | |
544 | * affine values (since they must never be duplicated). | |
545 | */ | |
546 | ||
547 | assert!(!ty::type_moves_by_default(&ty::empty_parameter_environment(bcx.tcx()), | |
548 | DUMMY_SP, | |
549 | self.ty)); | |
550 | self.shallow_copy_raw(bcx, dst) | |
551 | } | |
552 | ||
553 | #[allow(dead_code)] // useful for debugging | |
554 | pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String { | |
555 | format!("Datum({}, {}, {:?})", | |
556 | ccx.tn().val_to_string(self.val), | |
557 | ty_to_string(ccx.tcx(), self.ty), | |
558 | self.kind) | |
559 | } | |
560 | ||
561 | /// See the `appropriate_rvalue_mode()` function | |
562 | pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>) | |
563 | -> RvalueMode { | |
564 | appropriate_rvalue_mode(ccx, self.ty) | |
565 | } | |
566 | ||
567 | /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of | |
568 | /// responsibility to cleanup the value). For this to work, the value must be something | |
569 | /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is | |
570 | /// naturally passed around by value, and not by reference. | |
571 | pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { | |
572 | assert!(!type_needs_drop(bcx.tcx(), self.ty)); | |
573 | assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue); | |
574 | if self.kind.is_by_ref() { | |
575 | load_ty(bcx, self.val, self.ty) | |
576 | } else { | |
577 | self.val | |
578 | } | |
579 | } | |
580 | ||
581 | pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { | |
582 | assert!(ty::type_is_bool(self.ty)); | |
583 | self.to_llscalarish(bcx) | |
584 | } | |
585 | } | |
586 | ||
587 | impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> { | |
588 | pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>) | |
589 | -> DatumBlock<'blk, 'tcx, K> { | |
590 | DatumBlock { bcx: bcx, datum: datum } | |
591 | } | |
592 | } | |
593 | ||
594 | impl<'blk, 'tcx, K: KindOps + fmt::Show> DatumBlock<'blk, 'tcx, K> { | |
595 | pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> { | |
596 | DatumBlock::new(self.bcx, self.datum.to_expr_datum()) | |
597 | } | |
598 | } | |
599 | ||
600 | impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> { | |
601 | pub fn store_to_dest(self, | |
602 | dest: expr::Dest, | |
603 | expr_id: ast::NodeId) -> Block<'blk, 'tcx> { | |
604 | let DatumBlock { bcx, datum } = self; | |
605 | datum.store_to_dest(bcx, dest, expr_id) | |
606 | } | |
607 | ||
608 | pub fn to_llbool(self) -> Result<'blk, 'tcx> { | |
609 | let DatumBlock { datum, bcx } = self; | |
610 | Result::new(bcx, datum.to_llbool(bcx)) | |
611 | } | |
612 | } |