]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
authorMichael Woerister <michaelwoerister@posteo>
Wed, 24 Sep 2014 06:49:38 +0000 (08:49 +0200)
committerMichael Woerister <michaelwoerister@posteo>
Thu, 25 Sep 2014 12:17:14 +0000 (14:17 +0200)
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.

Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.

Fixes #17201
Fixes #15816
Fixes #15156

src/librustc/middle/trans/base.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/cleanup.rs
src/librustc/middle/trans/controlflow.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/glue.rs
src/librustc/middle/trans/intrinsic.rs
src/librustc/middle/trans/tvec.rs
src/test/debuginfo/borrowed-basic.rs

index cac6a8bbfed4cd370ebbe2d63c4a75c566160e5d..03045777155d411c6c13af4438d9fb58d61c8488 100644 (file)
@@ -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)
index 53c13f5628455864fee4c8e36546284165f92085..5962bee023abcd7ca6c9e6477e04167db9926d75 100644 (file)
@@ -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);
         }
         _ => {}
index cdc0bd76225aa62de759177f2c33af36b4eed7de..35464be0e43125e8aaea5f49da8b1768b9e02326 100644 (file)
@@ -18,7 +18,8 @@
 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 @@ fn push_ast_cleanup_scope(&self, id: ast::NodeId) {
         // 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 @@ fn push_loop_cleanup_scope(&self,
                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 @@ fn pop_and_trans_ast_cleanup_scope(&self,
 
         let scope = self.pop_scope();
         self.trans_scope_cleanups(bcx, &scope)
-
     }
 
     fn pop_loop_cleanup_scope(&self,
@@ -175,9 +212,9 @@ fn pop_custom_cleanup_scope(&self,
     }
 
     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 @@ fn trans_scope_cleanups(&self, // cannot borrow self, will recurse
         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 @@ fn trans_cleanups_to_exit_scope(&'blk self,
                 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 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
 }
 
 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 @@ fn clean_on_unwind(&self) -> bool {
         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 @@ fn clean_on_unwind(&self) -> bool {
         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 @@ fn clean_on_unwind(&self) -> bool {
         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 @@ fn clean_on_unwind(&self) -> bool {
         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)
index 5bba188fac7bfbac5aae15b3bc0c1d0ac6b35bb6..424007519af1ad93feb0cb6aa12b40f52c7571dc 100644 (file)
@@ -22,6 +22,7 @@
 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);
index 1980d67fc47146cb577f081af9acf12c6acff6dd..7a0e5aea7fffc90873080de035f44d9f64a5cc53 100644 (file)
@@ -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 @@ fn get_function_signature(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 @@ fn get_function_signature(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 @@ struct ScopeStackEntry {
 
     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);
         })
     }
 
index 75c28477414a92309395079ece1abe56f3a61d05..120e8404f2c67502671aa2be8fdd383d4c5e698b 100644 (file)
@@ -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
         }
index fa2b192615d878990dfdf1c40ca54ec1085668df..c8cc89ca66a2066804227c8a5f6aff913f34c207 100644 (file)
@@ -28,6 +28,7 @@
 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);
 
index 3b3d7d02a2c8a7c47a8e254ee62f516620bd39bb..628971775ae8ce42fcf2ef9d38ca3bc748838ce4 100644 (file)
@@ -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(_) => {}
     }
index f5c3ed388b7f9af7c80d2ffb88ca272de3ada0a3..848e59e2a60d8dff822bb5d63e01b27c0fe6ed33 100644 (file)
@@ -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
         };
index 84610b3c740517985ccc26b59eeafb29be0fa468..dae14a1be2b156ef2108c9d82d9f49761ce10d38 100644 (file)
@@ -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;