diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index cac6a8bbfed4..03045777155d 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: ¶m_substs, - id: ast::NodeId, + fn_ast_id: ast::NodeId, _attributes: &[ast::Attribute], arg_types: Vec, 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) + -> 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::>(); - 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 53c13f562845..5962bee023ab 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 cdc0bd76225a..35464be0e431 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, + // The debug location any drop calls generated for this scope will be + // associated with. + debug_loc: Option, + cached_early_exits: Vec, cached_landing_pad: Option, } @@ -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) + -> Block<'blk, 'tcx>; } pub type CleanupObj = Box; @@ -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) + -> 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) + -> 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) + -> 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) + -> 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) + -> 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) { + 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 5bba188fac7b..424007519af1 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 1980d67fc471..7a0e5aea7fff 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: ¶m_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) { 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 75c28477414a..120e8404f2c6 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(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, - dest: Dest) -> Block<'blk, 'tcx> { + dest: Dest, + source_location: Option) + -> 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 fa2b192615d8..c8cc89ca66a2 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) -> 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) -> 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 3b3d7d02a2c8..628971775ae8 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 f5c3ed388b7f..848e59e2a60d 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 84610b3c7405..dae14a1be2b1 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;