]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/datum.rs
introduce `base_and_len` fns for element length
[rust.git] / src / librustc / middle / trans / datum.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  *
13  * A `Datum` contains all the information you need to describe the LLVM
14  * translation of a Rust value.  It describes where the value is stored,
15  * what Rust type the value has, whether it is addressed by reference,
16  * and so forth.
17  *
18  * The idea of a datum is that, to the extent possible, you should not
19  * care about these details, but rather use the methods on the Datum
20  * type to "do what you want to do".  For example, you can simply call
21  * `copy_to()` or `move_to()` to copy or move the value into a new
22  * home.
23  *
24  * # Datum location
25  *
26  * The primary two fields of a datum are the `val` and the `mode`.
27  * The `val` is an LLVM value ref.  It may either *be the value* that
28  * is being tracked, or it may be a *pointer to the value being
29  * tracked*.  This is specified in the `mode` field, which can either
30  * be `ByValue` or `ByRef`, respectively.  The (Rust) type of the
31  * value stored in the datum is indicated in the field `ty`.
32  *
33  * Generally speaking, you probably do not want to access the `val` field
34  * unless you know what mode the value is in.  Instead you should use one
35  * of the following accessors:
36  *
37  * - `to_value_llval()` converts to by-value
38  * - `to_ref_llval()` converts to by-ref, allocating a stack slot if necessary
39  * - `to_appropriate_llval()` converts to by-value if this is an
40  *   immediate type, by-ref otherwise.  This is particularly
41  *   convenient for interfacing with the various code floating around
42  *   that predates datums.
43  *
44  * # Datum cleanup styles
45  *
46  * Each datum carries with it an idea of how its value will be cleaned
47  * up.  This is primarily determined by the mode: a `ByValue` datum
48  * will always be cleaned up by revoking cleanup using
49  * `revoke_clean()`, because there is no other option. By ref datums
50  * can sometimes be cleaned up via `revoke_clean` (in particular,
51  * by-ref datums that originated from rvalues), but sometimes they
52  * must be zeroed. This is indicated by the `DatumCleanup`
53  * parameter. Note that zeroing a by-ref datum *always works* to
54  * cancel the cleanup, but using `revoke_clean` is preferable since
55  * there is no runtime cost. Some older parts of the code (notably
56  * `match_`, at least at the time of this writing) rely on this and
57  * only use zeroing.
58  *
59  * # Copying, moving, and storing
60  *
61  * There are three methods for moving the value into a new
62  * location:
63  *
64  * - `copy_to()` will copy the value into a new location, meaning that
65  *    the value is first mem-copied and then the new location is "taken"
66  *    via the take glue, in effect creating a deep clone.
67  *
68  * - `move_to()` will copy the value, meaning that the value is mem-copied
69  *   into its new home and then the cleanup on the this datum is revoked.
70  *   This is a "shallow" clone.  After `move_to()`, the current datum
71  *   is invalid and should no longer be used.
72  *
73  * - `store_to()` either performs a copy or a move depending on the
74  *   Rust type of the datum.
75  *
76  * # Scratch datum
77  *
78  * Sometimes you just need some temporary scratch space.  The
79  * `scratch_datum()` function will yield you up a by-ref datum that
80  * points into the stack.  It's your responsibility to ensure that
81  * whatever you put in there gets cleaned up etc.
82  *
83  * # Other actions
84  *
85  * There are various other helper methods on Datum, such as `deref()`,
86  * `get_base_and_len()` and so forth.  These are documented on the
87  * methods themselves.  Most are only suitable for some types of
88  * values. */
89
90
91 use lib;
92 use lib::llvm::ValueRef;
93 use middle::trans::adt;
94 use middle::trans::base::*;
95 use middle::trans::build::*;
96 use middle::trans::common::*;
97 use middle::trans::common;
98 use middle::trans::expr;
99 use middle::trans::glue;
100 use middle::trans::tvec;
101 use middle::trans::type_of;
102 use middle::trans::write_guard;
103 use middle::ty;
104 use util::common::indenter;
105 use util::ppaux::ty_to_str;
106
107 use std::uint;
108 use syntax::ast;
109 use syntax::codemap::Span;
110 use syntax::parse::token::special_idents;
111
112 #[deriving(Eq)]
113 pub enum CopyAction {
114     INIT,
115     DROP_EXISTING
116 }
117
118 pub struct Datum {
119     /// The llvm value.  This is either a pointer to the Rust value or
120     /// the value itself, depending on `mode` below.
121     val: ValueRef,
122
123     /// The rust type of the value.
124     ty: ty::t,
125
126     /// Indicates whether this is by-ref or by-value.
127     mode: DatumMode,
128 }
129
130 pub struct DatumBlock {
131     bcx: @mut Block,
132     datum: Datum,
133 }
134
135 #[deriving(Eq, IterBytes)]
136 pub enum DatumMode {
137     /// `val` is a pointer to the actual value (and thus has type *T).
138     /// The argument indicates how to cancel cleanup of this datum if
139     /// the value is moved elsewhere, which can either be by zeroing
140     /// the memory or by canceling a registered cleanup.
141     ByRef(DatumCleanup),
142
143     /// `val` is the actual value (*only used for immediates* like ints, ptrs)
144     ByValue,
145 }
146
147 impl DatumMode {
148     pub fn is_by_ref(&self) -> bool {
149         match *self { ByRef(_) => true, ByValue => false }
150     }
151
152     pub fn is_by_value(&self) -> bool {
153         match *self { ByRef(_) => false, ByValue => true }
154     }
155 }
156
157 /// See `Datum cleanup styles` section at the head of this module.
158 #[deriving(Eq, IterBytes)]
159 pub enum DatumCleanup {
160     RevokeClean,
161     ZeroMem
162 }
163
164 pub fn immediate_rvalue(val: ValueRef, ty: ty::t) -> Datum {
165     return Datum {val: val, ty: ty, mode: ByValue};
166 }
167
168 pub fn immediate_rvalue_bcx(bcx: @mut Block,
169                             val: ValueRef,
170                             ty: ty::t)
171                          -> DatumBlock {
172     return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)};
173 }
174
175 pub fn scratch_datum(bcx: @mut Block, ty: ty::t, name: &str, zero: bool) -> Datum {
176     /*!
177      * Allocates temporary space on the stack using alloca() and
178      * returns a by-ref Datum pointing to it.  If `zero` is true, the
179      * space will be zeroed when it is allocated; this is normally not
180      * necessary, but in the case of automatic rooting in match
181      * statements it is possible to have temporaries that may not get
182      * initialized if a certain arm is not taken, so we must zero
183      * them. You must arrange any cleanups etc yourself!
184      */
185
186     let llty = type_of::type_of(bcx.ccx(), ty);
187     let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
188     Datum { val: scratch, ty: ty, mode: ByRef(RevokeClean) }
189 }
190
191 pub fn appropriate_mode(ccx: &mut CrateContext, ty: ty::t) -> DatumMode {
192     /*!
193      * Indicates the "appropriate" mode for this value,
194      * which is either by ref or by value, depending
195      * on whether type is immediate or not.
196      */
197
198     if ty::type_is_voidish(ccx.tcx, ty) {
199         ByValue
200     } else if type_is_immediate(ccx, ty) {
201         ByValue
202     } else {
203         ByRef(RevokeClean)
204     }
205 }
206
207 impl Datum {
208     pub fn store_to(&self,
209                     bcx: @mut Block,
210                     action: CopyAction,
211                     dst: ValueRef)
212                     -> @mut Block {
213         /*!
214          *
215          * Stores this value into its final home.  This moves if
216          * `id` is located in the move table, but copies otherwise.
217          */
218
219         if ty::type_moves_by_default(bcx.tcx(), self.ty) {
220             self.move_to(bcx, action, dst)
221         } else {
222             self.copy_to(bcx, action, dst)
223         }
224     }
225
226     pub fn store_to_dest(&self,
227                          bcx: @mut Block,
228                          dest: expr::Dest)
229                          -> @mut Block {
230         match dest {
231             expr::Ignore => {
232                 return bcx;
233             }
234             expr::SaveIn(addr) => {
235                 return self.store_to(bcx, INIT, addr);
236             }
237         }
238     }
239
240     pub fn store_to_datum(&self,
241                           bcx: @mut Block,
242                           action: CopyAction,
243                           datum: Datum)
244                           -> @mut Block {
245         debug2!("store_to_datum(self={}, action={:?}, datum={})",
246                self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
247         assert!(datum.mode.is_by_ref());
248         self.store_to(bcx, action, datum.val)
249     }
250
251     pub fn move_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
252                          -> @mut Block {
253         assert!(datum.mode.is_by_ref());
254         self.move_to(bcx, action, datum.val)
255     }
256
257     pub fn copy_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
258                          -> @mut Block {
259         assert!(datum.mode.is_by_ref());
260         self.copy_to(bcx, action, datum.val)
261     }
262
263     pub fn copy_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
264                    -> @mut Block {
265         /*!
266          *
267          * Copies the value into `dst`, which should be a pointer to a
268          * memory location suitable for `self.ty`.  You PROBABLY want
269          * `store_to()` instead, which will move if possible but copy if
270          * neccessary. */
271
272         let _icx = push_ctxt("copy_to");
273
274         if ty::type_is_voidish(bcx.tcx(), self.ty) {
275             return bcx;
276         }
277
278         debug2!("copy_to(self={}, action={:?}, dst={})",
279                self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
280
281         // Watch out for the case where we are writing the copying the
282         // value into the same location we read it out from.  We want
283         // to avoid the case where we drop the existing value, which
284         // frees it, and then overwrite it with itself (which has been
285         // freed).
286         if action == DROP_EXISTING &&
287             ty::type_needs_drop(bcx.tcx(), self.ty)
288         {
289             match self.mode {
290                 ByRef(_) => {
291                     let cast = PointerCast(bcx, dst, val_ty(self.val));
292                     let cmp = ICmp(bcx, lib::llvm::IntNE, cast, self.val);
293                     do with_cond(bcx, cmp) |bcx| {
294                         self.copy_to_no_check(bcx, action, dst)
295                     }
296                 }
297                 ByValue => {
298                     self.copy_to_no_check(bcx, action, dst)
299                 }
300             }
301         } else {
302             self.copy_to_no_check(bcx, action, dst)
303         }
304     }
305
306     pub fn copy_to_no_check(&self,
307                             bcx: @mut Block,
308                             action: CopyAction,
309                             dst: ValueRef)
310                             -> @mut Block {
311         /*!
312          *
313          * A helper for `copy_to()` which does not check to see if we
314          * are copying to/from the same value. */
315
316         let _icx = push_ctxt("copy_to_no_check");
317         let mut bcx = bcx;
318
319         if action == DROP_EXISTING {
320             bcx = glue::drop_ty(bcx, dst, self.ty);
321         }
322
323         match self.mode {
324             ByValue => {
325                 Store(bcx, self.val, dst);
326             }
327             ByRef(_) => {
328                 memcpy_ty(bcx, dst, self.val, self.ty);
329             }
330         }
331
332         return glue::take_ty(bcx, dst, self.ty);
333     }
334
335     // This works like copy_val, except that it deinitializes the source.
336     // Since it needs to zero out the source, src also needs to be an lval.
337     //
338     pub fn move_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
339                    -> @mut Block {
340         let _icx = push_ctxt("move_to");
341         let mut bcx = bcx;
342
343         debug2!("move_to(self={}, action={:?}, dst={})",
344                self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
345
346         if ty::type_is_voidish(bcx.tcx(), self.ty) {
347             return bcx;
348         }
349
350         if action == DROP_EXISTING {
351             bcx = glue::drop_ty(bcx, dst, self.ty);
352         }
353
354         match self.mode {
355             ByRef(_) => {
356                 memcpy_ty(bcx, dst, self.val, self.ty);
357             }
358             ByValue => {
359                 Store(bcx, self.val, dst);
360             }
361         }
362
363         self.cancel_clean(bcx);
364
365         return bcx;
366     }
367
368     pub fn add_clean(&self, bcx: @mut Block) {
369         /*!
370          * Schedules this datum for cleanup in `bcx`.  The datum
371          * must be an rvalue.
372          */
373
374         match self.mode {
375             ByValue => {
376                 add_clean_temp_immediate(bcx, self.val, self.ty);
377             }
378             ByRef(RevokeClean) => {
379                 add_clean_temp_mem(bcx, self.val, self.ty);
380             }
381             ByRef(ZeroMem) => {
382                 bcx.tcx().sess.bug(
383                     format!("Cannot add clean to a 'zero-mem' datum"));
384             }
385         }
386     }
387
388     pub fn cancel_clean(&self, bcx: @mut Block) {
389         if ty::type_needs_drop(bcx.tcx(), self.ty) {
390             match self.mode {
391                 ByValue |
392                 ByRef(RevokeClean) => {
393                     revoke_clean(bcx, self.val);
394                 }
395                 ByRef(ZeroMem) => {
396                     // Lvalues which potentially need to be dropped
397                     // must be passed by ref, so that we can zero them
398                     // out.
399                     assert!(self.mode.is_by_ref());
400                     zero_mem(bcx, self.val, self.ty);
401                 }
402             }
403         }
404     }
405
406     pub fn to_str(&self, ccx: &CrateContext) -> ~str {
407         format!("Datum \\{ val={}, ty={}, mode={:?} \\}",
408              ccx.tn.val_to_str(self.val),
409              ty_to_str(ccx.tcx, self.ty),
410              self.mode)
411     }
412
413     pub fn to_value_datum(&self, bcx: @mut Block) -> Datum {
414         /*!
415          *
416          * Yields a by-value form of this datum.  This may involve
417          * creation of a temporary stack slot.  The value returned by
418          * this function is not separately rooted from this datum, so
419          * it will not live longer than the current datum. */
420
421         match self.mode {
422             ByValue => *self,
423             ByRef(_) => {
424                 Datum {val: self.to_value_llval(bcx), mode: ByValue,
425                        ty: self.ty}
426             }
427         }
428     }
429
430     pub fn to_value_llval(&self, bcx: @mut Block) -> ValueRef {
431         /*!
432          *
433          * Yields the value itself. */
434
435         if ty::type_is_voidish(bcx.tcx(), self.ty) {
436             C_nil()
437         } else {
438             match self.mode {
439                 ByValue => self.val,
440                 ByRef(_) => {
441                     if ty::type_is_bool(self.ty) {
442                         LoadRangeAssert(bcx, self.val, 0, 2, lib::llvm::True)
443                     } else {
444                         Load(bcx, self.val)
445                     }
446                 }
447             }
448         }
449     }
450
451     pub fn to_ref_datum(&self, bcx: @mut Block) -> Datum {
452         /*!
453          * Yields a by-ref form of this datum.  This may involve
454          * creation of a temporary stack slot.  The value returned by
455          * this function is not separately rooted from this datum, so
456          * it will not live longer than the current datum.
457          */
458
459         match self.mode {
460             ByRef(_) => *self,
461             ByValue => {
462                 Datum {val: self.to_ref_llval(bcx), mode: ByRef(RevokeClean),
463                        ty: self.ty}
464             }
465         }
466     }
467
468     pub fn to_ref_llval(&self, bcx: @mut Block) -> ValueRef {
469         match self.mode {
470             ByRef(_) => self.val,
471             ByValue => {
472                 if ty::type_is_voidish(bcx.tcx(), self.ty) {
473                     C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
474                 } else {
475                     let slot = alloc_ty(bcx, self.ty, "");
476                     Store(bcx, self.val, slot);
477                     slot
478                 }
479             }
480         }
481     }
482
483     pub fn to_zeroable_ref_llval(&self, bcx: @mut Block) -> ValueRef {
484         /*!
485          * Returns a by-ref llvalue that can be zeroed in order to
486          * cancel cleanup. This is a kind of hokey bridge used
487          * to adapt to the match code. Please don't use it for new code.
488          */
489
490         match self.mode {
491             // All by-ref datums are zeroable, even if we *could* just
492             // cancel the cleanup.
493             ByRef(_) => self.val,
494
495             // By value datums can't be zeroed (where would you store
496             // the zero?) so we have to spill them. Add a temp cleanup
497             // for this spilled value and cancel the cleanup on this
498             // current value.
499             ByValue => {
500                 let slot = self.to_ref_llval(bcx);
501                 self.cancel_clean(bcx);
502                 add_clean_temp_mem(bcx, slot, self.ty);
503                 slot
504             }
505         }
506     }
507
508     pub fn appropriate_mode(&self, ccx: &mut CrateContext) -> DatumMode {
509         /*! See the `appropriate_mode()` function */
510
511         appropriate_mode(ccx, self.ty)
512     }
513
514     pub fn to_appropriate_llval(&self, bcx: @mut Block) -> ValueRef {
515         /*!
516          *
517          * Yields an llvalue with the `appropriate_mode()`. */
518
519         match self.appropriate_mode(bcx.ccx()) {
520             ByValue => self.to_value_llval(bcx),
521             ByRef(_) => self.to_ref_llval(bcx)
522         }
523     }
524
525     pub fn to_appropriate_datum(&self, bcx: @mut Block) -> Datum {
526         /*!
527          *
528          * Yields a datum with the `appropriate_mode()`. */
529
530         match self.appropriate_mode(bcx.ccx()) {
531             ByValue => self.to_value_datum(bcx),
532             ByRef(_) => self.to_ref_datum(bcx)
533         }
534     }
535
536     pub fn get_element(&self,
537                        bcx: @mut Block,
538                        ty: ty::t,
539                        source: DatumCleanup,
540                        gep: &fn(ValueRef) -> ValueRef)
541                        -> Datum {
542         let base_val = self.to_ref_llval(bcx);
543         Datum {
544             val: gep(base_val),
545             mode: ByRef(source),
546             ty: ty,
547         }
548     }
549
550     pub fn drop_val(&self, bcx: @mut Block) -> @mut Block {
551         if !ty::type_needs_drop(bcx.tcx(), self.ty) {
552             return bcx;
553         }
554
555         return match self.mode {
556             ByRef(_) => glue::drop_ty(bcx, self.val, self.ty),
557             ByValue => glue::drop_ty_immediate(bcx, self.val, self.ty)
558         };
559     }
560
561     pub fn box_body(&self, bcx: @mut Block) -> Datum {
562         /*!
563          *
564          * This datum must represent an @T or ~T box.  Returns a new
565          * by-ref datum of type T, pointing at the contents. */
566
567         let (content_ty, header) = match ty::get(self.ty).sty {
568             ty::ty_box(mt) => (mt.ty, true),
569             ty::ty_uniq(mt) => (mt.ty, false),
570             ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
571                 let unit_ty = ty::sequence_element_type(bcx.tcx(), self.ty);
572                 let unboxed_vec_ty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty);
573                 (unboxed_vec_ty, true)
574             }
575             _ => {
576                 bcx.tcx().sess.bug(format!(
577                     "box_body() invoked on non-box type {}",
578                     ty_to_str(bcx.tcx(), self.ty)));
579             }
580         };
581
582         if !header && !ty::type_contents(bcx.tcx(), content_ty).contains_managed() {
583             let ptr = self.to_value_llval(bcx);
584             let ty = type_of::type_of(bcx.ccx(), content_ty);
585             let body = PointerCast(bcx, ptr, ty.ptr_to());
586             Datum {val: body, ty: content_ty, mode: ByRef(ZeroMem)}
587         } else { // has a header
588             let ptr = self.to_value_llval(bcx);
589             let body = opaque_box_body(bcx, content_ty, ptr);
590             Datum {val: body, ty: content_ty, mode: ByRef(ZeroMem)}
591         }
592     }
593
594     pub fn to_rptr(&self, bcx: @mut Block) -> Datum {
595         //! Returns a new datum of region-pointer type containing the
596         //! the same ptr as this datum (after converting to by-ref
597         //! using `to_ref_llval()`).
598
599         // Convert to ref, yielding lltype *T.  Then create a Rust
600         // type &'static T (which translates to *T).  Construct new
601         // result (which will be by-value).  Note that it is not
602         // significant *which* region we pick here.
603         let llval = self.to_ref_llval(bcx);
604         let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static,
605                                       self.ty);
606         Datum {val: llval, ty: rptr_ty, mode: ByValue}
607     }
608
609     /// bcx: Block wherein to generate insns.
610     /// span: Location where deref occurs.
611     /// expr_id: ID of deref expr.
612     /// derefs: Number of times deref'd already.
613     /// is_auto: If true, only deref if auto-derefable.
614     pub fn try_deref(&self,
615                      bcx: @mut Block,
616                      span: Span,
617                      expr_id: ast::NodeId,
618                      derefs: uint,
619                      is_auto: bool)
620                      -> (Option<Datum>, @mut Block) {
621         let ccx = bcx.ccx();
622
623         debug2!("try_deref(expr_id={:?}, derefs={:?}, is_auto={}, self={:?})",
624                expr_id, derefs, is_auto, self.to_str(bcx.ccx()));
625
626         let bcx =
627             write_guard::root_and_write_guard(
628                 self, bcx, span, expr_id, derefs);
629
630         match ty::get(self.ty).sty {
631             ty::ty_box(_) | ty::ty_uniq(_) => {
632                 return (Some(self.box_body(bcx)), bcx);
633             }
634             ty::ty_ptr(mt) => {
635                 if is_auto { // unsafe ptrs are not AUTO-derefable
636                     return (None, bcx);
637                 } else {
638                     return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
639                 }
640             }
641             ty::ty_rptr(_, mt) => {
642                 return (Some(deref_ptr(bcx, self, mt.ty)), bcx);
643             }
644             ty::ty_enum(did, ref substs) => {
645                 // Check whether this enum is a newtype enum:
646                 let variants = ty::enum_variants(ccx.tcx, did);
647                 if (*variants).len() != 1 || variants[0].args.len() != 1 {
648                     return (None, bcx);
649                 }
650
651                 let repr = adt::represent_type(ccx, self.ty);
652                 let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]);
653                 return match self.mode {
654                     ByRef(_) => {
655                         // Recast lv.val as a pointer to the newtype
656                         // rather than a ptr to the enum type.
657                         (
658                             Some(Datum {
659                                 val: adt::trans_field_ptr(bcx, repr, self.val,
660                                                     0, 0),
661                                 ty: ty,
662                                 mode: ByRef(ZeroMem)
663                             }),
664                             bcx
665                         )
666                     }
667                     ByValue => {
668                         // Actually, this case cannot happen right
669                         // now, because enums are never immediate.
670                         assert!(type_is_immediate(bcx.ccx(), ty));
671                         (Some(Datum {ty: ty, ..*self}), bcx)
672                     }
673                 };
674             }
675             ty::ty_struct(did, ref substs) => {
676                 // Check whether this struct is a newtype struct.
677                 let fields = ty::struct_fields(ccx.tcx, did, substs);
678                 if fields.len() != 1 || fields[0].ident !=
679                     special_idents::unnamed_field {
680                     return (None, bcx);
681                 }
682
683                 let repr = adt::represent_type(ccx, self.ty);
684                 let ty = fields[0].mt.ty;
685                 return match self.mode {
686                     ByRef(_) => {
687                         // Recast lv.val as a pointer to the newtype rather
688                         // than a pointer to the struct type.
689                         // FIXME #6572: This isn't correct for structs with
690                         // destructors.
691                         (
692                             Some(Datum {
693                                 val: adt::trans_field_ptr(bcx, repr, self.val,
694                                                     0, 0),
695                                 ty: ty,
696                                 mode: ByRef(ZeroMem)
697                             }),
698                             bcx
699                         )
700                     }
701                     ByValue => {
702                         assert!(type_is_immediate(bcx.ccx(), ty));
703                         (
704                             Some(Datum {
705                                 val: ExtractValue(bcx, self.val, 0),
706                                 ty: ty,
707                                 mode: ByValue
708                             }),
709                             bcx
710                         )
711                     }
712                 }
713             }
714             _ => { // not derefable.
715                 return (None, bcx);
716             }
717         }
718
719         fn deref_ptr(bcx: @mut Block, lv: &Datum, ty: ty::t) -> Datum {
720             Datum {
721                 val: lv.to_value_llval(bcx),
722                 ty: ty,
723                 mode: ByRef(ZeroMem)
724             }
725         }
726     }
727
728     /// expr: The deref expression.
729     pub fn deref(&self, bcx: @mut Block, expr: &ast::Expr, derefs: uint)
730                  -> DatumBlock {
731         match self.try_deref(bcx, expr.span, expr.id, derefs, false) {
732             (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres },
733             (None, _) => {
734                 bcx.ccx().sess.span_bug(expr.span,
735                                         "Cannot deref this expression");
736             }
737         }
738     }
739
740     pub fn autoderef(&self,
741                      bcx: @mut Block,
742                      span: Span,
743                      expr_id: ast::NodeId,
744                      max: uint)
745                      -> DatumBlock {
746         let _icx = push_ctxt("autoderef");
747
748         debug2!("autoderef(expr_id={}, max={:?}, self={:?})",
749                expr_id, max, self.to_str(bcx.ccx()));
750         let _indenter = indenter();
751
752         let mut datum = *self;
753         let mut derefs = 0u;
754         let mut bcx = bcx;
755         while derefs < max {
756             derefs += 1u;
757             match datum.try_deref(bcx, span, expr_id, derefs, true) {
758                 (None, new_bcx) => { bcx = new_bcx; break }
759                 (Some(datum_deref), new_bcx) => {
760                     datum = datum_deref;
761                     bcx = new_bcx;
762                 }
763             }
764         }
765
766         // either we were asked to deref a specific number of times,
767         // in which case we should have, or we asked to deref as many
768         // times as we can
769         assert!(derefs == max || max == uint::max_value);
770         DatumBlock { bcx: bcx, datum: datum }
771     }
772
773     pub fn get_vec_base_and_byte_len(&self,
774                                      mut bcx: @mut Block,
775                                      span: Span,
776                                      expr_id: ast::NodeId,
777                                      derefs: uint)
778                                      -> (@mut Block, ValueRef, ValueRef) {
779         //! Converts a vector into the slice pair. Performs rooting
780         //! and write guards checks.
781
782         // only imp't for @[] and @str, but harmless
783         bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
784         let (base, len) = self.get_vec_base_and_byte_len_no_root(bcx);
785         (bcx, base, len)
786     }
787
788     pub fn get_vec_base_and_byte_len_no_root(&self, bcx: @mut Block)
789                                              -> (ValueRef, ValueRef) {
790         //! Converts a vector into the slice pair. Des not root
791         //! nor perform write guard checks.
792
793         let llval = self.to_appropriate_llval(bcx);
794         tvec::get_base_and_byte_len(bcx, llval, self.ty)
795     }
796
797     pub fn get_vec_base_and_len(&self,
798                                      mut bcx: @mut Block,
799                                      span: Span,
800                                      expr_id: ast::NodeId,
801                                      derefs: uint)
802                                      -> (@mut Block, ValueRef, ValueRef) {
803         //! Converts a vector into the slice pair. Performs rooting
804         //! and write guards checks.
805
806         // only imp't for @[] and @str, but harmless
807         bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
808         let (base, len) = self.get_vec_base_and_len_no_root(bcx);
809         (bcx, base, len)
810     }
811
812     pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block)
813                                              -> (ValueRef, ValueRef) {
814         //! Converts a vector into the slice pair. Des not root
815         //! nor perform write guard checks.
816
817         let llval = self.to_appropriate_llval(bcx);
818         tvec::get_base_and_len(bcx, llval, self.ty)
819     }
820
821     pub fn root_and_write_guard(&self,
822                                 bcx: @mut Block,
823                                 span: Span,
824                                 expr_id: ast::NodeId,
825                                 derefs: uint)
826                                 -> @mut Block {
827         write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs)
828     }
829
830     pub fn to_result(&self, bcx: @mut Block) -> common::Result {
831         rslt(bcx, self.to_appropriate_llval(bcx))
832     }
833 }
834
835 impl DatumBlock {
836     pub fn unpack(&self, bcx: &mut @mut Block) -> Datum {
837         *bcx = self.bcx;
838         return self.datum;
839     }
840
841     pub fn assert_by_ref(&self) -> DatumBlock {
842         assert!(self.datum.mode.is_by_ref());
843         *self
844     }
845
846     pub fn drop_val(&self) -> @mut Block {
847         self.datum.drop_val(self.bcx)
848     }
849
850     pub fn store_to(&self,
851                     action: CopyAction,
852                     dst: ValueRef)
853                     -> @mut Block {
854         self.datum.store_to(self.bcx, action, dst)
855     }
856
857     pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
858         self.datum.copy_to(self.bcx, action, dst)
859     }
860
861     pub fn move_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
862         self.datum.move_to(self.bcx, action, dst)
863     }
864
865     pub fn to_value_llval(&self) -> ValueRef {
866         self.datum.to_value_llval(self.bcx)
867     }
868
869     pub fn to_result(&self) -> common::Result {
870         rslt(self.bcx, self.datum.to_appropriate_llval(self.bcx))
871     }
872
873     pub fn ccx(&self) -> @mut CrateContext {
874         self.bcx.ccx()
875     }
876
877     pub fn tcx(&self) -> ty::ctxt {
878         self.bcx.tcx()
879     }
880
881     pub fn to_str(&self) -> ~str {
882         self.datum.to_str(self.ccx())
883     }
884 }