debuginfo: Add support for argument shadowing.
This commit is contained in:
parent
33e7d95e9c
commit
9c7d9eb6fd
3 changed files with 110 additions and 36 deletions
|
|
@ -230,8 +230,6 @@ pub struct FunctionContext {
|
|||
ccx: @mut CrateContext,
|
||||
|
||||
// Used and maintained by the debuginfo module.
|
||||
// @jdm: Not sure if the Option-wrapper is a good idea. It allows to save some space in
|
||||
// non-debug builds, but generates quite a bit of noise at usage sites. What's your opinion?
|
||||
debug_context: Option<~debuginfo::FunctionDebugContext>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,11 +271,11 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
|
|||
let cx = fcx.ccx;
|
||||
|
||||
let fnitem = cx.tcx.items.get_copy(&fcx.id);
|
||||
let (ident, ret_ty, id) = match fnitem {
|
||||
let (ident, fn_decl, id) = match fnitem {
|
||||
ast_map::node_item(ref item, _) => {
|
||||
match item.node {
|
||||
ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => {
|
||||
(item.ident, ty, item.id)
|
||||
ast::item_fn(ref fn_decl, _, _, _, _) => {
|
||||
(item.ident, fn_decl, item.id)
|
||||
}
|
||||
_ => fcx.ccx.sess.span_bug(item.span,
|
||||
"create_function_metadata: item bound to non-function")
|
||||
|
|
@ -283,20 +283,20 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
|
|||
}
|
||||
ast_map::node_method(
|
||||
@ast::method {
|
||||
decl: ast::fn_decl { output: ref ty, _ },
|
||||
decl: ref fn_decl,
|
||||
id: id,
|
||||
ident: ident,
|
||||
_
|
||||
},
|
||||
_,
|
||||
_) => {
|
||||
(ident, ty, id)
|
||||
(ident, fn_decl, id)
|
||||
}
|
||||
ast_map::node_expr(ref expr) => {
|
||||
match expr.node {
|
||||
ast::expr_fn_block(ref decl, _) => {
|
||||
ast::expr_fn_block(ref fn_decl, _) => {
|
||||
let name = gensym_name("fn");
|
||||
(name, &decl.output, expr.id)
|
||||
(name, fn_decl, expr.id)
|
||||
}
|
||||
_ => fcx.ccx.sess.span_bug(expr.span,
|
||||
"create_function_metadata: expected an expr_fn_block here")
|
||||
|
|
@ -305,14 +305,14 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
|
|||
ast_map::node_trait_method(
|
||||
@ast::provided(
|
||||
@ast::method {
|
||||
decl: ast::fn_decl { output: ref ty, _ },
|
||||
decl: ref fn_decl,
|
||||
id: id,
|
||||
ident: ident,
|
||||
_
|
||||
}),
|
||||
_,
|
||||
_) => {
|
||||
(ident, ty, id)
|
||||
(ident, fn_decl, id)
|
||||
}
|
||||
_ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
|
||||
};
|
||||
|
|
@ -335,9 +335,9 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
|
|||
let file_metadata = file_metadata(cx, loc.file.name);
|
||||
|
||||
let return_type_metadata = if cx.sess.opts.extra_debuginfo {
|
||||
match ret_ty.node {
|
||||
match fn_decl.output.node {
|
||||
ast::ty_nil => ptr::null(),
|
||||
_ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span)
|
||||
_ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), fn_decl.output.span)
|
||||
}
|
||||
} else {
|
||||
ptr::null()
|
||||
|
|
@ -382,7 +382,9 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
|
|||
match *entry_block {
|
||||
ast_map::node_block(ref block) => {
|
||||
let scope_map = &mut fn_debug_context.scope_map;
|
||||
populate_scope_map(cx, block, fn_metadata, scope_map);
|
||||
let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
|
||||
|
||||
populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
|
||||
}
|
||||
_ => cx.sess.span_bug(span,
|
||||
fmt!("debuginfo::create_function_metadata() - \
|
||||
|
|
@ -1278,9 +1280,11 @@ fn DIB(cx: &CrateContext) -> DIBuilderRef {
|
|||
// descriptors where necessary. These artificial scopes allow GDB to correctly handle name
|
||||
// shadowing.
|
||||
fn populate_scope_map(cx: &mut CrateContext,
|
||||
arg_pats: &[@ast::pat],
|
||||
fn_entry_block: &ast::Block,
|
||||
fn_metadata: DISubprogram,
|
||||
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
|
||||
let def_map = cx.tcx.def_map;
|
||||
|
||||
struct ScopeStackEntry {
|
||||
scope_metadata: DIScope,
|
||||
|
|
@ -1289,6 +1293,15 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
|
||||
let mut scope_stack = ~[ScopeStackEntry { scope_metadata: fn_metadata, ident: None }];
|
||||
|
||||
// Push argument identifiers onto the stack so arguments integrate nicely with variable
|
||||
// shadowing.
|
||||
for &arg_pat in arg_pats.iter() {
|
||||
do pat_util::pat_bindings(def_map, arg_pat) |_, _, _, path_ref| {
|
||||
let ident = ast_util::path_to_ident(path_ref);
|
||||
scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata, ident: Some(ident) });
|
||||
}
|
||||
}
|
||||
|
||||
walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
|
||||
|
||||
// local helper functions for walking the AST.
|
||||
|
|
@ -1300,7 +1313,6 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
inner_walk: &fn(&mut CrateContext,
|
||||
&mut ~[ScopeStackEntry],
|
||||
&mut HashMap<ast::NodeId, DIScope>)) {
|
||||
|
||||
// Create a new lexical scope and push it onto the stack
|
||||
let loc = cx.sess.codemap.lookup_char_pos(scope_span.lo);
|
||||
let file_metadata = file_metadata(cx, loc.file.name);
|
||||
|
|
@ -1335,7 +1347,6 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
block: &ast::Block,
|
||||
scope_stack: &mut ~[ScopeStackEntry],
|
||||
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
|
||||
|
||||
scope_map.insert(block.id, scope_stack.last().scope_metadata);
|
||||
|
||||
// The interesting things here are statements and the concluding expression.
|
||||
|
|
@ -1361,7 +1372,6 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
|
||||
match *decl {
|
||||
codemap::spanned { node: ast::decl_local(@ref local), _ } => {
|
||||
|
||||
scope_map.insert(local.id, scope_stack.last().scope_metadata);
|
||||
|
||||
walk_pattern(cx, local.pat, scope_stack, scope_map);
|
||||
|
|
@ -1383,7 +1393,7 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
|
||||
// Unfortunately, we cannot just use pat_util::pat_bindings() or ast_util::walk_pat() here
|
||||
// because we have to visit *all* nodes in order to put them into the scope map. The above
|
||||
// function don't do that.
|
||||
// functions don't do that.
|
||||
match pat.node {
|
||||
ast::pat_ident(_, ref path_ref, ref sub_pat_opt) => {
|
||||
|
||||
|
|
@ -1412,9 +1422,8 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
|
||||
// Is there already a binding with that name?
|
||||
let need_new_scope = scope_stack
|
||||
.rev_iter()
|
||||
.find_(|entry| entry.ident.iter().any(|i| *i == ident))
|
||||
.is_some();
|
||||
.iter()
|
||||
.any(|entry| entry.ident.iter().any(|i| *i == ident));
|
||||
|
||||
if need_new_scope {
|
||||
// Create a new lexical scope and push it onto the stack
|
||||
|
|
@ -1574,8 +1583,10 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
ast::expr_if(@ref cond_exp, ref then_block, ref opt_else_exp) => {
|
||||
walk_expr(cx, cond_exp, scope_stack, scope_map);
|
||||
|
||||
do with_new_scope(cx, then_block.span, scope_stack, scope_map) |c, s, m| {
|
||||
walk_block(c, then_block, s, m);
|
||||
do with_new_scope(cx, then_block.span, scope_stack, scope_map) |cx,
|
||||
scope_stack,
|
||||
scope_map| {
|
||||
walk_block(cx, then_block, scope_stack, scope_map);
|
||||
}
|
||||
|
||||
match *opt_else_exp {
|
||||
|
|
@ -1587,8 +1598,10 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
ast::expr_while(@ref cond_exp, ref loop_body) => {
|
||||
walk_expr(cx, cond_exp, scope_stack, scope_map);
|
||||
|
||||
do with_new_scope(cx, loop_body.span, scope_stack, scope_map) |c, s, m| {
|
||||
walk_block(c, loop_body, s, m);
|
||||
do with_new_scope(cx, loop_body.span, scope_stack, scope_map) |cx,
|
||||
scope_stack,
|
||||
scope_map| {
|
||||
walk_block(cx, loop_body, scope_stack, scope_map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1604,20 +1617,22 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
|
||||
ast::expr_loop(ref block, _) |
|
||||
ast::expr_block(ref block) => {
|
||||
do with_new_scope(cx, block.span, scope_stack, scope_map) |c, s, m| {
|
||||
walk_block(c, block, s, m);
|
||||
do with_new_scope(cx, block.span, scope_stack, scope_map) |cx,
|
||||
scope_stack,
|
||||
scope_map| {
|
||||
walk_block(cx, block, scope_stack, scope_map);
|
||||
}
|
||||
}
|
||||
|
||||
ast::expr_fn_block(ast::fn_decl { inputs: ref inputs, _ }, ref block) => {
|
||||
|
||||
do with_new_scope(cx, block.span, scope_stack, scope_map) |c, s, m| {
|
||||
|
||||
do with_new_scope(cx, block.span, scope_stack, scope_map) |cx,
|
||||
scope_stack,
|
||||
scope_map| {
|
||||
for &ast::arg { pat: pattern, _ } in inputs.iter() {
|
||||
walk_pattern(c, pattern, s, m);
|
||||
walk_pattern(cx, pattern, scope_stack, scope_map);
|
||||
}
|
||||
|
||||
walk_block(c, block, s, m);
|
||||
walk_block(cx, block, scope_stack, scope_map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1663,14 +1678,16 @@ fn populate_scope_map(cx: &mut CrateContext,
|
|||
for arm_ref in arms.iter() {
|
||||
let arm_span = arm_ref.pats[0].span;
|
||||
|
||||
do with_new_scope(cx, arm_span, scope_stack, scope_map) |c, s, m| {
|
||||
walk_pattern(c, arm_ref.pats[0], s, m);
|
||||
do with_new_scope(cx, arm_span, scope_stack, scope_map) |cx,
|
||||
scope_stack,
|
||||
scope_map| {
|
||||
walk_pattern(cx, arm_ref.pats[0], scope_stack, scope_map);
|
||||
|
||||
for &@ref guard_exp in arm_ref.guard.iter() {
|
||||
walk_expr(c, guard_exp, s, m)
|
||||
walk_expr(cx, guard_exp, scope_stack, scope_map)
|
||||
}
|
||||
|
||||
walk_block(c, &arm_ref.body, s, m);
|
||||
walk_block(cx, &arm_ref.body, scope_stack, scope_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
src/test/debug-info/shadowed-argument.rs
Normal file
59
src/test/debug-info/shadowed-argument.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
|
||||
|
||||
// compile-flags:-Z extra-debug-info
|
||||
// debugger:break zzz
|
||||
// debugger:run
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$1 = false
|
||||
// debugger:print y
|
||||
// check:$2 = true
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$3 = 10
|
||||
// debugger:print y
|
||||
// check:$4 = true
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$5 = 10.5
|
||||
// debugger:print y
|
||||
// check:$6 = 20
|
||||
// debugger:continue
|
||||
|
||||
fn a_function(x: bool, y: bool) {
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
let x = 10;
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
let x = 10.5;
|
||||
let y = 20;
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a_function(false, true);
|
||||
}
|
||||
|
||||
fn zzz() {()}
|
||||
fn sentinel() {()}
|
||||
Loading…
Add table
Add a link
Reference in a new issue