]> git.lizzy.rs Git - rust.git/commitdiff
Extend `trans::datum::Lvalue` so that it carrys an optional dropflag hint.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Fri, 5 Jun 2015 19:34:03 +0000 (21:34 +0200)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Tue, 28 Jul 2015 14:12:32 +0000 (16:12 +0200)
Instrumented calls sites that construct Lvalues to ease tracking down
cases that we might need to change whether or not they carry a hint.

Note that this commit does not do anything to actually *construct*
the `lldropflag_hints` map, nor does it change anything about codegen
itself. Those parts are in follow-on commits.

src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/adt.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/datum.rs
src/librustc_trans/trans/expr.rs

index c1fb6f2437f70d1fb9efa9fbb0d1cae7d5dd0389..08be1fd2e4c57cca36831286105283b0c3dd7f7d 100644 (file)
@@ -437,7 +437,7 @@ impl MatchInput {
     fn from_val(val: ValueRef) -> MatchInput {
         MatchInput {
             val: val,
-            lval: Lvalue,
+            lval: Lvalue::new("MatchInput::from_val"),
         }
     }
 
@@ -941,30 +941,41 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                cs: Option<cleanup::ScopeId>)
                                -> Block<'blk, 'tcx> {
     for (&ident, &binding_info) in bindings_map {
-        let llval = match binding_info.trmode {
+        let (llval, aliases_other_state) = match binding_info.trmode {
             // By value mut binding for a copy type: load from the ptr
             // into the matched value and copy to our alloca
             TrByCopy(llbinding) |
             TrByMoveIntoCopy(llbinding) => {
                 let llval = Load(bcx, binding_info.llmatch);
-                let datum = Datum::new(llval, binding_info.ty, Lvalue);
+                let lval = match binding_info.trmode {
+                    TrByCopy(..) =>
+                        Lvalue::new("_match::insert_lllocals"),
+                    TrByMoveIntoCopy(..) =>
+                        Lvalue::match_input("_match::insert_lllocals", bcx, binding_info.id),
+                    _ => unreachable!(),
+                };
+                let datum = Datum::new(llval, binding_info.ty, lval);
                 call_lifetime_start(bcx, llbinding);
                 bcx = datum.store_to(bcx, llbinding);
                 if let Some(cs) = cs {
                     bcx.fcx.schedule_lifetime_end(cs, llbinding);
                 }
 
-                llbinding
+                (llbinding, false)
             },
 
             // By value move bindings: load from the ptr into the matched value
-            TrByMoveRef => Load(bcx, binding_info.llmatch),
+            TrByMoveRef => (Load(bcx, binding_info.llmatch), true),
 
             // By ref binding: use the ptr into the matched value
-            TrByRef => binding_info.llmatch
+            TrByRef => (binding_info.llmatch, true),
         };
 
-        let datum = Datum::new(llval, binding_info.ty, Lvalue);
+        let lval = Lvalue::local("_match::insert_lllocals",
+                                 bcx,
+                                 binding_info.id,
+                                 aliases_other_state);
+        let datum = Datum::new(llval, binding_info.ty, lval);
         if let Some(cs) = cs {
             bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
             bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty);
@@ -1619,6 +1630,7 @@ fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             let scope = cleanup::var_scope(tcx, p_id);
             bcx = mk_binding_alloca(
                 bcx, p_id, path1.node.name, scope, (),
+                "_match::store_local::create_dummy_locals",
                 |(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx });
         });
         bcx
@@ -1641,6 +1653,7 @@ fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                     let var_scope = cleanup::var_scope(tcx, local.id);
                     return mk_binding_alloca(
                         bcx, pat.id, ident.name, var_scope, (),
+                        "_match::store_local",
                         |(), bcx, v, _| expr::trans_into(bcx, &**init_expr,
                                                          expr::SaveIn(v)));
                 }
@@ -1668,6 +1681,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
                                        name: ast::Name,
                                        cleanup_scope: cleanup::ScopeId,
                                        arg: A,
+                                       caller_name: &'static str,
                                        populate: F)
                                        -> Block<'blk, 'tcx> where
     F: FnOnce(A, Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
@@ -1685,7 +1699,8 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
 
     // Now that memory is initialized and has cleanup scheduled,
     // create the datum and insert into the local variable map.
-    let datum = Datum::new(llval, var_ty, Lvalue);
+    let lval = Lvalue::binding(caller_name, bcx, p_id, name);
+    let datum = Datum::new(llval, var_ty, lval);
     bcx.fcx.lllocals.borrow_mut().insert(p_id, datum);
     bcx
 }
@@ -1730,6 +1745,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // map.
                 bcx = mk_binding_alloca(
                     bcx, pat.id, path1.node.name, cleanup_scope, (),
+                    "_match::bind_irrefutable_pat",
                     |(), bcx, llval, ty| {
                         match pat_binding_mode {
                             ast::BindByValue(_) => {
index dc7e34a386f93d124377eb22ca85dd0f052922ae..d2753f5b78fb40a0fce87ef5ec9cc356054cbe10 100644 (file)
@@ -1083,7 +1083,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             ));
             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
                 let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
-                datum::Datum::new(ptr, ptr_ty, datum::Lvalue)
+                datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr"))
                     .store_to(variant_cx, scratch.val)
             });
             let expr_datum = scratch.to_expr_datum();
index 1e016ea1fdcf3da4e5e250611d6632b435ac08ef..ec7ff4fa748e0dbac8f1e767fac064959a8c2a02 100644 (file)
@@ -56,7 +56,7 @@
 use trans::closure;
 use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
 use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
-use trans::common::{CrateContext, FunctionContext};
+use trans::common::{CrateContext, DropFlagHintsMap, FunctionContext};
 use trans::common::{Result, NodeIdAndSpan};
 use trans::common::{node_id_type, return_type_is_void};
 use trans::common::{type_is_immediate, type_is_zero_size, val_ty};
@@ -1235,6 +1235,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
           caller_expects_out_pointer: uses_outptr,
           lllocals: RefCell::new(NodeMap()),
           llupvars: RefCell::new(NodeMap()),
+          lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
           id: id,
           param_substs: param_substs,
           span: sp,
index 0d49712031937fe232cd749e47958829bba10fec..fe996020267ed5d0388234fec4b8f5ab78d2efe2 100644 (file)
 use trans::build;
 use trans::common;
 use trans::common::{Block, FunctionContext, NodeIdAndSpan};
+use trans::datum::{Datum, Lvalue};
 use trans::debuginfo::{DebugLoc, ToDebugLoc};
 use trans::glue;
 use middle::region;
@@ -212,6 +213,12 @@ pub enum ScopeId {
     CustomScope(CustomScopeIndex)
 }
 
+#[derive(Copy, Clone, Debug)]
+pub struct DropHint<K>(pub ast::NodeId, pub K);
+
+pub type DropHintDatum<'tcx> = DropHint<Datum<'tcx, Lvalue>>;
+pub type DropHintValue = DropHint<ValueRef>;
+
 impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
     /// Invoked when we start to trans the code contained within a new cleanup scope.
     fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) {
index 8ec65639b5227d6fff4c0264294ddda8319fdf15..82c835e8c34ec8dcf757d6c4f041066d32b3b6b4 100644 (file)
@@ -299,6 +299,27 @@ pub fn validate_substs(substs: &Substs) {
 type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
 pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
 
+#[derive(Clone, Debug)]
+struct HintEntry<'tcx> {
+    // The datum for the dropflag-hint itself; note that many
+    // source-level Lvalues will be associated with the same
+    // dropflag-hint datum.
+    datum: cleanup::DropHintDatum<'tcx>,
+}
+
+pub struct DropFlagHintsMap<'tcx> {
+    // Maps NodeId for expressions that read/write unfragmented state
+    // to that state's drop-flag "hint."  (A stack-local hint
+    // indicates either that (1.) it is certain that no-drop is
+    // needed, or (2.)  inline drop-flag must be consulted.)
+    node_map: NodeMap<HintEntry<'tcx>>,
+}
+
+impl<'tcx> DropFlagHintsMap<'tcx> {
+    pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } }
+    pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) }
+}
+
 // Function context.  Every LLVM function we create will have one of
 // these.
 pub struct FunctionContext<'a, 'tcx: 'a> {
@@ -349,6 +370,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     // Same as above, but for closure upvars
     pub llupvars: RefCell<NodeMap<ValueRef>>,
 
+    // Carries info about drop-flags for local bindings (longer term,
+    // paths) for the code being compiled.
+    pub lldropflag_hints: RefCell<DropFlagHintsMap<'tcx>>,
+
     // The NodeId of the function, or -1 if it doesn't correspond to
     // a user-defined function.
     pub id: ast::NodeId,
index c0ebffb58afcf088ed10c9fab0cf63167261eda0..f14b6f368f4b140298a1da949674b9cf64894a1a 100644 (file)
@@ -138,17 +138,141 @@ pub enum Expr {
     /// `val` is a pointer into memory for which a cleanup is scheduled
     /// (and thus has type *T). If you move out of an Lvalue, you must
     /// zero out the memory (FIXME #5016).
-    LvalueExpr,
+    LvalueExpr(Lvalue),
 }
 
-#[derive(Clone, Copy, Debug)]
-pub struct Lvalue;
+#[derive(Copy, Clone, Debug)]
+pub enum DropFlagInfo {
+    DontZeroJustUse(ast::NodeId),
+    ZeroAndMaintain(ast::NodeId),
+    None,
+}
+
+impl DropFlagInfo {
+    pub fn must_zero(&self) -> bool {
+        match *self {
+            DropFlagInfo::DontZeroJustUse(..) => false,
+            DropFlagInfo::ZeroAndMaintain(..) => true,
+            DropFlagInfo::None => true,
+        }
+    }
+
+    pub fn hint_to_maintain(&self) -> Option<ast::NodeId> {
+        match *self {
+            DropFlagInfo::DontZeroJustUse(id) => Some(id),
+            DropFlagInfo::ZeroAndMaintain(id) => Some(id),
+            DropFlagInfo::None => None,
+        }
+    }
+}
+
+// FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients
+// may not realize that subparts of an Lvalue can have a subset of
+// drop-flags associated with them, while this as written will just
+// memcpy the drop_flag_info. But, it is an easier way to get `_match`
+// off the ground to just let this be `Copy` for now.
+#[derive(Copy, Clone, Debug)]
+pub struct Lvalue {
+    pub source: &'static str,
+    pub drop_flag_info: DropFlagInfo
+}
 
 #[derive(Debug)]
 pub struct Rvalue {
     pub mode: RvalueMode
 }
 
+impl Lvalue {
+    pub fn new(source: &'static str) -> Lvalue {
+        Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
+    }
+
+    pub fn upvar<'blk, 'tcx>(source: &'static str,
+                             bcx: Block<'blk, 'tcx>,
+                             id: ast::NodeId) -> Lvalue {
+        let info = if Lvalue::has_dropflag_hint(bcx, id) {
+            DropFlagInfo::ZeroAndMaintain(id)
+        } else {
+            DropFlagInfo::None
+        };
+        let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
+        debug!("upvar Lvalue at {}, id: {} info: {:?}", source, id, info);
+        Lvalue { source: source, drop_flag_info: info }
+    }
+
+    pub fn match_input<'blk, 'tcx>(source: &'static str,
+                                   bcx: Block<'blk, 'tcx>,
+                                   id: ast::NodeId) -> Lvalue
+    {
+        let info = if Lvalue::has_dropflag_hint(bcx, id) {
+            // match_input is used to move from the input into a
+            // separate stack slot; it must zero (at least until we
+            // improve things to track drop flags for the fragmented
+            // parent match input expression).
+            DropFlagInfo::ZeroAndMaintain(id)
+        } else {
+            DropFlagInfo::None
+        };
+        let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
+        debug!("match_input Lvalue at {}, id: {} info: {:?}", source, id, info);
+        Lvalue { source: source, drop_flag_info: info }
+    }
+
+    pub fn local<'blk, 'tcx>(source: &'static str,
+                             bcx: Block<'blk, 'tcx>,
+                             id: ast::NodeId,
+                             aliases_other_state: bool)
+                             -> Lvalue
+    {
+        let info = if Lvalue::has_dropflag_hint(bcx, id) {
+            if aliases_other_state {
+                DropFlagInfo::ZeroAndMaintain(id)
+            } else {
+                DropFlagInfo::DontZeroJustUse(id)
+            }
+        } else {
+            DropFlagInfo::None
+        };
+        let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
+        debug!("local Lvalue at {}, id: {} info: {:?}", source, id, info);
+        Lvalue { source: source, drop_flag_info: info }
+    }
+
+    pub fn store_arg<'blk, 'tcx>(source: &'static str,
+                                 bcx: Block<'blk, 'tcx>,
+                                 id: ast::NodeId) -> Lvalue
+    {
+        let info = if Lvalue::has_dropflag_hint(bcx, id) {
+            DropFlagInfo::ZeroAndMaintain(id)
+        } else {
+            DropFlagInfo::None
+        };
+        let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
+        debug!("store_arg Lvalue at {}, id: {} info: {:?}", source, id, info);
+        Lvalue { source: source, drop_flag_info: info }
+    }
+
+    pub fn binding<'blk, 'tcx>(source: &'static str,
+                               bcx: Block<'blk, 'tcx>,
+                               id: ast::NodeId,
+                               name: ast::Name) -> Lvalue {
+        let info = if Lvalue::has_dropflag_hint(bcx, id) {
+            DropFlagInfo::DontZeroJustUse(id)
+        } else {
+            DropFlagInfo::None
+        };
+        let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
+        debug!("binding Lvalue at {}, id: {} name: {} info: {:?}",
+               source, id, name, info);
+        Lvalue { source: source, drop_flag_info: info }
+    }
+
+    fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                     id: ast::NodeId) -> bool {
+        bcx.fcx.lldropflag_hints.borrow().has_hint(id)
+    }
+}
+
 impl Rvalue {
     pub fn new(m: RvalueMode) -> Rvalue {
         Rvalue { mode: m }
@@ -201,7 +325,7 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
     bcx.fcx.schedule_lifetime_end(scope, scratch);
     bcx.fcx.schedule_drop_mem(scope, scratch, ty);
 
-    DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
+    DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
 }
 
 /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
@@ -308,7 +432,7 @@ fn is_by_ref(&self) -> bool {
     }
 
     fn to_expr_kind(self) -> Expr {
-        LvalueExpr
+        LvalueExpr(self)
     }
 }
 
@@ -319,14 +443,14 @@ fn post_store<'blk, 'tcx>(&self,
                               ty: Ty<'tcx>)
                               -> Block<'blk, 'tcx> {
         match *self {
-            LvalueExpr => Lvalue.post_store(bcx, val, ty),
+            LvalueExpr(ref l) => l.post_store(bcx, val, ty),
             RvalueExpr(ref r) => r.post_store(bcx, val, ty),
         }
     }
 
     fn is_by_ref(&self) -> bool {
         match *self {
-            LvalueExpr => Lvalue.is_by_ref(),
+            LvalueExpr(ref l) => l.is_by_ref(),
             RvalueExpr(ref r) => r.is_by_ref()
         }
     }
@@ -360,7 +484,10 @@ pub fn to_lvalue_datum_in_scope<'blk>(self,
         match self.kind.mode {
             ByRef => {
                 add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
-                DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue))
+                DatumBlock::new(bcx, Datum::new(
+                    self.val,
+                    self.ty,
+                    Lvalue::new("datum::to_lvalue_datum_in_scope")))
             }
 
             ByValue => {
@@ -417,7 +544,7 @@ fn match_kind<R, F, G>(self, if_lvalue: F, if_rvalue: G) -> R where
     {
         let Datum { val, ty, kind } = self;
         match kind {
-            LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)),
+            LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)),
             RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
         }
     }
@@ -528,7 +655,7 @@ pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>,
         };
         Datum {
             val: val,
-            kind: Lvalue,
+            kind: Lvalue::new("Datum::get_element"),
             ty: ty,
         }
     }
index 962803932b88b03361d671be9dfd79b6dadc6c40..1582a43d94de59d9c69fa65fdc0087e86e81c60f 100644 (file)
@@ -227,7 +227,7 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let const_ty = expr_ty_adjusted(bcx, expr);
             let llty = type_of::type_of(bcx.ccx(), const_ty);
             let global = PointerCast(bcx, global, llty.ptr_to());
-            let datum = Datum::new(global, const_ty, Lvalue);
+            let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
             return DatumBlock::new(bcx, datum.to_expr_datum());
         }
 
@@ -733,7 +733,7 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
 
             // Always generate an lvalue datum, because this pointer doesn't own
             // the data and cleanup is scheduled elsewhere.
-            DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr))
+            DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind)))
         }
     })
 
@@ -810,10 +810,11 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                Some(SaveIn(scratch.val)),
                                                false));
             let datum = scratch.to_expr_datum();
+            let lval = Lvalue::new("expr::trans_index overload");
             if type_is_sized(bcx.tcx(), elt_ty) {
-                Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
+                Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr(lval))
             } else {
-                Datum::new(datum.val, elt_ty, LvalueExpr)
+                Datum::new(datum.val, elt_ty, LvalueExpr(lval))
             }
         }
         None => {
@@ -867,7 +868,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             });
             let elt = InBoundsGEP(bcx, base, &[ix_val]);
             let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
-            Datum::new(elt, unit_ty, LvalueExpr)
+            let lval = Lvalue::new("expr::trans_index fallback");
+            Datum::new(elt, unit_ty, LvalueExpr(lval))
         }
     };
 
@@ -912,7 +914,8 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // Case 2.
                 base::get_extern_const(bcx.ccx(), did, const_ty)
             };
-            DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
+            let lval = Lvalue::new("expr::trans_def");
+            DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
         }
         def::DefConst(_) => {
             bcx.sess().span_bug(ref_expr.span,
@@ -1302,8 +1305,9 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         def::DefUpvar(nid, _) => {
             // Can't move upvars, so this is never a ZeroMemLastUse.
             let local_ty = node_id_type(bcx, nid);
+            let lval = Lvalue::upvar("expr::trans_local_var", bcx, nid);
             match bcx.fcx.llupvars.borrow().get(&nid) {
-                Some(&val) => Datum::new(val, local_ty, Lvalue),
+                Some(&val) => Datum::new(val, local_ty, lval),
                 None => {
                     bcx.sess().bug(&format!(
                         "trans_local_var: no llval for upvar {} found",
@@ -2267,7 +2271,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
             if type_is_sized(bcx.tcx(), content_ty) {
                 let ptr = load_ty(bcx, datum.val, datum.ty);
-                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
+                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(datum.kind)))
             } else {
                 // A fat pointer and a DST lvalue have the same representation
                 // just different types. Since there is no temporary for `*e`
@@ -2275,13 +2279,15 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // object code path for running drop glue and free. Instead,
                 // we schedule cleanup for `e`, turning it into an lvalue.
 
-                let datum = Datum::new(datum.val, content_ty, LvalueExpr);
+                let lval = Lvalue::new("expr::deref_once ty_uniq");
+                let datum = Datum::new(datum.val, content_ty, LvalueExpr(lval));
                 DatumBlock::new(bcx, datum)
             }
         }
 
         ty::TyRawPtr(ty::TypeAndMut { ty: content_ty, .. }) |
         ty::TyRef(_, ty::TypeAndMut { ty: content_ty, .. }) => {
+            let lval = Lvalue::new("expr::deref_once ptr");
             if type_is_sized(bcx.tcx(), content_ty) {
                 let ptr = datum.to_llscalarish(bcx);
 
@@ -2290,11 +2296,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // rvalue for non-owning pointers like &T or *T, in which
                 // case cleanup *is* scheduled elsewhere, by the true
                 // owner (or, in the case of *T, by the user).
-                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
+                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(lval)))
             } else {
                 // A fat pointer and a DST lvalue have the same representation
                 // just different types.
-                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr))
+                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr(lval)))
             }
         }