about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/trans/base.rs25
-rw-r--r--src/librustc/middle/trans/callee.rs10
-rw-r--r--src/librustc/middle/trans/cleanup.rs120
-rw-r--r--src/librustc/middle/trans/controlflow.rs12
-rw-r--r--src/librustc/middle/trans/debuginfo.rs78
-rw-r--r--src/librustc/middle/trans/expr.rs70
-rw-r--r--src/librustc/middle/trans/glue.rs34
-rw-r--r--src/librustc/middle/trans/intrinsic.rs2
-rw-r--r--src/librustc/middle/trans/tvec.rs2
-rw-r--r--src/test/debuginfo/borrowed-basic.rs4
10 files changed, 284 insertions, 73 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index cac6a8bbfed..03045777155 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1791,7 +1791,7 @@ pub fn trans_closure(ccx: &CrateContext,
                      body: &ast::Block,
                      llfndecl: ValueRef,
                      param_substs: &param_substs,
-                     id: ast::NodeId,
+                     fn_ast_id: ast::NodeId,
                      _attributes: &[ast::Attribute],
                      arg_types: Vec<ty::t>,
                      output_type: ty::t,
@@ -1811,7 +1811,7 @@ pub fn trans_closure(ccx: &CrateContext,
     let arena = TypedArena::new();
     let fcx = new_fn_ctxt(ccx,
                           llfndecl,
-                          id,
+                          fn_ast_id,
                           has_env,
                           output_type,
                           param_substs,
@@ -1820,7 +1820,9 @@ pub fn trans_closure(ccx: &CrateContext,
     let mut bcx = init_function(&fcx, false, output_type);
 
     // cleanup scope for the incoming arguments
-    let arg_scope = fcx.push_custom_cleanup_scope();
+    let fn_cleanup_debug_loc =
+        debuginfo::get_cleanup_debug_loc_for_ast_node(fn_ast_id, body.span, true);
+    let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);
 
     let block_ty = node_id_type(bcx, body.id);
 
@@ -1969,7 +1971,9 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                                  ctor_ty: ty::t,
                                                  disr: ty::Disr,
                                                  args: callee::CallArgs,
-                                                 dest: expr::Dest) -> Result<'blk, 'tcx> {
+                                                 dest: expr::Dest,
+                                                 call_info: Option<NodeInfo>)
+                                                 -> Result<'blk, 'tcx> {
 
     let ccx = bcx.fcx.ccx;
     let tcx = ccx.tcx();
@@ -1999,8 +2003,13 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         match args {
             callee::ArgExprs(exprs) => {
                 let fields = exprs.iter().map(|x| &**x).enumerate().collect::<Vec<_>>();
-                bcx = expr::trans_adt(bcx, result_ty, disr, fields.as_slice(),
-                                      None, expr::SaveIn(llresult));
+                bcx = expr::trans_adt(bcx,
+                                      result_ty,
+                                      disr,
+                                      fields.as_slice(),
+                                      None,
+                                      expr::SaveIn(llresult),
+                                      call_info);
             }
             _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
         }
@@ -2010,7 +2019,9 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     // drop the temporary we made
     let bcx = match dest {
         expr::SaveIn(_) => bcx,
-        expr::Ignore => glue::drop_ty(bcx, llresult, result_ty)
+        expr::Ignore => {
+            glue::drop_ty(bcx, llresult, result_ty, call_info)
+        }
     };
 
     Result::new(bcx, llresult)
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 53c13f56284..5962bee023a 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -714,8 +714,12 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
             let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
-            return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
-                                                       args, dest.unwrap());
+            return base::trans_named_tuple_constructor(bcx,
+                                                       ctor_ty,
+                                                       disr,
+                                                       args,
+                                                       dest.unwrap(),
+                                                       call_info);
         }
     };
 
@@ -835,7 +839,7 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     match (dest, opt_llretslot) {
         (Some(expr::Ignore), Some(llretslot)) => {
             // drop the value if it is not being saved.
-            bcx = glue::drop_ty(bcx, llretslot, ret_ty);
+            bcx = glue::drop_ty(bcx, llretslot, ret_ty, call_info);
             call_lifetime_end(bcx, llretslot);
         }
         _ => {}
diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs
index cdc0bd76225..35464be0e43 100644
--- a/src/librustc/middle/trans/cleanup.rs
+++ b/src/librustc/middle/trans/cleanup.rs
@@ -18,7 +18,8 @@ use middle::trans::base;
 use middle::trans::build;
 use middle::trans::callee;
 use middle::trans::common;
-use middle::trans::common::{Block, FunctionContext, ExprId};
+use middle::trans::common::{Block, FunctionContext, ExprId, NodeInfo};
+use middle::trans::debuginfo;
 use middle::trans::glue;
 use middle::trans::type_::Type;
 use middle::ty;
@@ -36,6 +37,10 @@ pub struct CleanupScope<'blk, 'tcx: 'blk> {
     // Cleanups to run upon scope exit.
     cleanups: Vec<CleanupObj>,
 
+    // The debug location any drop calls generated for this scope will be
+    // associated with.
+    debug_loc: Option<NodeInfo>,
+
     cached_early_exits: Vec<CachedEarlyExit>,
     cached_landing_pad: Option<BasicBlockRef>,
 }
@@ -69,7 +74,10 @@ pub struct CachedEarlyExit {
 pub trait Cleanup {
     fn must_unwind(&self) -> bool;
     fn clean_on_unwind(&self) -> bool;
-    fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx>;
+    fn trans<'blk, 'tcx>(&self,
+                         bcx: Block<'blk, 'tcx>,
+                         debug_loc: Option<NodeInfo>)
+                      -> Block<'blk, 'tcx>;
 }
 
 pub type CleanupObj = Box<Cleanup+'static>;
@@ -80,14 +88,14 @@ pub enum ScopeId {
 }
 
 impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
-    fn push_ast_cleanup_scope(&self, id: ast::NodeId) {
+    fn push_ast_cleanup_scope(&self, debug_loc: NodeInfo) {
         /*!
          * Invoked when we start to trans the code contained
          * within a new cleanup scope.
          */
 
         debug!("push_ast_cleanup_scope({})",
-               self.ccx.tcx().map.node_to_string(id));
+               self.ccx.tcx().map.node_to_string(debug_loc.id));
 
         // FIXME(#2202) -- currently closure bodies have a parent
         // region, which messes up the assertion below, since there
@@ -101,10 +109,15 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
         // this new AST scope had better be its immediate child.
         let top_scope = self.top_ast_scope();
         if top_scope.is_some() {
-            assert_eq!(self.ccx.tcx().region_maps.opt_encl_scope(id), top_scope);
+            assert_eq!(self.ccx
+                           .tcx()
+                           .region_maps
+                           .opt_encl_scope(debug_loc.id),
+                       top_scope);
         }
 
-        self.push_scope(CleanupScope::new(AstScopeKind(id)));
+        self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),
+                                          Some(debug_loc)));
     }
 
     fn push_loop_cleanup_scope(&self,
@@ -114,13 +127,38 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
                self.ccx.tcx().map.node_to_string(id));
         assert_eq!(Some(id), self.top_ast_scope());
 
-        self.push_scope(CleanupScope::new(LoopScopeKind(id, exits)));
+        // Just copy the debuginfo source location from the enclosing scope
+        let debug_loc = self.scopes
+                            .borrow()
+                            .last()
+                            .unwrap()
+                            .debug_loc;
+
+        self.push_scope(CleanupScope::new(LoopScopeKind(id, exits), debug_loc));
     }
 
     fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
         let index = self.scopes_len();
         debug!("push_custom_cleanup_scope(): {}", index);
-        self.push_scope(CleanupScope::new(CustomScopeKind));
+
+        // Just copy the debuginfo source location from the enclosing scope
+        let debug_loc = self.scopes
+                            .borrow()
+                            .last()
+                            .map(|opt_scope| opt_scope.debug_loc)
+                            .unwrap_or(None);
+
+        self.push_scope(CleanupScope::new(CustomScopeKind, debug_loc));
+        CustomScopeIndex { index: index }
+    }
+
+    fn push_custom_cleanup_scope_with_debug_loc(&self,
+                                                debug_loc: NodeInfo)
+                                                -> CustomScopeIndex {
+        let index = self.scopes_len();
+        debug!("push_custom_cleanup_scope(): {}", index);
+
+        self.push_scope(CleanupScope::new(CustomScopeKind, Some(debug_loc)));
         CustomScopeIndex { index: index }
     }
 
@@ -141,7 +179,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
 
         let scope = self.pop_scope();
         self.trans_scope_cleanups(bcx, &scope)
-
     }
 
     fn pop_loop_cleanup_scope(&self,
@@ -175,9 +212,9 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
     }
 
     fn pop_and_trans_custom_cleanup_scope(&self,
-                                        bcx: Block<'blk, 'tcx>,
-                                        custom_scope: CustomScopeIndex)
-                                        -> Block<'blk, 'tcx> {
+                                          bcx: Block<'blk, 'tcx>,
+                                          custom_scope: CustomScopeIndex)
+                                          -> Block<'blk, 'tcx> {
         /*!
          * Removes the top cleanup scope from the stack, which must be
          * a temporary scope, and generates the code to do its
@@ -503,7 +540,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
         let mut bcx = bcx;
         if !bcx.unreachable.get() {
             for cleanup in scope.cleanups.iter().rev() {
-                bcx = cleanup.trans(bcx);
+                bcx = cleanup.trans(bcx, scope.debug_loc);
             }
         }
         bcx
@@ -671,7 +708,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
                 let mut bcx_out = bcx_in;
                 for cleanup in scope.cleanups.iter().rev() {
                     if cleanup_is_suitable_for(&**cleanup, label) {
-                        bcx_out = cleanup.trans(bcx_out);
+                        bcx_out = cleanup.trans(bcx_out,
+                                                scope.debug_loc);
                     }
                 }
                 build::Br(bcx_out, prev_llbb);
@@ -785,9 +823,12 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
 }
 
 impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> {
-    fn new(kind: CleanupScopeKind<'blk, 'tcx>) -> CleanupScope<'blk, 'tcx> {
+    fn new(kind: CleanupScopeKind<'blk, 'tcx>,
+           debug_loc: Option<NodeInfo>)
+        -> CleanupScope<'blk, 'tcx> {
         CleanupScope {
             kind: kind,
+            debug_loc: debug_loc,
             cleanups: vec!(),
             cached_early_exits: vec!(),
             cached_landing_pad: None,
@@ -902,11 +943,14 @@ impl Cleanup for DropValue {
         self.must_unwind
     }
 
-    fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+    fn trans<'blk, 'tcx>(&self,
+                         bcx: Block<'blk, 'tcx>,
+                         debug_loc: Option<NodeInfo>)
+                         -> Block<'blk, 'tcx> {
         let bcx = if self.is_immediate {
-            glue::drop_ty_immediate(bcx, self.val, self.ty)
+            glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc)
         } else {
-            glue::drop_ty(bcx, self.val, self.ty)
+            glue::drop_ty(bcx, self.val, self.ty, debug_loc)
         };
         if self.zero {
             base::zero_mem(bcx, self.val, self.ty);
@@ -935,7 +979,12 @@ impl Cleanup for FreeValue {
         true
     }
 
-    fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+    fn trans<'blk, 'tcx>(&self,
+                         bcx: Block<'blk, 'tcx>,
+                         debug_loc: Option<NodeInfo>)
+                      -> Block<'blk, 'tcx> {
+        apply_debug_loc(bcx.fcx, debug_loc);
+
         match self.heap {
             HeapManaged => {
                 glue::trans_free(bcx, self.ptr)
@@ -963,7 +1012,12 @@ impl Cleanup for FreeSlice {
         true
     }
 
-    fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+    fn trans<'blk, 'tcx>(&self,
+                         bcx: Block<'blk, 'tcx>,
+                         debug_loc: Option<NodeInfo>)
+                      -> Block<'blk, 'tcx> {
+        apply_debug_loc(bcx.fcx, debug_loc);
+
         match self.heap {
             HeapManaged => {
                 glue::trans_free(bcx, self.ptr)
@@ -988,7 +1042,11 @@ impl Cleanup for LifetimeEnd {
         true
     }
 
-    fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+    fn trans<'blk, 'tcx>(&self,
+                         bcx: Block<'blk, 'tcx>,
+                         debug_loc: Option<NodeInfo>)
+                      -> Block<'blk, 'tcx> {
+        apply_debug_loc(bcx.fcx, debug_loc);
         base::call_lifetime_end(bcx, self.ptr);
         bcx
     }
@@ -1023,15 +1081,29 @@ fn cleanup_is_suitable_for(c: &Cleanup,
     !label.is_unwind() || c.clean_on_unwind()
 }
 
+fn apply_debug_loc(fcx: &FunctionContext, debug_loc: Option<NodeInfo>) {
+    match debug_loc {
+        Some(ref src_loc) => {
+            debuginfo::set_source_location(fcx, src_loc.id, src_loc.span);
+        }
+        None => {
+            debuginfo::clear_source_location(fcx);
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // These traits just exist to put the methods into this file.
 
 pub trait CleanupMethods<'blk, 'tcx> {
-    fn push_ast_cleanup_scope(&self, id: ast::NodeId);
+    fn push_ast_cleanup_scope(&self, id: NodeInfo);
     fn push_loop_cleanup_scope(&self,
-                                   id: ast::NodeId,
-                                   exits: [Block<'blk, 'tcx>, ..EXIT_MAX]);
+                               id: ast::NodeId,
+                               exits: [Block<'blk, 'tcx>, ..EXIT_MAX]);
     fn push_custom_cleanup_scope(&self) -> CustomScopeIndex;
+    fn push_custom_cleanup_scope_with_debug_loc(&self,
+                                                debug_loc: NodeInfo)
+                                                -> CustomScopeIndex;
     fn pop_and_trans_ast_cleanup_scope(&self,
                                               bcx: Block<'blk, 'tcx>,
                                               cleanup_scope: ast::NodeId)
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 5bba188fac7..424007519af 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -22,6 +22,7 @@ use middle::trans::cleanup;
 use middle::trans::common::*;
 use middle::trans::consts;
 use middle::trans::datum;
+use middle::trans::debuginfo;
 use middle::trans::expr;
 use middle::trans::meth;
 use middle::trans::type_::Type;
@@ -53,7 +54,9 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     let mut bcx = cx;
 
     let id = ast_util::stmt_id(s);
-    fcx.push_ast_cleanup_scope(id);
+    let cleanup_debug_loc =
+        debuginfo::get_cleanup_debug_loc_for_ast_node(id, s.span, false);
+    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
 
     match s.node {
         ast::StmtExpr(ref e, _) | ast::StmtSemi(ref e, _) => {
@@ -75,8 +78,7 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
         ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
     }
 
-    bcx = fcx.pop_and_trans_ast_cleanup_scope(
-        bcx, ast_util::stmt_id(s));
+    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, ast_util::stmt_id(s));
 
     return bcx;
 }
@@ -100,7 +102,9 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let fcx = bcx.fcx;
     let mut bcx = bcx;
 
-    fcx.push_ast_cleanup_scope(b.id);
+    let cleanup_debug_loc =
+        debuginfo::get_cleanup_debug_loc_for_ast_node(b.id, b.span, true);
+    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
 
     for s in b.stmts.iter() {
         bcx = trans_stmt(bcx, &**s);
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 1980d67fc47..7a0e5aea7ff 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -1030,6 +1030,55 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
     })
 }
 
+pub fn get_cleanup_debug_loc_for_ast_node(node_id: ast::NodeId,
+                                          node_span: Span,
+                                          is_block: bool)
+                                          -> NodeInfo {
+    // A debug location needs two things:
+    // (1) A span (of which only the beginning will actually be used)
+    // (2) An AST node-id which will be used to look up the lexical scope
+    //     for the location in the functions scope-map
+    //
+    // This function will calculate the debug location for compiler-generated
+    // cleanup calls that are executed when control-flow leaves the
+    // scope identified by `node_id`.
+    //
+    // For everything but block-like things we can simply take id and span of
+    // the given expression, meaning that from a debugger's view cleanup code is
+    // executed at the same source location as the statement/expr itself.
+    //
+    // Blocks are a special case. Here we want the cleanup to be linked to the
+    // closing curly brace of the block. The *scope* the cleanup is executed in
+    // is up to debate: It could either still be *within* the block being
+    // cleaned up, meaning that locals from the block are still visible in the
+    // debugger.
+    // Or it could be in the scope that the block is contained in, so any locals
+    // from within the block are already considered out-of-scope and thus not
+    // accessible in the debugger anymore.
+    //
+    // The current implementation opts for the second option: cleanup of a block
+    // already happens in the parent scope of the block. The main reason for
+    // this decision is that scoping becomes controlflow dependent when variable
+    // shadowing is involved and it's impossible to decide statically which
+    // scope is actually left when the cleanup code is executed.
+    // In practice it shouldn't make much of a difference.
+
+    let cleanup_span = if is_block {
+        Span {
+            lo: node_span.hi - codemap::BytePos(1), // closing brace should always be 1 byte...
+            hi: node_span.hi,
+            expn_id: node_span.expn_id
+        }
+    } else {
+        node_span
+    };
+
+    NodeInfo {
+        id: node_id,
+        span: cleanup_span
+    }
+}
+
 /// Sets the current debug location at the beginning of the span.
 ///
 /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). The node_id
@@ -1107,7 +1156,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
     // Do this here already, in case we do an early exit from this function.
     set_debug_location(cx, UnknownLocation);
 
-    if fn_ast_id == -1 {
+    if fn_ast_id == ast::DUMMY_NODE_ID {
+        // This is a function not linked to any source location, so don't
+        // generate debuginfo for it.
         return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
     }
 
@@ -1289,6 +1340,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
                        fn_decl.inputs.as_slice(),
                        &*top_level_block,
                        fn_metadata,
+                       fn_ast_id,
                        &mut *fn_debug_context.scope_map.borrow_mut());
 
     return FunctionDebugContext { repr: DebugInfo(fn_debug_context) };
@@ -1297,7 +1349,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
                               fn_ast_id: ast::NodeId,
                               fn_decl: &ast::FnDecl,
                               param_substs: &param_substs,
-                              error_span: Span) -> DIArray {
+                              error_reporting_span: Span) -> DIArray {
         if cx.sess().opts.debuginfo == LimitedDebugInfo {
             return create_DIArray(DIB(cx), []);
         }
@@ -1310,7 +1362,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
                 signature.push(ptr::null_mut());
             }
             _ => {
-                assert_type_for_node_id(cx, fn_ast_id, error_span);
+                assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
 
                 let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
                 let return_type = return_type.substp(cx.tcx(), param_substs);
@@ -1634,15 +1686,17 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile {
 /// Finds the scope metadata node for the given AST node.
 fn scope_metadata(fcx: &FunctionContext,
                   node_id: ast::NodeId,
-                  span: Span)
+                  error_reporting_span: Span)
                -> DIScope {
-    let scope_map = &fcx.debug_context.get_ref(fcx.ccx, span).scope_map;
+    let scope_map = &fcx.debug_context
+                        .get_ref(fcx.ccx, error_reporting_span)
+                        .scope_map;
     match scope_map.borrow().find_copy(&node_id) {
         Some(scope_metadata) => scope_metadata,
         None => {
             let node = fcx.ccx.tcx().map.get(node_id);
 
-            fcx.ccx.sess().span_bug(span,
+            fcx.ccx.sess().span_bug(error_reporting_span,
                 format!("debuginfo: Could not find scope info for node {:?}",
                         node).as_slice());
         }
@@ -3139,9 +3193,12 @@ fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
     }
 }
 
-fn assert_type_for_node_id(cx: &CrateContext, node_id: ast::NodeId, error_span: Span) {
+fn assert_type_for_node_id(cx: &CrateContext,
+                           node_id: ast::NodeId,
+                           error_reporting_span: Span) {
     if !cx.tcx().node_types.borrow().contains_key(&(node_id as uint)) {
-        cx.sess().span_bug(error_span, "debuginfo: Could not find type for node id!");
+        cx.sess().span_bug(error_reporting_span,
+                           "debuginfo: Could not find type for node id!");
     }
 }
 
@@ -3169,6 +3226,7 @@ fn populate_scope_map(cx: &CrateContext,
                       args: &[ast::Arg],
                       fn_entry_block: &ast::Block,
                       fn_metadata: DISubprogram,
+                      fn_ast_id: ast::NodeId,
                       scope_map: &mut HashMap<ast::NodeId, DIScope>) {
     let def_map = &cx.tcx().def_map;
 
@@ -3179,13 +3237,15 @@ fn populate_scope_map(cx: &CrateContext,
 
     let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata,
                                                  ident: None });
+    scope_map.insert(fn_ast_id, fn_metadata);
 
     // Push argument identifiers onto the stack so arguments integrate nicely
     // with variable shadowing.
     for arg in args.iter() {
-        pat_util::pat_bindings(def_map, &*arg.pat, |_, _, _, path1| {
+        pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
             scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
                                                ident: Some(path1.node) });
+            scope_map.insert(node_id, fn_metadata);
         })
     }
 
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 75c28477414..120e8404f2c 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -119,10 +119,13 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
-    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
 
-    bcx.fcx.push_ast_cleanup_scope(expr.id);
+    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
+                                                                          expr.span,
+                                                                          false);
+    bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
 
+    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
     let kind = ty::expr_kind(bcx.tcx(), expr);
     bcx = match kind {
         ty::LvalueExpr | ty::RvalueDatumExpr => {
@@ -154,7 +157,10 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
     let fcx = bcx.fcx;
 
-    fcx.push_ast_cleanup_scope(expr.id);
+    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
+                                                                          expr.span,
+                                                                          false);
+    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
     let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
     let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
     bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
@@ -644,7 +650,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             match x.node {
                 ast::ExprRepeat(..) | ast::ExprVec(..) => {
                     // Special case for slices.
-                    fcx.push_ast_cleanup_scope(x.id);
+                    let cleanup_debug_loc =
+                        debuginfo::get_cleanup_debug_loc_for_ast_node(x.id, x.span, false);
+                    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
                     let datum = unpack_datum!(
                         bcx, tvec::trans_slice_vec(bcx, expr, &**x));
                     bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
@@ -908,6 +916,8 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         return bcx;
     }
 
+    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
+
     match expr.node {
         ast::ExprParen(ref e) => {
             trans_into(bcx, &**e, Ignore)
@@ -954,10 +964,14 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 //
                 // We could avoid this intermediary with some analysis
                 // to determine whether `dst` may possibly own `src`.
+                debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
                 let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
                 let src_datum = unpack_datum!(
                     bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
-                bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
+                bcx = glue::drop_ty(bcx,
+                                    dst_datum.val,
+                                    dst_datum.ty,
+                                    Some(NodeInfo { id: expr.id, span: expr.span }));
                 src_datum.store_to(bcx, dst_datum.val)
             } else {
                 trans_into(bcx, &**src, SaveIn(dst_datum.to_llref()))
@@ -987,6 +1001,8 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
     let tcx = bcx.tcx();
 
+    debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
+
     match expr.node {
         ast::ExprParen(ref e) => {
             trans_into(bcx, &**e, dest)
@@ -1014,7 +1030,13 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprTup(ref args) => {
             let numbered_fields: Vec<(uint, &ast::Expr)> =
                 args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
-            trans_adt(bcx, expr_ty(bcx, expr), 0, numbered_fields.as_slice(), None, dest)
+            trans_adt(bcx,
+                      expr_ty(bcx, expr),
+                      0,
+                      numbered_fields.as_slice(),
+                      None,
+                      dest,
+                      Some(NodeInfo { id: expr.id, span: expr.span }))
         }
         ast::ExprLit(ref lit) => {
             match lit.node {
@@ -1297,15 +1319,15 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
 
 fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             fields: &[ast::Field],
-                       base: Option<&ast::Expr>,
+                            base: Option<&ast::Expr>,
                             expr_span: codemap::Span,
-                            id: ast::NodeId,
+                            expr_id: ast::NodeId,
                             dest: Dest) -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_rec");
 
-    let ty = node_id_type(bcx, id);
+    let ty = node_id_type(bcx, expr_id);
     let tcx = bcx.tcx();
-    with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
+    with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| {
         let mut need_base = Vec::from_elem(field_tys.len(), true);
 
         let numbered_fields = fields.iter().map(|field| {
@@ -1342,7 +1364,13 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
         };
 
-        trans_adt(bcx, ty, discr, numbered_fields.as_slice(), optbase, dest)
+        trans_adt(bcx,
+                  ty,
+                  discr,
+                  numbered_fields.as_slice(),
+                  optbase,
+                  dest,
+                  Some(NodeInfo { id: expr_id, span: expr_span }))
     })
 }
 
@@ -1376,11 +1404,20 @@ pub fn trans_adt<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                              discr: ty::Disr,
                              fields: &[(uint, &ast::Expr)],
                              optbase: Option<StructBaseInfo>,
-                             dest: Dest) -> Block<'blk, 'tcx> {
+                             dest: Dest,
+                             source_location: Option<NodeInfo>)
+                          -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_adt");
     let fcx = bcx.fcx;
     let repr = adt::represent_type(bcx.ccx(), ty);
 
+    match source_location {
+        Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
+                                                        src_loc.id,
+                                                        src_loc.span),
+        None => {}
+    };
+
     // If we don't care about the result, just make a
     // temporary stack slot
     let addr = match dest {
@@ -1414,6 +1451,13 @@ pub fn trans_adt<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     }
 
+    match source_location {
+        Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
+                                                        src_loc.id,
+                                                        src_loc.span),
+        None => {}
+    };
+
     // Now, we just overwrite the fields we've explicitly specified
     for &(i, ref e) in fields.iter() {
         let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
@@ -1432,7 +1476,7 @@ pub fn trans_adt<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     match dest {
         SaveIn(_) => bcx,
         Ignore => {
-            bcx = glue::drop_ty(bcx, addr, ty);
+            bcx = glue::drop_ty(bcx, addr, ty, source_location);
             base::call_lifetime_end(bcx, addr);
             bcx
         }
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index fa2b192615d..c8cc89ca66a 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -28,6 +28,7 @@ use middle::trans::cleanup;
 use middle::trans::cleanup::CleanupMethods;
 use middle::trans::common::*;
 use middle::trans::datum;
+use middle::trans::debuginfo;
 use middle::trans::expr;
 use middle::trans::machine::*;
 use middle::trans::reflect;
@@ -125,7 +126,10 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
     }
 }
 
-pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
+pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                           v: ValueRef,
+                           t: ty::t,
+                           source_location: Option<NodeInfo>)
                            -> Block<'blk, 'tcx> {
     // NB: v is an *alias* of type t here, not a direct value.
     debug!("drop_ty(t={})", t.repr(bcx.tcx()));
@@ -139,17 +143,26 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
         } else {
             v
         };
+
+        match source_location {
+            Some(sl) => debuginfo::set_source_location(bcx.fcx, sl.id, sl.span),
+            None => debuginfo::clear_source_location(bcx.fcx)
+        };
+
         Call(bcx, glue, [ptr], None);
     }
     bcx
 }
 
-pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
+pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                     v: ValueRef,
+                                     t: ty::t,
+                                     source_location: Option<NodeInfo>)
                                      -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("drop_ty_immediate");
     let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
     Store(bcx, v, vp);
-    drop_ty(bcx, vp, t)
+    drop_ty(bcx, vp, t, source_location)
 }
 
 pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
@@ -464,7 +477,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
                     let llbox = Load(bcx, llval);
                     let not_null = IsNotNull(bcx, llbox);
                     with_cond(bcx, not_null, |bcx| {
-                        let bcx = drop_ty(bcx, v0, content_ty);
+                        let bcx = drop_ty(bcx, v0, content_ty, None);
                         let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
                         let info = Load(bcx, info);
                         let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
@@ -477,7 +490,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
                     let llbox = Load(bcx, llval);
                     let not_null = IsNotNull(bcx, llbox);
                     with_cond(bcx, not_null, |bcx| {
-                        let bcx = drop_ty(bcx, llbox, content_ty);
+                        let bcx = drop_ty(bcx, llbox, content_ty, None);
                         trans_exchange_free_ty(bcx, llbox, content_ty)
                     })
                 }
@@ -508,11 +521,14 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
                 }
                 ty::NoDtor => {
                     // No dtor? Just the default case
-                    iter_structural_ty(bcx, v0, t, drop_ty)
+                    iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
                 }
             }
         }
-        ty::ty_unboxed_closure(..) => iter_structural_ty(bcx, v0, t, drop_ty),
+        ty::ty_unboxed_closure(..) => iter_structural_ty(bcx,
+                                                         v0,
+                                                         t,
+                                                         |bb, vv, tt| drop_ty(bb, vv, tt, None)),
         ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
             let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
             let env = Load(bcx, box_cell_v);
@@ -544,7 +560,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
             assert!(ty::type_is_sized(bcx.tcx(), t));
             if ty::type_needs_drop(bcx.tcx(), t) &&
                 ty::type_is_structural(t) {
-                iter_structural_ty(bcx, v0, t, drop_ty)
+                iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
             } else {
                 bcx
             }
@@ -574,7 +590,7 @@ fn decr_refcnt_maybe_free<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let v = Load(free_bcx, box_ptr_ptr);
     let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
-    let free_bcx = drop_ty(free_bcx, body, t);
+    let free_bcx = drop_ty(free_bcx, body, t, None);
     let free_bcx = trans_free(free_bcx, v);
     Br(free_bcx, next_bcx.llbb);
 
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 3b3d7d02a2c..628971775ae 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -541,7 +541,7 @@ pub fn trans_intrinsic_call<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, node: ast::N
     // If we made a temporary stack slot, let's clean it up
     match dest {
         expr::Ignore => {
-            bcx = glue::drop_ty(bcx, llresult, ret_ty);
+            bcx = glue::drop_ty(bcx, llresult, ret_ty, Some(call_info));
         }
         expr::SaveIn(_) => {}
     }
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index f5c3ed388b7..848e59e2a60 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -64,7 +64,7 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let dataptr = get_dataptr(bcx, vptr);
         let bcx = if ty::type_needs_drop(tcx, unit_ty) {
             let len = get_len(bcx, vptr);
-            iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
+            iter_vec_raw(bcx, dataptr, unit_ty, len, |bb, vv, tt| glue::drop_ty(bb, vv, tt, None))
         } else {
             bcx
         };
diff --git a/src/test/debuginfo/borrowed-basic.rs b/src/test/debuginfo/borrowed-basic.rs
index 84610b3c740..dae14a1be2b 100644
--- a/src/test/debuginfo/borrowed-basic.rs
+++ b/src/test/debuginfo/borrowed-basic.rs
@@ -130,8 +130,8 @@ fn main() {
     let i32_val: i32 = -32;
     let i32_ref: &i32 = &i32_val;
 
-    let uint_val: i64 = -64;
-    let i64_ref: &i64 = &uint_val;
+    let i64_val: i64 = -64;
+    let i64_ref: &i64 = &i64_val;
 
     let uint_val: uint = 1;
     let uint_ref: &uint = &uint_val;