debuginfo: Implemented proper handling of lexical scopes and variable shadowing.

This commit is contained in:
Michael Woerister 2013-08-05 11:12:40 +02:00
parent 4601ea65f8
commit 33e7d95e9c
16 changed files with 1874 additions and 146 deletions

View File

@ -214,6 +214,7 @@ use middle::trans::expr;
use middle::trans::glue; use middle::trans::glue;
use middle::trans::tvec; use middle::trans::tvec;
use middle::trans::type_of; use middle::trans::type_of;
use middle::trans::debuginfo;
use middle::ty; use middle::ty;
use util::common::indenter; use util::common::indenter;
use util::ppaux::{Repr, vec_map_to_str}; use util::ppaux::{Repr, vec_map_to_str};
@ -385,6 +386,7 @@ struct BindingInfo {
llmatch: ValueRef, llmatch: ValueRef,
trmode: TransBindingMode, trmode: TransBindingMode,
id: ast::NodeId, id: ast::NodeId,
span: span,
ty: ty::t, ty: ty::t,
} }
@ -1305,7 +1307,7 @@ fn insert_lllocals(bcx: @mut Block,
BindArgument => bcx.fcx.llargs BindArgument => bcx.fcx.llargs
}; };
for (_, &binding_info) in bindings_map.iter() { for (&ident, &binding_info) in bindings_map.iter() {
let llval = match binding_info.trmode { let llval = match binding_info.trmode {
// By value bindings: use the stack slot that we // By value bindings: use the stack slot that we
// copied/moved the value into // copied/moved the value into
@ -1325,6 +1327,14 @@ fn insert_lllocals(bcx: @mut Block,
debug!("binding %? to %s", binding_info.id, bcx.val_to_str(llval)); debug!("binding %? to %s", binding_info.id, bcx.val_to_str(llval));
llmap.insert(binding_info.id, llval); llmap.insert(binding_info.id, llval);
if bcx.sess().opts.extra_debuginfo {
debuginfo::create_match_binding_metadata(bcx,
ident,
binding_info.id,
binding_info.ty,
binding_info.span);
}
} }
return bcx; return bcx;
} }
@ -1771,7 +1781,7 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::pat) -> BindingsMap {
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let tcx = bcx.tcx(); let tcx = bcx.tcx();
let mut bindings_map = HashMap::new(); let mut bindings_map = HashMap::new();
do pat_bindings(tcx.def_map, pat) |bm, p_id, _s, path| { do pat_bindings(tcx.def_map, pat) |bm, p_id, span, path| {
let ident = path_to_ident(path); let ident = path_to_ident(path);
let variable_ty = node_id_type(bcx, p_id); let variable_ty = node_id_type(bcx, p_id);
let llvariable_ty = type_of::type_of(ccx, variable_ty); let llvariable_ty = type_of::type_of(ccx, variable_ty);
@ -1793,8 +1803,11 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::pat) -> BindingsMap {
} }
}; };
bindings_map.insert(ident, BindingInfo { bindings_map.insert(ident, BindingInfo {
llmatch: llmatch, trmode: trmode, llmatch: llmatch,
id: p_id, ty: variable_ty trmode: trmode,
id: p_id,
span: span,
ty: variable_ty
}); });
} }
return bindings_map; return bindings_map;

View File

@ -1103,7 +1103,6 @@ pub fn trans_stmt(cx: @mut Block, s: &ast::stmt) -> @mut Block {
} }
let mut bcx = cx; let mut bcx = cx;
debuginfo::update_source_pos(cx, s.span);
match s.node { match s.node {
ast::stmt_expr(e, _) | ast::stmt_semi(e, _) => { ast::stmt_expr(e, _) | ast::stmt_semi(e, _) => {
@ -1634,7 +1633,8 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
param_substs: param_substs, param_substs: param_substs,
span: sp, span: sp,
path: path, path: path,
ccx: ccx ccx: ccx,
debug_context: None,
}; };
fcx.llenv = unsafe { fcx.llenv = unsafe {
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint) llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
@ -1933,7 +1933,7 @@ pub fn trans_fn(ccx: @mut CrateContext,
attrs, attrs,
output_type, output_type,
|fcx| { |fcx| {
if ccx.sess.opts.extra_debuginfo if ccx.sess.opts.debuginfo
&& fcx_has_nonzero_span(fcx) { && fcx_has_nonzero_span(fcx) {
debuginfo::create_function_metadata(fcx); debuginfo::create_function_metadata(fcx);
} }

View File

@ -23,6 +23,7 @@ use middle::trans::build;
use middle::trans::datum; use middle::trans::datum;
use middle::trans::glue; use middle::trans::glue;
use middle::trans::write_guard; use middle::trans::write_guard;
use middle::trans::debuginfo;
use middle::ty::substs; use middle::ty::substs;
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
@ -226,7 +227,12 @@ pub struct FunctionContext {
path: path, path: path,
// This function's enclosing crate context. // This function's enclosing crate context.
ccx: @mut CrateContext 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>
} }
impl FunctionContext { impl FunctionContext {

View File

@ -19,7 +19,6 @@ use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
use middle::trans::callee; use middle::trans::callee;
use middle::trans::common::*; use middle::trans::common::*;
use middle::trans::debuginfo;
use middle::trans::expr; use middle::trans::expr;
use middle::trans::type_of::*; use middle::trans::type_of::*;
use middle::ty; use middle::ty;
@ -38,12 +37,10 @@ pub fn trans_block(bcx: @mut Block, b: &ast::Block, dest: expr::Dest) -> @mut Bl
let _icx = push_ctxt("trans_block"); let _icx = push_ctxt("trans_block");
let mut bcx = bcx; let mut bcx = bcx;
for s in b.stmts.iter() { for s in b.stmts.iter() {
debuginfo::update_source_pos(bcx, b.span);
bcx = trans_stmt(bcx, *s); bcx = trans_stmt(bcx, *s);
} }
match b.expr { match b.expr {
Some(e) => { Some(e) => {
debuginfo::update_source_pos(bcx, e.span);
bcx = expr::trans_into(bcx, e, dest); bcx = expr::trans_into(bcx, e, dest);
} }
None => { None => {

View File

@ -99,9 +99,7 @@ pub struct DebugContext {
priv created_files: HashMap<~str, DIFile>, priv created_files: HashMap<~str, DIFile>,
priv created_functions: HashMap<ast::NodeId, DISubprogram>, priv created_functions: HashMap<ast::NodeId, DISubprogram>,
priv created_blocks: HashMap<ast::NodeId, DILexicalBlock>, priv created_blocks: HashMap<ast::NodeId, DILexicalBlock>,
priv created_types: HashMap<uint, DIType>, priv created_types: HashMap<uint, DIType>
priv last_function_context_id: ast::NodeId,
priv argument_counter: uint,
} }
impl DebugContext { impl DebugContext {
@ -118,8 +116,21 @@ impl DebugContext {
created_files: HashMap::new(), created_files: HashMap::new(),
created_functions: HashMap::new(), created_functions: HashMap::new(),
created_blocks: HashMap::new(), created_blocks: HashMap::new(),
created_types: HashMap::new(), created_types: HashMap::new()
last_function_context_id: -1, // magic value :( };
}
}
pub struct FunctionDebugContext {
priv scope_map: HashMap<ast::NodeId, DIScope>,
priv argument_counter: uint,
}
impl FunctionDebugContext {
priv fn new() -> FunctionDebugContext {
return FunctionDebugContext {
scope_map: HashMap::new(),
argument_counter: 1, argument_counter: 1,
}; };
} }
@ -141,61 +152,24 @@ pub fn finalize(cx: @mut CrateContext) {
pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) { pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) {
let cx = bcx.ccx(); let cx = bcx.ccx();
let def_map = cx.tcx.def_map; let def_map = cx.tcx.def_map;
let pattern = local.pat;
let scope = match bcx.parent { do pat_util::pat_bindings(def_map, local.pat) |_, node_id, span, path_ref| {
None => create_function_metadata(bcx.fcx),
Some(_) => lexical_block_metadata(bcx)
};
let filename = span_start(cx, local.span).file.name; let var_ident = ast_util::path_to_ident(path_ref);
let file_metadata = file_metadata(cx, filename); let var_type = node_id_type(bcx, node_id);
do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| { declare_local(bcx, var_ident, node_id, var_type, span);
let ident = ast_util::path_to_ident(path_ref);
let name: &str = cx.sess.str_of(ident);
debug!("create_local_var_metadata: %s", name);
let loc = span_start(cx, span);
let ty = node_id_type(bcx, node_id);
let type_metadata = type_metadata(cx, ty, span);
let var_metadata = do name.to_c_str().with_ref |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_auto_variable,
scope,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
false,
0,
0)
}
};
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
}
};
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
llptr,
var_metadata,
bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
} }
} }
pub fn create_match_binding_metadata(bcx: @mut Block,
variable_ident: ast::ident,
node_id: ast::NodeId,
variable_type: ty::t,
span: span) {
declare_local(bcx, variable_ident, node_id, variable_type, span);
}
/// Creates debug information for the given function argument. /// Creates debug information for the given function argument.
/// ///
/// Adds the created metadata nodes directly to the crate's IR. /// Adds the created metadata nodes directly to the crate's IR.
@ -213,20 +187,6 @@ pub fn create_argument_metadata(bcx: @mut Block,
return; return;
} }
// Limited the scope within which `debug_context` is live,
// otherwise => borrowing errors
{
let debug_context = dbg_cx(cx);
// If this is a new function, reset the counter. llvm::DIBuilder
// wants arguments to be indexed starting from 1.
if fcx.id != debug_context.last_function_context_id {
debug_context.argument_counter = 1;
}
// Keep track of the function we are in
debug_context.last_function_context_id = fcx.id;
}
let def_map = cx.tcx.def_map; let def_map = cx.tcx.def_map;
let file_metadata = file_metadata(cx, filename); let file_metadata = file_metadata(cx, filename);
let scope = create_function_metadata(fcx); let scope = create_function_metadata(fcx);
@ -241,9 +201,9 @@ pub fn create_argument_metadata(bcx: @mut Block,
debug!("create_argument_metadata: %s", name); debug!("create_argument_metadata: %s", name);
let argument_index = { let argument_index = {
let debug_context = dbg_cx(cx); let counter = &mut fcx.debug_context.get_mut_ref().argument_counter;
let argument_index = debug_context.argument_counter; let argument_index = *counter;
debug_context.argument_counter += 1; *counter += 1;
argument_index as c_uint argument_index as c_uint
}; };
@ -270,7 +230,7 @@ pub fn create_argument_metadata(bcx: @mut Block,
} }
}; };
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint()); set_debug_location(cx, scope, loc.line, loc.col.to_uint());
unsafe { unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx), DIB(cx),
@ -286,20 +246,28 @@ pub fn create_argument_metadata(bcx: @mut Block,
/// Sets the current debug location at the beginning of the span /// Sets the current debug location at the beginning of the span
/// ///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...) /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
pub fn update_source_pos(bcx: @mut Block, span: span) { pub fn update_source_pos(fcx: &FunctionContext,
if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) { node_id: ast::NodeId,
span: span) {
let cx: &mut CrateContext = fcx.ccx;
if !cx.sess.opts.debuginfo || (*span.lo == 0 && *span.hi == 0) {
return; return;
} }
debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span));
let loc = span_start(bcx.ccx(), span); debug!("update_source_pos: %s", cx.sess.codemap.span_to_str(span));
set_debug_location(bcx.ccx(), lexical_block_metadata(bcx), loc.line, loc.col.to_uint())
let loc = span_start(cx, span);
let scope = scope_metadata(fcx, node_id, span);
set_debug_location(cx, scope, loc.line, loc.col.to_uint());
} }
/// Creates debug information for the given function. /// Creates debug information for the given function.
/// ///
/// Adds the created metadata nodes directly to the crate's IR. /// Adds the created metadata nodes directly to the crate's IR.
/// The return value should be ignored if called from outside of the debuginfo module. /// The return value should be ignored if called from outside of the debuginfo module.
pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram { pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
let cx = fcx.ccx; let cx = fcx.ccx;
let fnitem = cx.tcx.items.get_copy(&fcx.id); let fnitem = cx.tcx.items.get_copy(&fcx.id);
@ -349,8 +317,8 @@ pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
_ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem)) _ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
}; };
match dbg_cx(cx).created_functions.find(&id) { match dbg_cx(cx).created_functions.find_copy(&id) {
Some(fn_metadata) => return *fn_metadata, Some(fn_metadata) => return fn_metadata,
None => () None => ()
} }
@ -405,6 +373,25 @@ pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
} }
}}; }};
assert!(fcx.debug_context.is_none());
let mut fn_debug_context = ~FunctionDebugContext::new();
let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
let entry_block = cx.tcx.items.get(&entry_block_id);
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);
}
_ => cx.sess.span_bug(span,
fmt!("debuginfo::create_function_metadata() - \
FunctionContext::entry_bcx::node_info points to wrong type of ast_map entry. \
Expected: ast_map::node_block, actual: %?", *entry_block))
}
fcx.debug_context = Some(fn_debug_context);
dbg_cx(cx).created_functions.insert(id, fn_metadata); dbg_cx(cx).created_functions.insert(id, fn_metadata);
return fn_metadata; return fn_metadata;
} }
@ -445,6 +432,56 @@ fn compile_unit_metadata(cx: @mut CrateContext) {
}}}}}; }}}}};
} }
fn declare_local(bcx: @mut Block,
variable_ident: ast::ident,
node_id: ast::NodeId,
variable_type: ty::t,
span: span) {
let cx: &mut CrateContext = bcx.ccx();
let filename = span_start(cx, span).file.name;
let file_metadata = file_metadata(cx, filename);
let name: &str = cx.sess.str_of(variable_ident);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
let scope = scope_metadata(bcx.fcx, node_id, span);
let var_metadata = do name.as_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_auto_variable,
scope,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
false,
0,
0)
}
};
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
}
};
set_debug_location(cx, scope, loc.line, loc.col.to_uint());
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
llptr,
var_metadata,
bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
}
fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile { fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
match dbg_cx(cx).created_files.find_equiv(&full_path) { match dbg_cx(cx).created_files.find_equiv(&full_path) {
Some(file_metadata) => return *file_metadata, Some(file_metadata) => return *file_metadata,
@ -473,50 +510,26 @@ fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
return file_metadata; return file_metadata;
} }
/// Get or create the lexical block metadata node for the given LLVM basic block. /// Finds the scope metadata node for the given AST node.
fn lexical_block_metadata(bcx: @mut Block) -> DILexicalBlock { fn scope_metadata(fcx: &FunctionContext,
let cx = bcx.ccx(); node_id: ast::NodeId,
let mut bcx = bcx; span: span) -> DIScope {
if fcx.debug_context.is_none() {
fcx.ccx.sess.span_bug(span, "debuginfo: FunctionDebugContext should be initialized \
but is not!");
}
// Search up the tree of basic blocks until we find one that knows the containing lexical block. let scope_map = &fcx.debug_context.get_ref().scope_map;
while bcx.node_info.is_none() {
match bcx.parent { match scope_map.find_copy(&node_id) {
Some(b) => bcx = b, Some(scope_metadata) => scope_metadata,
None => cx.sess.bug("debuginfo: Could not find lexical block for LLVM basic block.") None => {
let node = fcx.ccx.tcx.items.get_copy(&node_id);
fcx.ccx.sess.span_bug(span,
fmt!("debuginfo: Could not find scope info for node %?", node));
} }
} }
let span = bcx.node_info.unwrap().span;
let id = bcx.node_info.unwrap().id;
// Check whether we already have a cache entry for this node id
match dbg_cx(cx).created_blocks.find(&id) {
Some(block) => return *block,
None => ()
}
debug!("lexical_block_metadata: %s", bcx.sess().codemap.span_to_str(span));
let parent = match bcx.parent {
None => create_function_metadata(bcx.fcx),
Some(b) => lexical_block_metadata(b)
};
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
let lexical_block_metadata = unsafe {
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(cx),
parent,
file_metadata,
loc.line as c_uint,
loc.col.to_uint() as c_uint)
};
dbg_cx(cx).created_blocks.insert(id, lexical_block_metadata);
return lexical_block_metadata;
} }
fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType { fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
@ -1206,7 +1219,7 @@ fn type_metadata(cx: &mut CrateContext,
return type_metadata; return type_metadata;
} }
fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) { fn set_debug_location(cx: &mut CrateContext, scope: DIScope, line: uint, col: uint) {
if dbg_cx(cx).curr_loc == (line, col) { if dbg_cx(cx).curr_loc == (line, col) {
return; return;
} }
@ -1224,7 +1237,6 @@ fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: ui
} }
} }
//=------------------------------------------------------------------------------------------------- //=-------------------------------------------------------------------------------------------------
// Utility Functions // Utility Functions
//=------------------------------------------------------------------------------------------------- //=-------------------------------------------------------------------------------------------------
@ -1256,3 +1268,436 @@ fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext {
fn DIB(cx: &CrateContext) -> DIBuilderRef { fn DIB(cx: &CrateContext) -> DIBuilderRef {
cx.dbg_cx.get_ref().builder cx.dbg_cx.get_ref().builder
} }
// This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
// the function's AST to the correct DIScope metadata instance.
//
// This builder procedure walks the AST in execution order and keeps track of what belongs to which
// scope, creating DIScope DIEs along the way, and introducing *artificial* lexical scope
// descriptors where necessary. These artificial scopes allow GDB to correctly handle name
// shadowing.
fn populate_scope_map(cx: &mut CrateContext,
fn_entry_block: &ast::Block,
fn_metadata: DISubprogram,
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
struct ScopeStackEntry {
scope_metadata: DIScope,
ident: Option<ast::ident>
}
let mut scope_stack = ~[ScopeStackEntry { scope_metadata: fn_metadata, ident: None }];
walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
// local helper functions for walking the AST.
fn with_new_scope(cx: &mut CrateContext,
scope_span: span,
scope_stack: &mut ~[ScopeStackEntry],
scope_map: &mut HashMap<ast::NodeId, DIScope>,
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);
let parent_scope = scope_stack.last().scope_metadata;
let scope_metadata = unsafe {
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope,
file_metadata,
loc.line as c_uint,
loc.col.to_uint() as c_uint)
};
scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, ident: None });
inner_walk(cx, scope_stack, scope_map);
// pop artificial scopes
while scope_stack.last().ident.is_some() {
scope_stack.pop();
}
if scope_stack.last().scope_metadata != scope_metadata {
cx.sess.span_bug(scope_span, "debuginfo: Inconsistency in scope management.");
}
scope_stack.pop();
}
fn walk_block(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.
for &@ ref statement in block.stmts.iter() {
scope_map.insert(ast_util::stmt_id(statement), scope_stack.last().scope_metadata);
match statement.node {
ast::stmt_decl(@ref decl, _) => walk_decl(cx, decl, scope_stack, scope_map),
ast::stmt_expr(@ref exp, _) |
ast::stmt_semi(@ref exp, _) => walk_expr(cx, exp, scope_stack, scope_map),
ast::stmt_mac(*) => () // ignore macros (which should be expanded anyway)
}
}
for &@ref exp in block.expr.iter() {
walk_expr(cx, exp, scope_stack, scope_map);
}
}
fn walk_decl(cx: &mut CrateContext,
decl: &ast::decl,
scope_stack: &mut ~[ScopeStackEntry],
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);
for &@ref exp in local.init.iter() {
walk_expr(cx, exp, scope_stack, scope_map);
}
}
_ => ()
}
}
fn walk_pattern(cx: &mut CrateContext,
pat: @ast::pat,
scope_stack: &mut ~[ScopeStackEntry],
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
let def_map = cx.tcx.def_map;
// 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.
match pat.node {
ast::pat_ident(_, ref path_ref, ref sub_pat_opt) => {
// Check if this is a binding. If so we need to put it on the scope stack and maybe
// introduce an articial scope
if pat_util::pat_is_binding(def_map, pat) {
let ident = ast_util::path_to_ident(path_ref);
// LLVM does not properly generate 'DW_AT_start_scope' fields for variable DIEs.
// For this reason we have to introduce an artificial scope at bindings whenever
// a variable with the same name is declared in *any* parent scope.
//
// Otherwise the following error occurs:
//
// let x = 10;
//
// do_something(); // 'gdb print x' correctly prints 10
//
// {
// do_something(); // 'gdb print x' prints 0, because it already reads the
// // uninitialized 'x' from the next line...
// let x = 100;
// do_something(); // 'gdb print x' correctly prints 100
// }
// 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();
if need_new_scope {
// Create a new lexical scope and push it onto the stack
let loc = cx.sess.codemap.lookup_char_pos(pat.span.lo);
let file_metadata = file_metadata(cx, loc.file.name);
let parent_scope = scope_stack.last().scope_metadata;
let scope_metadata = unsafe {
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope,
file_metadata,
loc.line as c_uint,
loc.col.to_uint() as c_uint)
};
scope_stack.push(ScopeStackEntry {
scope_metadata: scope_metadata,
ident: Some(ident)
});
} else {
// Push a new entry anyway so the name can be found
let prev_metadata = scope_stack.last().scope_metadata;
scope_stack.push(ScopeStackEntry {
scope_metadata: prev_metadata,
ident: Some(ident)
});
}
}
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
for &sub_pat in sub_pat_opt.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
}
ast::pat_wild => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
}
ast::pat_enum(_, ref sub_pats_opt) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
for ref sub_pats in sub_pats_opt.iter() {
for &p in sub_pats.iter() {
walk_pattern(cx, p, scope_stack, scope_map);
}
}
}
ast::pat_struct(_, ref field_pats, _) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
for &ast::field_pat { pat: sub_pat, _ } in field_pats.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
}
ast::pat_tup(ref sub_pats) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
for &sub_pat in sub_pats.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
}
ast::pat_box(sub_pat) |
ast::pat_uniq(sub_pat) |
ast::pat_region(sub_pat) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
ast::pat_lit(@ref exp) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
walk_expr(cx, exp, scope_stack, scope_map);
}
ast::pat_range(@ref exp1, @ref exp2) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
walk_expr(cx, exp1, scope_stack, scope_map);
walk_expr(cx, exp2, scope_stack, scope_map);
}
ast::pat_vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
scope_map.insert(pat.id, scope_stack.last().scope_metadata);
for &sub_pat in front_sub_pats.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
for &sub_pat in middle_sub_pats.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
for &sub_pat in back_sub_pats.iter() {
walk_pattern(cx, sub_pat, scope_stack, scope_map);
}
}
}
}
fn walk_expr(cx: &mut CrateContext,
exp: &ast::expr,
scope_stack: &mut ~[ScopeStackEntry],
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
scope_map.insert(exp.id, scope_stack.last().scope_metadata);
match exp.node {
ast::expr_self |
ast::expr_lit(_) |
ast::expr_break(_) |
ast::expr_again(_) |
ast::expr_path(_) => (),
ast::expr_vstore(@ref sub_exp, _) |
ast::expr_cast(@ref sub_exp, _) |
ast::expr_addr_of(_, @ref sub_exp) |
ast::expr_field(@ref sub_exp, _, _) |
ast::expr_paren(@ref sub_exp) => walk_expr(cx, sub_exp, scope_stack, scope_map),
ast::expr_ret(exp_opt) => match exp_opt {
Some(@ref sub_exp) => walk_expr(cx, sub_exp, scope_stack, scope_map),
None => ()
},
ast::expr_unary(node_id, _, @ref sub_exp) => {
scope_map.insert(node_id, scope_stack.last().scope_metadata);
walk_expr(cx, sub_exp, scope_stack, scope_map);
}
ast::expr_assign_op(node_id, _, @ref lhs, @ref rhs) |
ast::expr_index(node_id, @ref lhs, @ref rhs) |
ast::expr_binary(node_id, _, @ref lhs, @ref rhs) => {
scope_map.insert(node_id, scope_stack.last().scope_metadata);
walk_expr(cx, lhs, scope_stack, scope_map);
walk_expr(cx, rhs, scope_stack, scope_map);
}
ast::expr_vec(ref init_expressions, _) |
ast::expr_tup(ref init_expressions) => {
for &@ref ie in init_expressions.iter() {
walk_expr(cx, ie, scope_stack, scope_map);
}
}
ast::expr_assign(@ref sub_exp1, @ref sub_exp2) |
ast::expr_log(@ref sub_exp1, @ref sub_exp2) |
ast::expr_repeat(@ref sub_exp1, @ref sub_exp2, _) => {
walk_expr(cx, sub_exp1, scope_stack, scope_map);
walk_expr(cx, sub_exp2, scope_stack, scope_map);
}
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);
}
match *opt_else_exp {
Some(@ref else_exp) => walk_expr(cx, else_exp, scope_stack, scope_map),
_ => ()
}
}
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);
}
}
ast::expr_for_loop(_, _, _) => {
cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \
Found unexpanded for-loop.");
}
ast::expr_mac(_) => {
cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \
Found unexpanded macro.");
}
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);
}
}
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| {
for &ast::arg { pat: pattern, _ } in inputs.iter() {
walk_pattern(c, pattern, s, m);
}
walk_block(c, block, s, m);
}
}
// ast::expr_loop_body(@ref inner_exp) |
ast::expr_do_body(@ref inner_exp) => {
let inner_expr_is_expr_fn_block = match *inner_exp {
ast::expr { node: ast::expr_fn_block(*), _ } => true,
_ => false
};
if !inner_expr_is_expr_fn_block {
cx.sess.span_bug(inner_exp.span, "debuginfo: Inner expression was expected \
to be an ast::expr_fn_block.");
}
walk_expr(cx, inner_exp, scope_stack, scope_map);
}
ast::expr_call(@ref fn_exp, ref args, _) => {
walk_expr(cx, fn_exp, scope_stack, scope_map);
for &@ref arg_exp in args.iter() {
walk_expr(cx, arg_exp, scope_stack, scope_map);
}
}
ast::expr_method_call(node_id, @ref receiver_exp, _, _, ref args, _) => {
scope_map.insert(node_id, scope_stack.last().scope_metadata);
walk_expr(cx, receiver_exp, scope_stack, scope_map);
for &@ref arg_exp in args.iter() {
walk_expr(cx, arg_exp, scope_stack, scope_map);
}
}
ast::expr_match(@ref discriminant_exp, ref arms) => {
walk_expr(cx, discriminant_exp, scope_stack, scope_map);
// for each arm we have to first walk the pattern as these might introduce new
// artificial scopes. It should be sufficient to walk only one pattern per arm, as
// they all must contain the same binding names
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);
for &@ref guard_exp in arm_ref.guard.iter() {
walk_expr(c, guard_exp, s, m)
}
walk_block(c, &arm_ref.body, s, m);
}
}
}
ast::expr_struct(_, ref fields, ref base_exp) => {
for &ast::Field { expr: @ref exp, _ } in fields.iter() {
walk_expr(cx, exp, scope_stack, scope_map);
}
match *base_exp {
Some(@ref exp) => walk_expr(cx, exp, scope_stack, scope_map),
None => ()
}
}
ast::expr_inline_asm(ast::inline_asm { inputs: ref inputs,
outputs: ref outputs,
_ }) => {
// inputs, outputs: ~[(@str, @expr)]
for &(_, @ref exp) in inputs.iter() {
walk_expr(cx, exp, scope_stack, scope_map);
}
for &(_, @ref exp) in outputs.iter() {
walk_expr(cx, exp, scope_stack, scope_map);
}
}
}
}
}

View File

@ -413,7 +413,7 @@ pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
dest.to_str(bcx.ccx())); dest.to_str(bcx.ccx()));
let _indenter = indenter(); let _indenter = indenter();
debuginfo::update_source_pos(bcx, expr.span); debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
let dest = { let dest = {
if ty::type_is_nil(ty) || ty::type_is_bot(ty) { if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
@ -485,7 +485,7 @@ fn trans_to_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr)); debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
let _indenter = indenter(); let _indenter = indenter();
debuginfo::update_source_pos(bcx, expr.span); debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) { match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
ty::LvalueExpr => { ty::LvalueExpr => {

View File

@ -0,0 +1,77 @@
// 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
// FIRST ITERATION
// debugger:finish
// debugger:print x
// check:$1 = 1
// debugger:continue
// debugger:finish
// debugger:print x
// check:$2 = -1
// debugger:continue
// SECOND ITERATION
// debugger:finish
// debugger:print x
// check:$3 = 2
// debugger:continue
// debugger:finish
// debugger:print x
// check:$4 = -2
// debugger:continue
// THIRD ITERATION
// debugger:finish
// debugger:print x
// check:$5 = 3
// debugger:continue
// debugger:finish
// debugger:print x
// check:$6 = -3
// debugger:continue
// AFTER LOOP
// debugger:finish
// debugger:print x
// check:$7 = 1000000
// debugger:continue
fn main() {
let range = [1, 2, 3];
let x = 1000000; // wan meeeljen doollaars!
for &x in range.iter() {
zzz();
sentinel();
let x = -1 * x;
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,128 @@
// 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
// BEFORE if
// debugger:finish
// debugger:print x
// check:$1 = 999
// debugger:print y
// check:$2 = -1
// debugger:continue
// AT BEGINNING of 'then' block
// debugger:finish
// debugger:print x
// check:$3 = 999
// debugger:print y
// check:$4 = -1
// debugger:continue
// AFTER 1st redeclaration of 'x'
// debugger:finish
// debugger:print x
// check:$5 = 1001
// debugger:print y
// check:$6 = -1
// debugger:continue
// AFTER 2st redeclaration of 'x'
// debugger:finish
// debugger:print x
// check:$7 = 1002
// debugger:print y
// check:$8 = 1003
// debugger:continue
// AFTER 1st if expression
// debugger:finish
// debugger:print x
// check:$9 = 999
// debugger:print y
// check:$10 = -1
// debugger:continue
// BEGINNING of else branch
// debugger:finish
// debugger:print x
// check:$11 = 999
// debugger:print y
// check:$12 = -1
// debugger:continue
// BEGINNING of else branch
// debugger:finish
// debugger:print x
// check:$13 = 1004
// debugger:print y
// check:$14 = 1005
// debugger:continue
// BEGINNING of else branch
// debugger:finish
// debugger:print x
// check:$15 = 999
// debugger:print y
// check:$16 = -1
// debugger:continue
use std::util;
fn main() {
let x = 999;
let y = -1;
zzz();
sentinel();
if x < 1000 {
zzz();
sentinel();
let x = 1001;
zzz();
sentinel();
let x = 1002;
let y = 1003;
zzz();
sentinel();
} else {
util::unreachable();
}
zzz();
sentinel();
if x > 1000 {
util::unreachable();
} else {
zzz();
sentinel();
let x = 1004;
let y = 1005;
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,148 @@
// 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 shadowed
// check:$1 = 231
// debugger:print not_shadowed
// check:$2 = 232
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$3 = 233
// debugger:print not_shadowed
// check:$4 = 232
// debugger:print local_to_arm
// check:$5 = 234
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$6 = 236
// debugger:print not_shadowed
// check:$7 = 232
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$8 = 237
// debugger:print not_shadowed
// check:$9 = 232
// debugger:print local_to_arm
// check:$10 = 238
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$11 = 239
// debugger:print not_shadowed
// check:$12 = 232
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$13 = 241
// debugger:print not_shadowed
// check:$14 = 232
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$15 = 243
// debugger:print *local_to_arm
// check:$16 = 244
// debugger:continue
// debugger:finish
// debugger:print shadowed
// check:$17 = 231
// debugger:print not_shadowed
// check:$18 = 232
// debugger:continue
struct Struct {
x: int,
y: int
}
fn main() {
let shadowed = 231;
let not_shadowed = 232;
zzz();
sentinel();
match (233, 234) {
(shadowed, local_to_arm) => {
zzz();
sentinel();
}
}
match (235, 236) {
// with literal
(235, shadowed) => {
zzz();
sentinel();
}
_ => {}
}
match Struct { x: 237, y: 238 } {
Struct { x: shadowed, y: local_to_arm } => {
zzz();
sentinel();
}
}
match Struct { x: 239, y: 240 } {
// ignored field
Struct { x: shadowed, _ } => {
zzz();
sentinel();
}
}
match Struct { x: 241, y: 242 } {
// with literal
Struct { x: shadowed, y: 242 } => {
zzz();
sentinel();
}
_ => {}
}
match (243, 244) {
(shadowed, ref local_to_arm) => {
zzz();
sentinel();
}
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,127 @@
// 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
// FIRST ITERATION
// debugger:finish
// debugger:print x
// check:$1 = 0
// debugger:continue
// debugger:finish
// debugger:print x
// check:$2 = 1
// debugger:continue
// debugger:finish
// debugger:print x
// check:$3 = 101
// debugger:continue
// debugger:finish
// debugger:print x
// check:$4 = 101
// debugger:continue
// debugger:finish
// debugger:print x
// check:$5 = -987
// debugger:continue
// debugger:finish
// debugger:print x
// check:$6 = 101
// debugger:continue
// SECOND ITERATION
// debugger:finish
// debugger:print x
// check:$7 = 1
// debugger:continue
// debugger:finish
// debugger:print x
// check:$8 = 2
// debugger:continue
// debugger:finish
// debugger:print x
// check:$9 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$10 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$11 = -987
// debugger:continue
// debugger:finish
// debugger:print x
// check:$12 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$13 = 2
// debugger:continue
fn main() {
let mut x = 0;
loop {
if x >= 2 {
break;
}
zzz();
sentinel();
x += 1;
zzz();
sentinel();
// Shadow x
let x = x + 100;
zzz();
sentinel();
// open scope within loop's top level scope
{
zzz();
sentinel();
let x = -987;
zzz();
sentinel();
}
// Check that we get the x before the inner scope again
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,123 @@
// 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
// FIRST ITERATION
// debugger:finish
// debugger:print x
// check:$1 = 0
// debugger:continue
// debugger:finish
// debugger:print x
// check:$2 = 1
// debugger:continue
// debugger:finish
// debugger:print x
// check:$3 = 101
// debugger:continue
// debugger:finish
// debugger:print x
// check:$4 = 101
// debugger:continue
// debugger:finish
// debugger:print x
// check:$5 = -987
// debugger:continue
// debugger:finish
// debugger:print x
// check:$6 = 101
// debugger:continue
// SECOND ITERATION
// debugger:finish
// debugger:print x
// check:$7 = 1
// debugger:continue
// debugger:finish
// debugger:print x
// check:$8 = 2
// debugger:continue
// debugger:finish
// debugger:print x
// check:$9 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$10 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$11 = -987
// debugger:continue
// debugger:finish
// debugger:print x
// check:$12 = 102
// debugger:continue
// debugger:finish
// debugger:print x
// check:$13 = 2
// debugger:continue
fn main() {
let mut x = 0;
while x < 2 {
zzz();
sentinel();
x += 1;
zzz();
sentinel();
// Shadow x
let x = x + 100;
zzz();
sentinel();
// open scope within loop's top level scope
{
zzz();
sentinel();
let x = -987;
zzz();
sentinel();
}
// Check that we get the x before the inner scope again
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,129 @@
// 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 a
// check:$1 = 10
// debugger:print b
// check:$2 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$3 = 890242
// debugger:print b
// check:$4 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$5 = 10
// debugger:print b
// check:$6 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$7 = 102
// debugger:print b
// check:$8 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$9 = 110
// debugger:print b
// check:$10 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$11 = 10
// debugger:print b
// check:$12 = 34
// debugger:continue
// debugger:finish
// debugger:print a
// check:$13 = 10
// debugger:print b
// check:$14 = 34
// debugger:print c
// check:$15 = 400
// debugger:continue
macro_rules! trivial(
($e1:expr) => ($e1)
)
macro_rules! no_new_scope(
($e1:expr) => (($e1 + 2) - 1)
)
macro_rules! new_scope(
() => ({
let a = 890242;
zzz();
sentinel();
})
)
macro_rules! shadow_within_macro(
($e1:expr) => ({
let a = $e1 + 2;
zzz();
sentinel();
let a = $e1 + 10;
zzz();
sentinel();
})
)
macro_rules! dup_expr(
($e1:expr) => (($e1) + ($e1))
)
fn main() {
let a = trivial!(10);
let b = no_new_scope!(33);
zzz();
sentinel();
new_scope!();
zzz();
sentinel();
shadow_within_macro!(100);
zzz();
sentinel();
let c = dup_expr!(10 * 20);
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,344 @@
// 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
// STRUCT EXPRESSION
// debugger:finish
// debugger:print val
// check:$1 = -1
// debugger:print ten
// check:$2 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$3 = 11
// debugger:print ten
// check:$4 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$5 = -1
// debugger:print ten
// check:$6 = 10
// debugger:continue
// FUNCTION CALL
// debugger:finish
// debugger:print val
// check:$7 = -1
// debugger:print ten
// check:$8 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$9 = 12
// debugger:print ten
// check:$10 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$11 = -1
// debugger:print ten
// check:$12 = 10
// debugger:continue
// TUPLE EXPRESSION
// debugger:finish
// debugger:print val
// check:$13 = -1
// debugger:print ten
// check:$14 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$15 = 13
// debugger:print ten
// check:$16 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$17 = -1
// debugger:print ten
// check:$18 = 10
// debugger:continue
// VEC EXPRESSION
// debugger:finish
// debugger:print val
// check:$19 = -1
// debugger:print ten
// check:$20 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$21 = 14
// debugger:print ten
// check:$22 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$23 = -1
// debugger:print ten
// check:$24 = 10
// debugger:continue
// REPEAT VEC EXPRESSION
// debugger:finish
// debugger:print val
// check:$25 = -1
// debugger:print ten
// check:$26 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$27 = 15
// debugger:print ten
// check:$28 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$29 = -1
// debugger:print ten
// check:$30 = 10
// debugger:continue
// ASSIGNMENT EXPRESSION
// debugger:finish
// debugger:print val
// check:$31 = -1
// debugger:print ten
// check:$32 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$33 = 16
// debugger:print ten
// check:$34 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$35 = -1
// debugger:print ten
// check:$36 = 10
// debugger:continue
// ARITHMETIC EXPRESSION
// debugger:finish
// debugger:print val
// check:$37 = -1
// debugger:print ten
// check:$38 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$39 = 17
// debugger:print ten
// check:$40 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$41 = -1
// debugger:print ten
// check:$42 = 10
// debugger:continue
// INDEX EXPRESSION
// debugger:finish
// debugger:print val
// check:$43 = -1
// debugger:print ten
// check:$44 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$45 = 18
// debugger:print ten
// check:$46 = 10
// debugger:continue
// debugger:finish
// debugger:print val
// check:$47 = -1
// debugger:print ten
// check:$48 = 10
// debugger:continue
struct Point {
x: int,
y: int
}
fn a_function(x: int) -> int {
x + 1
}
fn main() {
let val = -1;
let ten = 10;
// surrounded by struct expression
let point = Point {
x: {
zzz();
sentinel();
let val = ten + 1;
zzz();
sentinel();
val
},
y: 10
};
zzz();
sentinel();
// surrounded by function call
let _ = a_function({
zzz();
sentinel();
let val = ten + 2;
zzz();
sentinel();
val
});
zzz();
sentinel();
// surrounded by tup
let _ = ({
zzz();
sentinel();
let val = ten + 3;
zzz();
sentinel();
val
}, 0);
zzz();
sentinel();
// surrounded by vec
let _ = [{
zzz();
sentinel();
let val = ten + 4;
zzz();
sentinel();
val
}, 0, 0];
zzz();
sentinel();
// surrounded by repeat vec
let _ = [{
zzz();
sentinel();
let val = ten + 5;
zzz();
sentinel();
val
}, ..10];
zzz();
sentinel();
// assignment expression
let mut var = 0;
var = {
zzz();
sentinel();
let val = ten + 6;
zzz();
sentinel();
val
};
zzz();
sentinel();
// arithmetic expression
var = 10 + -{
zzz();
sentinel();
let val = ten + 7;
zzz();
sentinel();
val
} * 5;
zzz();
sentinel();
// index expression
let a_vector = [10, ..20];
let _ = a_vector[{
zzz();
sentinel();
let val = ten + 8;
zzz();
sentinel();
val
}];
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,95 @@
// 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
// debugger:finish
// debugger:print x
// check:$7 = true
// debugger:print y
// check:$8 = 2220
// debugger:continue
// debugger:finish
// debugger:print x
// check:$9 = 203203.5
// debugger:print y
// check:$10 = 2220
// debugger:continue
// debugger:finish
// debugger:print x
// check:$11 = 10.5
// debugger:print y
// check:$12 = 20
// debugger:continue
fn main() {
let x = false;
let y = true;
zzz();
sentinel();
let x = 10;
zzz();
sentinel();
let x = 10.5;
let y = 20;
zzz();
sentinel();
{
let x = true;
let y = 2220;
zzz();
sentinel();
let x = 203203.5;
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -8,42 +8,51 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// xfail-test // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info // compile-flags:-Z extra-debug-info
// debugger:break zzz // debugger:break zzz
// debugger:run // debugger:run
// debugger:finish // debugger:finish
// debugger:print x // debugger:print x
// check:$1 = false // check:$1 = false
// debugger:print y // debugger:print y
// check:$2 = true // check:$2 = true
// debugger:continue // debugger:continue
// debugger:finish // debugger:finish
// debugger:print x // debugger:print x
// check:$3 = 10 // check:$3 = 10
// debugger:print y
// check:$4 = true
// debugger:continue // debugger:continue
// debugger:finish // debugger:finish
// debugger:print x // debugger:print x
// check:$4 = false // check:$5 = 10.5
// debugger:print y // debugger:print y
// check:$5 = 11 // check:$6 = 20
// debugger:continue
fn main() { fn main() {
let x = false; let x = false;
let y = true; let y = true;
zzz(); zzz();
sentinel();
{ let x = 10;
let x = 10;
zzz();
}
let y = 11;
zzz(); zzz();
sentinel();
let x = 10.5;
let y = 20;
zzz();
sentinel();
} }
fn zzz() {()} fn zzz() {()}
fn sentinel() {()}

View File

@ -0,0 +1,87 @@
// 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:continue
// debugger:finish
// debugger:print x
// check:$2 = false
// debugger:continue
// debugger:finish
// debugger:print x
// check:$3 = 10
// debugger:continue
// debugger:finish
// debugger:print x
// check:$4 = 10
// debugger:continue
// debugger:finish
// debugger:print x
// check:$5 = 10.5
// debugger:continue
// debugger:finish
// debugger:print x
// check:$6 = 10
// debugger:continue
// debugger:finish
// debugger:print x
// check:$7 = false
// debugger:continue
fn main() {
let x = false;
zzz();
sentinel();
{
zzz();
sentinel();
let x = 10;
zzz();
sentinel();
{
zzz();
sentinel();
let x = 10.5;
zzz();
sentinel();
}
zzz();
sentinel();
}
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}