From b81ea86530dfd9dff69815b099ba10be274830ea Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 23 Aug 2013 18:45:02 +0200 Subject: [PATCH 1/7] debuginfo: Support for variables captured in closures and closure type descriptions. --- src/librustc/lib/llvm.rs | 19 + src/librustc/middle/moves.rs | 2 +- src/librustc/middle/trans/base.rs | 28 +- src/librustc/middle/trans/closure.rs | 6 + src/librustc/middle/trans/common.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 475 ++++++++++++------ src/libsyntax/ast_map.rs | 8 +- src/rustllvm/RustWrapper.cpp | 36 ++ .../var-captured-in-managed-closure.rs | 58 +++ .../var-captured-in-sendable-closure.rs | 56 +++ .../var-captured-in-stack-closure.rs | 61 +++ 11 files changed, 559 insertions(+), 192 deletions(-) create mode 100644 src/test/debug-info/var-captured-in-managed-closure.rs create mode 100644 src/test/debug-info/var-captured-in-sendable-closure.rs create mode 100644 src/test/debug-info/var-captured-in-stack-closure.rs diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index c9253026488e2..7903e6f02fa2e 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2084,6 +2084,25 @@ pub mod llvm { ColumnNo: c_uint) -> ValueRef; + #[fast_ffi] + pub fn LLVMDIBuilderCreateOpDeref(IntType: TypeRef) -> ValueRef; + + #[fast_ffi] + pub fn LLVMDIBuilderCreateOpPlus(IntType: TypeRef) -> ValueRef; + + #[fast_ffi] + pub fn LLVMDIBuilderCreateComplexVariable(Builder: DIBuilderRef, + Tag: c_uint, + Scope: ValueRef, + Name: *c_char, + File: ValueRef, + LineNo: c_uint, + Ty: ValueRef, + AddrOps: *ValueRef, + AddrOpsCount: c_uint, + ArgNo: c_uint) + -> ValueRef; + pub fn LLVMInitializeX86TargetInfo(); pub fn LLVMInitializeX86Target(); pub fn LLVMInitializeX86TargetMC(); diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index ba05ab1f3c3cd..cb672947774a5 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -143,7 +143,7 @@ use syntax::visit; use syntax::visit::Visitor; use syntax::codemap::Span; -#[deriving(Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable)] pub enum CaptureMode { CapCopy, // Copy the value into the closure. CapMove, // Move the value into the closure. diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 2ed9af42248c9..92aedbdef84ba 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -131,20 +131,6 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt { _InsnCtxt { _x: () } } -fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool { - match fcx.span { - None => false, - Some(span) => *span.lo != 0 || *span.hi != 0 - } -} - -fn span_is_empty(opt_span: &Option) -> bool { - match *opt_span { - None => true, - Some(span) => *span.lo == 0 && *span.hi == 0 - } -} - struct StatRecorder<'self> { ccx: @mut CrateContext, name: &'self str, @@ -1132,8 +1118,7 @@ pub fn trans_stmt(cx: @mut Block, s: &ast::Stmt) -> @mut Block { match d.node { ast::DeclLocal(ref local) => { bcx = init_local(bcx, *local); - if cx.sess().opts.extra_debuginfo - && fcx_has_nonzero_span(bcx.fcx) { + if cx.sess().opts.extra_debuginfo { debuginfo::create_local_var_metadata(bcx, *local); } } @@ -1633,12 +1618,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, } }; let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type); - - let debug_context = if id != -1 && ccx.sess.opts.debuginfo && !span_is_empty(&sp) { - Some(debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl)) - } else { - None - }; + let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl); let fcx = @mut FunctionContext { llfn: llfndecl, @@ -1784,7 +1764,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext, fcx.llself = Some(ValSelfData {v: self_val, ..slf}); add_clean(bcx, self_val, slf.t); - if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { + if fcx.ccx.sess.opts.extra_debuginfo { debuginfo::create_self_argument_metadata(bcx, slf.t, self_val); } } @@ -1811,7 +1791,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext, }; bcx = _match::store_arg(bcx, args[arg_n].pat, llarg); - if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { + if fcx.ccx.sess.opts.extra_debuginfo { debuginfo::create_argument_metadata(bcx, &args[arg_n]); } } diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 645f81577668e..d25fedf2d8e6e 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -17,6 +17,7 @@ use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; use middle::trans::datum::{Datum, INIT}; +use middle::trans::debuginfo; use middle::trans::expr; use middle::trans::glue; use middle::trans::type_of::*; @@ -317,6 +318,11 @@ pub fn load_environment(fcx: @mut FunctionContext, } let def_id = ast_util::def_id_of_def(cap_var.def); fcx.llupvars.insert(def_id.node, upvarptr); + + if fcx.ccx.sess.opts.extra_debuginfo { + debuginfo::create_captured_var_metadata(bcx, def_id.node, upvarptr, cap_var.span); + } + i += 1u; } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index fb80cfe3485eb..d64f221cb9ecd 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -228,7 +228,7 @@ pub struct FunctionContext { ccx: @mut CrateContext, // Used and maintained by the debuginfo module. - debug_context: Option<~debuginfo::FunctionDebugContext> + debug_context: debuginfo::FunctionDebugContext, } impl FunctionContext { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index a9e3a869be098..049dee6bfea96 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -72,7 +72,7 @@ use syntax::codemap::Span; use syntax::{ast, codemap, ast_util, ast_map, opt_vec}; use syntax::parse::token::special_idents; -static DW_LANG_RUST: int = 0x9000; +static DW_LANG_RUST: c_uint = 0x9000; static DW_TAG_auto_variable: c_uint = 0x100; static DW_TAG_arg_variable: c_uint = 0x101; @@ -118,11 +118,63 @@ impl DebugContext { } } -pub struct FunctionDebugContext { - priv scope_map: HashMap, - priv fn_metadata: DISubprogram, - priv argument_counter: uint, - priv source_locations_enabled: bool, +pub enum FunctionDebugContext { + priv FunctionDebugContext(~FunctionDebugContextData), + priv DebugInfoDisabled, + priv FunctionWithoutDebugInfo, +} + +impl FunctionDebugContext { + fn get_ref<'a>(&'a self, cx: &CrateContext, span: span) -> &'a FunctionDebugContextData { + match *self { + FunctionDebugContext(~ref data) => data, + DebugInfoDisabled => { + cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \ + although debug info is disabled!"); + } + FunctionWithoutDebugInfo => { + cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \ + for function that should be ignored by debug info!"); + } + } + } + + fn get_mut_ref<'a>(&'a mut self, + cx: &CrateContext, + span: span) + -> &'a mut FunctionDebugContextData { + match *self { + FunctionDebugContext(~ref mut data) => data, + DebugInfoDisabled => { + cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \ + although debug info is disabled!"); + } + FunctionWithoutDebugInfo => { + cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \ + for function that should be ignored by debug info!"); + } + } + } +} + +struct FunctionDebugContextData { + scope_map: HashMap, + fn_metadata: DISubprogram, + argument_counter: uint, + source_locations_enabled: bool, +} + +enum VariableAccess { + // The value given is a pointer to data + DirectVariable, + // The value given has to be dereferenced once to get the pointer to data + IndirectVariable +} + +enum VariableKind { + ArgumentVariable(uint /*index*/), + LocalVariable, + CapturedVariable, } /// Create any deferred debug metadata nodes @@ -138,7 +190,12 @@ pub fn finalize(cx: @mut CrateContext) { /// Creates debug information for the given local variable. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) { +pub fn create_local_var_metadata(bcx: @mut Block, + local: &ast::Local) { + if fn_should_be_ignored(bcx.fcx) { + return; + } + let cx = bcx.ccx(); let def_map = cx.tcx.def_map; @@ -147,10 +204,66 @@ pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) { let var_ident = ast_util::path_to_ident(path_ref); let var_type = node_id_type(bcx, node_id); - declare_local(bcx, var_ident, node_id, var_type, span); + 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)); + } + }; + + let scope_metadata = scope_metadata(bcx.fcx, node_id, span); + + declare_local(bcx, + llptr, + var_ident, + var_type, + scope_metadata, + DirectVariable, + LocalVariable, + span); } } +/// Creates debug information for a local variable introduced in the head of a match-statement arm. +/// +// /// Adds the created metadata nodes directly to the crate's IR. +pub fn create_captured_var_metadata(bcx: @mut Block, + node_id: ast::NodeId, + llptr: ValueRef, + span: span) { + if fn_should_be_ignored(bcx.fcx) { + return; + } + + let cx = bcx.ccx(); + + let ast_item = cx.tcx.items.find_copy(&node_id); + let variable_ident = match ast_item { + None => { + cx.sess.span_bug(span, "debuginfo::create_captured_var_metadata() - NodeId not found"); + } + Some(ast_map::node_local(ident)) => ident, + Some(ast_map::node_arg(@ast::pat { node: ast::pat_ident(_, ref path, _), _ })) => { + ast_util::path_to_ident(path) + } + _ => { + cx.sess.span_bug(span, fmt!("debuginfo::create_captured_var_metadata() - \ + Captured var-id refers to unexpected ast_map variant: %?", ast_item)); + } + }; + let variable_type = node_id_type(bcx, node_id); + let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata; + + declare_local(bcx, + llptr, + variable_ident, + variable_type, + scope_metadata, + IndirectVariable, + CapturedVariable, + span); +} + /// Creates debug information for a local variable introduced in the head of a match-statement arm. /// /// Adds the created metadata nodes directly to the crate's IR. @@ -158,62 +271,76 @@ 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); + span: span) { + if fn_should_be_ignored(bcx.fcx) { + return; + } + + 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)); + } + }; + + let scope_metadata = scope_metadata(bcx.fcx, node_id, span); + + declare_local(bcx, + llptr, + variable_ident, + variable_type, + scope_metadata, + DirectVariable, + LocalVariable, + span); } /// Creates debug information for the self argument of a method. /// /// Adds the created metadata nodes directly to the crate's IR. pub fn create_self_argument_metadata(bcx: @mut Block, - variable_type: ty::t, + type_of_self: ty::t, llptr: ValueRef) { - assert_fcx_has_span(bcx.fcx); - let span = bcx.fcx.span.unwrap(); - - let cx = bcx.ccx(); + if fn_should_be_ignored(bcx.fcx) { + return; + } - let filename = span_start(cx, span).file.name; - let file_metadata = file_metadata(cx, filename); + // Extract the span of the self argument from the method's AST + let fnitem = bcx.ccx().tcx.items.get_copy(&bcx.fcx.id); + let span = match fnitem { + ast_map::node_method(@ast::method { explicit_self: explicit_self, _ }, _, _) => { + explicit_self.span + } + ast_map::node_trait_method( + @ast::provided( + @ast::method { + explicit_self: explicit_self, + _ + }), + _, + _) => { + explicit_self.span + } + _ => bcx.ccx().sess.bug(fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) + }; - let loc = span_start(cx, span); - let type_metadata = type_metadata(cx, variable_type, span); - let scope = bcx.fcx.debug_context.get_ref().fn_metadata; + let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata; let argument_index = { - let counter = &mut bcx.fcx.debug_context.get_mut_ref().argument_counter; + let counter = &mut bcx.fcx.debug_context.get_mut_ref(bcx.ccx(), span).argument_counter; let argument_index = *counter; *counter += 1; - argument_index as c_uint - }; - - let var_metadata = do cx.sess.str_of(special_idents::self_).to_c_str().with_ref |name| { - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - DW_TAG_arg_variable, - scope, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - false, - 0, - argument_index) - } + argument_index }; - set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col)); - unsafe { - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( - DIB(cx), - llptr, - var_metadata, - bcx.llbb); - - llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); - } - set_debug_location(cx, UnknownLocation); + declare_local(bcx, + llptr, + special_idents::self_, + type_of_self, + scope_metadata, + DirectVariable, + ArgumentVariable(argument_index), + span); } /// Creates debug information for the given function argument. @@ -221,54 +348,22 @@ pub fn create_self_argument_metadata(bcx: @mut Block, /// Adds the created metadata nodes directly to the crate's IR. pub fn create_argument_metadata(bcx: @mut Block, arg: &ast::arg) { + if fn_should_be_ignored(bcx.fcx) { + return; + } + let fcx = bcx.fcx; let cx = fcx.ccx; let pattern = arg.pat; let filename = span_start(cx, pattern.span).file.name; - if fcx.id == -1 || - fcx.span.is_none() || - "" == filename { - return; - } - let def_map = cx.tcx.def_map; let file_metadata = file_metadata(cx, filename); - let scope = bcx.fcx.debug_context.get_ref().fn_metadata;//create_function_metadata(fcx); + let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata; do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| { - let ty = node_id_type(bcx, node_id); - let type_metadata = type_metadata(cx, ty, codemap::dummy_sp()); - let loc = span_start(cx, span); - let ident = ast_util::path_to_ident(path_ref); - let name: &str = cx.sess.str_of(ident); - debug!("create_argument_metadata: %s", name); - - let argument_index = { - let counter = &mut fcx.debug_context.get_mut_ref().argument_counter; - let argument_index = *counter; - *counter += 1; - argument_index as c_uint - }; - - let arg_metadata = do name.with_c_str |name| { - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - DW_TAG_arg_variable, - scope, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - false, - 0, - argument_index) - } - }; - let llptr = match bcx.fcx.llargs.find_copy(&node_id) { Some(v) => v, None => { @@ -276,17 +371,24 @@ pub fn create_argument_metadata(bcx: @mut Block, } }; - set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col)); - unsafe { - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( - DIB(cx), - llptr, - arg_metadata, - bcx.llbb); + let argument_type = node_id_type(bcx, node_id); + let argument_ident = ast_util::path_to_ident(path_ref); - llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); - } - set_debug_location(cx, UnknownLocation); + let argument_index = { + let counter = &mut fcx.debug_context.get_mut_ref(cx, span).argument_counter; + let argument_index = *counter; + *counter += 1; + argument_index + }; + + declare_local(bcx, + llptr, + argument_ident, + argument_type, + scope_metadata, + DirectVariable, + ArgumentVariable(argument_index), + span); } } @@ -296,16 +398,16 @@ pub fn create_argument_metadata(bcx: @mut Block, /// reliably find the correct visibility scope for the code position. pub fn set_source_location(fcx: &FunctionContext, node_id: ast::NodeId, - span: Span) { - let cx: &mut CrateContext = fcx.ccx; - - if !cx.sess.opts.debuginfo || (*span.lo == 0 && *span.hi == 0) { + span: span) { + if fn_should_be_ignored(fcx) { return; } + let cx = fcx.ccx; + debug!("set_source_location: %s", cx.sess.codemap.span_to_str(span)); - if fcx.debug_context.get_ref().source_locations_enabled { + if fcx.debug_context.get_ref(cx, span).source_locations_enabled { let loc = span_start(cx, span); let scope = scope_metadata(fcx, node_id, span); @@ -316,16 +418,23 @@ pub fn set_source_location(fcx: &FunctionContext, } pub fn start_emitting_source_locations(fcx: &mut FunctionContext) { - for debug_context in fcx.debug_context.mut_iter() { - debug_context.source_locations_enabled = true; + match fcx.debug_context { + FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true, + _ => { /* safe to ignore */} } } pub fn create_function_debug_context(cx: &mut CrateContext, fn_ast_id: ast::NodeId, param_substs: Option<@param_substs>, - llfn: ValueRef) -> ~FunctionDebugContext { - assert!(fn_ast_id != -1); + llfn: ValueRef) -> FunctionDebugContext { + if !cx.sess.opts.debuginfo { + return DebugInfoDisabled; + } + + if fn_ast_id == -1 { + return FunctionWithoutDebugInfo; + } let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty }; @@ -395,9 +504,18 @@ pub fn create_function_debug_context(cx: &mut CrateContext, _) => { (ident, fn_decl, generics, None, span) } + ast_map::node_variant(*) | + ast_map::node_struct_ctor(*) => { + return FunctionWithoutDebugInfo; + } _ => cx.sess.bug(fmt!("create_function_debug_context: unexpected sort of node: %?", fnitem)) }; + // This can be the case for functions inlined from another crate + if span == codemap::dummy_sp() { + return FunctionWithoutDebugInfo; + } + let loc = span_start(cx, span); let file_metadata = file_metadata(cx, loc.file.name); @@ -438,7 +556,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext, }; // Initialize fn debug context (including scope map) - let mut fn_debug_context = ~FunctionDebugContext { + let mut fn_debug_context = ~FunctionDebugContextData { scope_map: HashMap::new(), fn_metadata: fn_metadata, argument_counter: 1, @@ -448,7 +566,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext, let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat }; populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map); - return fn_debug_context; + return FunctionDebugContext(fn_debug_context); fn get_function_signature(cx: &mut CrateContext, fn_ast_id: ast::NodeId, @@ -631,19 +749,28 @@ fn compile_unit_metadata(cx: @mut CrateContext) { do "".with_c_str |flags| { do "".with_c_str |split_name| { unsafe { - llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder, - DW_LANG_RUST as c_uint, crate_name, work_dir, producer, + llvm::LLVMDIBuilderCreateCompileUnit( + dcx.builder, + DW_LANG_RUST, + crate_name, + work_dir, + producer, cx.sess.opts.optimize != session::No, - flags, 0, split_name); + flags, + 0, + split_name); } }}}}}; } fn declare_local(bcx: @mut Block, - variable_ident: ast::Ident, - node_id: ast::NodeId, + llptr: ValueRef, + variable_ident: ast::ident, variable_type: ty::t, - span: Span) { + scope_metadata: DIScope, + variable_access: VariableAccess, + variable_kind: VariableKind, + span: span) { let cx: &mut CrateContext = bcx.ccx(); let filename = span_start(cx, span).file.name; @@ -652,32 +779,48 @@ fn declare_local(bcx: @mut Block, 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 argument_index = match variable_kind { + ArgumentVariable(index) => index, + LocalVariable | + CapturedVariable => 0 + } as c_uint; let var_metadata = do name.with_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) - } - }; + match variable_access { + DirectVariable => unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + DW_TAG_auto_variable, + scope_metadata, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess.opts.optimize != session::No, + 0, + argument_index) + }, + IndirectVariable => unsafe { + let address_op = llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()); + let address_op_count = 1; - 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)); + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + DW_TAG_auto_variable, + scope_metadata, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + ptr::to_unsafe_ptr(&address_op), + address_op_count, + argument_index) + } } }; - set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col)); + set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, *loc.col)); unsafe { let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( DIB(cx), @@ -687,6 +830,14 @@ fn declare_local(bcx: @mut Block, llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); } + + match variable_kind { + ArgumentVariable(_) | CapturedVariable => { + assert!(!bcx.fcx.debug_context.get_ref(cx, span).source_locations_enabled); + set_debug_location(cx, UnknownLocation); + } + _ => { /* fallthrough */ } + } } fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile { @@ -720,13 +871,9 @@ fn file_metadata(cx: &mut 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) -> DIScope { - if fcx.debug_context.is_none() { - fcx.ccx.sess.span_bug(span, "debuginfo: FunctionDebugContext should be initialized \ - but is not!"); - } - - let scope_map = &fcx.debug_context.get_ref().scope_map; + span: span) + -> DIScope { + let scope_map = &fcx.debug_context.get_ref(fcx.ccx, span).scope_map; match scope_map.find_copy(&node_id) { Some(scope_metadata) => scope_metadata, @@ -1260,30 +1407,31 @@ fn vec_slice_metadata(cx: &mut CrateContext, } } -fn bare_fn_metadata(cx: &mut CrateContext, - _fn_ty: ty::t, - inputs: ~[ty::t], - output: ty::t, - span: Span) - -> DICompositeType { - - debug!("bare_fn_metadata: %?", ty::get(_fn_ty)); - +fn subroutine_type_metadata(cx: &mut CrateContext, + signature: &ty::FnSig, + span: span) + -> DICompositeType { let loc = span_start(cx, span); let file_metadata = file_metadata(cx, loc.file.name); - let nil_pointer_type_metadata = type_metadata(cx, ty::mk_nil_ptr(cx.tcx), span); - let output_metadata = type_metadata(cx, output, span); - let output_ptr_metadata = pointer_type_metadata(cx, output, output_metadata); + let mut signature_metadata: ~[DIType] = vec::with_capacity(signature.inputs.len() + 1); + + // return type + signature_metadata.push(match ty::get(signature.output).sty { + ty::ty_nil => ptr::null(), + _ => type_metadata(cx, signature.output, span) + }); - let inputs_vals = do inputs.map |arg| { type_metadata(cx, *arg, span) }; - let members = ~[output_ptr_metadata, nil_pointer_type_metadata] + inputs_vals; + // regular arguments + for &argument_type in signature.inputs.iter() { + signature_metadata.push(type_metadata(cx, argument_type, span)); + } return unsafe { llvm::LLVMDIBuilderCreateSubroutineType( DIB(cx), file_metadata, - create_DIArray(DIB(cx), members)) + create_DIArray(DIB(cx), signature_metadata)) }; } @@ -1407,13 +1555,10 @@ fn type_metadata(cx: &mut CrateContext, pointer_type_metadata(cx, t, pointee) }, ty::ty_bare_fn(ref barefnty) => { - let inputs = barefnty.sig.inputs.map(|a| *a); - let output = barefnty.sig.output; - bare_fn_metadata(cx, t, inputs, output, span) + subroutine_type_metadata(cx, &barefnty.sig, span) }, - ty::ty_closure(ref _closurety) => { - cx.sess.span_note(span, "debuginfo for closure NYI"); - unimplemented_type_metadata(cx, t) + ty::ty_closure(ref closurety) => { + subroutine_type_metadata(cx, &closurety.sig, span) }, ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => { cx.sess.span_note(span, "debuginfo for trait NYI"); @@ -1458,7 +1603,6 @@ fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) { return; } - let metadata_node; match debug_location { @@ -1524,6 +1668,13 @@ fn assert_fcx_has_span(fcx: &FunctionContext) { } } +fn fn_should_be_ignored(fcx: &FunctionContext) -> bool { + match fcx.debug_context { + FunctionDebugContext(_) => false, + _ => true + } +} + // 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. // diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index e3023b919f879..518d0fb0c38ca 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -73,7 +73,7 @@ pub enum ast_node { node_variant(variant, @item, @path), node_expr(@Expr), node_stmt(@Stmt), - node_arg, + node_arg(@pat), node_local(Ident), node_block(Block), node_struct_ctor(@struct_def, @item, @path), @@ -171,7 +171,7 @@ impl Ctx { sp: codemap::Span, id: NodeId) { for a in decl.inputs.iter() { - self.map.insert(a.id, node_arg); + self.map.insert(a.id, node_arg(a.pat)); } visit::walk_fn(self, fk, decl, body, sp, id, ()); } @@ -487,8 +487,8 @@ pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str { fmt!("stmt %s (id=%?)", pprust::stmt_to_str(stmt, itr), id) } - Some(&node_arg) => { - fmt!("arg (id=%?)", id) + Some(&node_arg(pat)) => { + fmt!("arg %s (id=%?)", pprust::pat_to_str(pat, itr), id) } Some(&node_local(ident)) => { fmt!("local (id=%?, name=%s)", id, itr.get(ident.name)) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 54af6fe7e73ba..376adf24e25fd 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -724,3 +724,39 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter( LineNo, ColumnNo)); } + +extern "C" LLVMValueRef LLVMDIBuilderCreateOpDeref(LLVMTypeRef IntTy) +{ + return LLVMConstInt(IntTy, DIBuilder::OpDeref, true); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateOpPlus(LLVMTypeRef IntTy) +{ + return LLVMConstInt(IntTy, DIBuilder::OpPlus, true); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateComplexVariable( + DIBuilderRef Builder, + unsigned Tag, + LLVMValueRef Scope, + const char *Name, + LLVMValueRef File, + unsigned LineNo, + LLVMValueRef Ty, + LLVMValueRef* AddrOps, + unsigned AddrOpsCount, + unsigned ArgNo) +{ + llvm::ArrayRef addr_ops((llvm::Value**)AddrOps, AddrOpsCount); + + return wrap(Builder->createComplexVariable( + Tag, + unwrapDI(Scope), + Name, + unwrapDI(File), + LineNo, + unwrapDI(Ty), + addr_ops, + ArgNo + )); +} diff --git a/src/test/debug-info/var-captured-in-managed-closure.rs b/src/test/debug-info/var-captured-in-managed-closure.rs new file mode 100644 index 0000000000000..37f5fef471b6d --- /dev/null +++ b/src/test/debug-info/var-captured-in-managed-closure.rs @@ -0,0 +1,58 @@ +// 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 or the MIT license +// , 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 constant +// check:$1 = 1 +// debugger:print a_struct +// check:$2 = {a = -2, b = 3.5, c = 4} +// debugger:print *owned +// check:$3 = 5 +// debugger:print managed->val +// check:$4 = 6 + +#[allow(unused_variable)]; + +struct Struct { + a: int, + b: float, + c: uint +} + +fn main() { + let constant = 1; + + let a_struct = Struct { + a: -2, + b: 3.5, + c: 4 + }; + + let owned = ~5; + let managed = @6; + + let closure: @fn() = || { + zzz(); + do_something(&constant, &a_struct.a, owned, managed); + }; + + closure(); +} + +fn do_something(_: &int, _:&int, _:&int, _:&int) { +} + +fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-sendable-closure.rs b/src/test/debug-info/var-captured-in-sendable-closure.rs new file mode 100644 index 0000000000000..c4568bd592fa6 --- /dev/null +++ b/src/test/debug-info/var-captured-in-sendable-closure.rs @@ -0,0 +1,56 @@ +// 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 or the MIT license +// , 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 constant +// check:$1 = 1 +// debugger:print a_struct +// check:$2 = {a = -2, b = 3.5, c = 4} +// debugger:print *owned +// check:$3 = 5 + +#[allow(unused_variable)]; + +struct Struct { + a: int, + b: float, + c: uint +} + +fn main() { + let constant = 1; + + let a_struct = Struct { + a: -2, + b: 3.5, + c: 4 + }; + + let owned = ~5; + + let closure: ~fn() = || { + zzz(); + do_something(&constant, &a_struct.a, owned); + }; + + closure(); +} + +fn do_something(_: &int, _:&int, _:&int) { + +} + +fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-stack-closure.rs b/src/test/debug-info/var-captured-in-stack-closure.rs new file mode 100644 index 0000000000000..6694d5111a835 --- /dev/null +++ b/src/test/debug-info/var-captured-in-stack-closure.rs @@ -0,0 +1,61 @@ +// 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 or the MIT license +// , 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 variable +// check:$1 = 1 +// debugger:print constant +// check:$2 = 2 +// debugger:print a_struct +// check:$3 = {a = -3, b = 4.5, c = 5} +// debugger:print *struct_ref +// check:$4 = {a = -3, b = 4.5, c = 5} +// debugger:print *owned +// check:$5 = 6 +// debugger:print managed->val +// check:$6 = 7 + +#[allow(unused_variable)]; + +struct Struct { + a: int, + b: float, + c: uint +} + +fn main() { + let mut variable = 1; + let constant = 2; + + let a_struct = Struct { + a: -3, + b: 4.5, + c: 5 + }; + + let struct_ref = &a_struct; + let owned = ~6; + let managed = @7; + + let closure = || { + zzz(); + variable = constant + a_struct.a + struct_ref.a + *owned + *managed; + }; + + closure(); +} + +fn zzz() {()} From 30375ccb303807223dac67a74a0a0f6a3c37263f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 28 Aug 2013 17:47:31 +0200 Subject: [PATCH 2/7] debuginfo: Support for by-value arguments (still excluding some cases of self arguments) --- src/librustc/lib/llvm.rs | 6 ++ src/librustc/middle/trans/debuginfo.rs | 16 +++- .../by-value-self-argument-in-trait-impl.rs | 79 +++++++++++++++++++ .../debug-info/by-value-struct-argument.rs | 3 - 4 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 src/test/debug-info/by-value-self-argument-in-trait-impl.rs diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 7903e6f02fa2e..9e81ee5e64ccf 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2103,6 +2103,12 @@ pub mod llvm { ArgNo: c_uint) -> ValueRef; + #[fast_ffi] + pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; + + #[fast_ffi] + pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; + pub fn LLVMInitializeX86TargetInfo(); pub fn LLVMInitializeX86Target(); pub fn LLVMInitializeX86TargetMC(); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 049dee6bfea96..70eb54313ca63 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -333,12 +333,18 @@ pub fn create_self_argument_metadata(bcx: @mut Block, argument_index }; + let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() { + DirectVariable + } else { + IndirectVariable + }; + declare_local(bcx, llptr, special_idents::self_, type_of_self, scope_metadata, - DirectVariable, + variable_access, ArgumentVariable(argument_index), span); } @@ -371,6 +377,12 @@ pub fn create_argument_metadata(bcx: @mut Block, } }; + let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() { + DirectVariable + } else { + IndirectVariable + }; + let argument_type = node_id_type(bcx, node_id); let argument_ident = ast_util::path_to_ident(path_ref); @@ -386,7 +398,7 @@ pub fn create_argument_metadata(bcx: @mut Block, argument_ident, argument_type, scope_metadata, - DirectVariable, + variable_access, ArgumentVariable(argument_index), span); } diff --git a/src/test/debug-info/by-value-self-argument-in-trait-impl.rs b/src/test/debug-info/by-value-self-argument-in-trait-impl.rs new file mode 100644 index 0000000000000..6e381c74a339e --- /dev/null +++ b/src/test/debug-info/by-value-self-argument-in-trait-impl.rs @@ -0,0 +1,79 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run + +// debugger:finish +// debugger:print self +// check:$1 = 1111 +// debugger:continue + +// debugger:finish +// debugger:print self +// check:$2 = {x = 2222, y = 3333} +// debugger:continue + +// debugger:finish +// debugger:print self +// check:$3 = {4444.5, 5555, 6666, 7777.5} +// debugger:continue + +// debugger:finish +// debugger:print self->val +// check:$4 = 8888 +// debugger:continue + +trait Trait { + fn method(self) -> Self; +} + +impl Trait for int { + fn method(self) -> int { + zzz(); + self + } +} + +struct Struct { + x: uint, + y: uint, +} + +impl Trait for Struct { + fn method(self) -> Struct { + zzz(); + self + } +} + +impl Trait for (float, int, int, float) { + fn method(self) -> (float, int, int, float) { + zzz(); + self + } +} + +impl Trait for @int { + fn method(self) -> @int { + zzz(); + self + } +} + +fn main() { + let _ = (1111 as int).method(); + let _ = Struct { x: 2222, y: 3333 }.method(); + let _ = (4444.5, 5555, 6666, 7777.5).method(); + let _ = (@8888).method(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/by-value-struct-argument.rs b/src/test/debug-info/by-value-struct-argument.rs index 052b3c6994a9c..73bd805a6f4c7 100644 --- a/src/test/debug-info/by-value-struct-argument.rs +++ b/src/test/debug-info/by-value-struct-argument.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Does not work yet, see issue #8512 -// xfail-test - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run From c19f493129e45e1f23aaf67900d092fcc2a81ff3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 29 Aug 2013 11:44:11 +0200 Subject: [PATCH 3/7] debuginfo: Added test cases for structs, tuples, enums, etc passed by value. Also updated documentation comments in debuginfo and renamed DebugContext to CrateDebugContext. --- src/librustc/middle/trans/context.rs | 4 +- src/librustc/middle/trans/debuginfo.rs | 49 +++++---- src/rustllvm/rustllvm.def.in | 3 + .../by-value-non-immediate-argument.rs | 99 +++++++++++++++++++ .../debug-info/by-value-struct-argument.rs | 34 ------- .../var-captured-in-managed-closure.rs | 2 - .../var-captured-in-nested-closure.rs | 74 ++++++++++++++ .../var-captured-in-sendable-closure.rs | 2 - .../var-captured-in-stack-closure.rs | 2 - 9 files changed, 206 insertions(+), 63 deletions(-) create mode 100644 src/test/debug-info/by-value-non-immediate-argument.rs delete mode 100644 src/test/debug-info/by-value-struct-argument.rs create mode 100644 src/test/debug-info/var-captured-in-nested-closure.rs diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index e7781e93d8cec..59159f61f485f 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -111,7 +111,7 @@ pub struct CrateContext { // decl_gc_metadata knows whether to link to the module metadata, which // is not emitted by LLVM's GC pass when no functions use GC. uses_gc: bool, - dbg_cx: Option, + dbg_cx: Option, do_not_commit_warning_issued: bool } @@ -161,7 +161,7 @@ impl CrateContext { let crate_map = decl_crate_map(sess, link_meta, llmod); let dbg_cx = if sess.opts.debuginfo { - Some(debuginfo::DebugContext::new(llmod, name.to_owned())) + Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned())) } else { None }; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 70eb54313ca63..1a39e0aa1a0f6 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -27,7 +27,7 @@ where possible. This will hopefully ease the adaption of this module to future L The public API of the module is a set of functions that will insert the correct metadata into the LLVM IR when called with the right parameters. The module is thus driven from an outside client with -functions like `debuginfo::local_var_metadata(bcx: block, local: &ast::local)`. +functions like `debuginfo::create_local_var_metadata(bcx: block, local: &ast::local)`. Internally the module will try to reuse already created metadata by utilizing a cache. The way to get a shared metadata node when needed is thus to just call the corresponding function in this @@ -37,9 +37,8 @@ module: The function will take care of probing the cache for an existing node for that exact file path. -All private state used by the module is stored within a DebugContext struct, which in turn is -contained in the CrateContext. - +All private state used by the module is stored within either the CrateDebugContext struct (owned by +the CrateContext) or the FunctionDebugContext (owned by the FunctionContext). This file consists of three conceptual sections: 1. The public interface of the module @@ -92,7 +91,7 @@ static DW_ATE_unsigned_char: c_uint = 0x08; //=------------------------------------------------------------------------------------------------- /// A context object for maintaining all state needed by the debuginfo module. -pub struct DebugContext { +pub struct CrateDebugContext { priv crate_file: ~str, priv llcontext: ContextRef, priv builder: DIBuilderRef, @@ -101,13 +100,13 @@ pub struct DebugContext { priv created_types: HashMap, } -impl DebugContext { - pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext { - debug!("DebugContext::new"); +impl CrateDebugContext { + pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext { + debug!("CrateDebugContext::new"); let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; - return DebugContext { + return CrateDebugContext { crate_file: crate, llcontext: llcontext, builder: builder, @@ -165,9 +164,9 @@ struct FunctionDebugContextData { } enum VariableAccess { - // The value given is a pointer to data + // The value given is a pointer to the data (T*) DirectVariable, - // The value given has to be dereferenced once to get the pointer to data + // The value given has to be dereferenced once to get the pointer to data (T**) IndirectVariable } @@ -224,9 +223,9 @@ pub fn create_local_var_metadata(bcx: @mut Block, } } -/// Creates debug information for a local variable introduced in the head of a match-statement arm. +/// Creates debug information for a variable captured in a closure. /// -// /// Adds the created metadata nodes directly to the crate's IR. +/// Adds the created metadata nodes directly to the crate's IR. pub fn create_captured_var_metadata(bcx: @mut Block, node_id: ast::NodeId, llptr: ValueRef, @@ -321,7 +320,8 @@ pub fn create_self_argument_metadata(bcx: @mut Block, _) => { explicit_self.span } - _ => bcx.ccx().sess.bug(fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) + _ => bcx.ccx().sess.bug( + fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) }; let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata; @@ -361,14 +361,10 @@ pub fn create_argument_metadata(bcx: @mut Block, let fcx = bcx.fcx; let cx = fcx.ccx; - let pattern = arg.pat; - let filename = span_start(cx, pattern.span).file.name; - let def_map = cx.tcx.def_map; - let file_metadata = file_metadata(cx, filename); let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata; - do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| { + do pat_util::pat_bindings(def_map, arg.pat) |_, node_id, span, path_ref| { let llptr = match bcx.fcx.llargs.find_copy(&node_id) { Some(v) => v, @@ -429,13 +425,24 @@ pub fn set_source_location(fcx: &FunctionContext, } } +/// Enables emitting source locations for the given functions. +/// +/// Since we don't want source locations to be emitted for the function prelude, they are disabled +/// when beginning to translate a new function. This functions switches source location emitting on +/// and must therefore be called before the first real statement/expression of the function is +/// translated. pub fn start_emitting_source_locations(fcx: &mut FunctionContext) { match fcx.debug_context { FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true, - _ => { /* safe to ignore */} + _ => { /* safe to ignore */ } } } +/// Creates the function-specific debug context. +/// +/// Returns the FunctionDebugContext for the function which holds state needed for debug info +/// creation. The function may also return another variant of the FunctionDebugContext enum which +/// indicates why no debuginfo should be created for the function. pub fn create_function_debug_context(cx: &mut CrateContext, fn_ast_id: ast::NodeId, param_substs: Option<@param_substs>, @@ -1663,7 +1670,7 @@ fn bytes_to_bits(bytes: uint) -> c_ulonglong { } #[inline] -fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { +fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext { cx.dbg_cx.get_mut_ref() } diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index e2cec6a04f346..79cfe8b28519a 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -608,6 +608,9 @@ LLVMDIBuilderCreateEnumerator LLVMDIBuilderCreateEnumerationType LLVMDIBuilderCreateUnionType LLVMDIBuilderCreateTemplateTypeParameter +LLVMDIBuilderCreateOpDeref +LLVMDIBuilderCreateOpPlus +LLVMDIBuilderCreateComplexVariable LLVMSetUnnamedAddr LLVMRustAddPass LLVMRustAddAnalysisPasses diff --git a/src/test/debug-info/by-value-non-immediate-argument.rs b/src/test/debug-info/by-value-non-immediate-argument.rs new file mode 100644 index 0000000000000..da9c79a00ed47 --- /dev/null +++ b/src/test/debug-info/by-value-non-immediate-argument.rs @@ -0,0 +1,99 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run + +// debugger:finish +// debugger:print s +// check:$1 = {a = 1, b = 2.5} +// debugger:continue + +// debugger:finish +// debugger:print x +// check:$2 = {a = 3, b = 4.5} +// debugger:print y +// check:$3 = 5 +// debugger:print z +// check:$4 = 6.5 +// debugger:continue + +// debugger:finish +// debugger:print a +// check:$5 = {7, 8, 9.5, 10.5} +// debugger:continue + +// debugger:finish +// debugger:print a +// check:$6 = {11.5, 12.5, 13, 14} +// debugger:continue + +// debugger:finish +// debugger:print x +// check:$7 = {{Case1, x = 0, y = 8970181431921507452}, {Case1, 0, 2088533116, 2088533116}} +// debugger:continue + +#[deriving(Clone)] +struct Struct { + a: int, + b: float +} + +#[deriving(Clone)] +struct StructStruct { + a: Struct, + b: Struct +} + +fn fun(s: Struct) { + zzz(); +} + +fn fun_fun(StructStruct { a: x, b: Struct { a: y, b: z } }: StructStruct) { + zzz(); +} + +fn tup(a: (int, uint, float, float)) { + zzz(); +} + +struct Newtype(float, float, int, uint); + +fn new_type(a: Newtype) { + zzz(); +} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum Enum { + Case1 { x: i64, y: i64 }, + Case2 (i64, i32, i32), +} + +fn by_val_enum(x: Enum) { + zzz(); +} + +fn main() { + fun(Struct { a: 1, b: 2.5 }); + fun_fun(StructStruct { a: Struct { a: 3, b: 4.5 }, b: Struct { a: 5, b: 6.5 } }); + tup((7, 8, 9.5, 10.5)); + new_type(Newtype(11.5, 12.5, 13, 14)); + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + by_val_enum(Case1 { x: 0, y: 8970181431921507452 }); +} + +fn zzz() {()} diff --git a/src/test/debug-info/by-value-struct-argument.rs b/src/test/debug-info/by-value-struct-argument.rs deleted file mode 100644 index 73bd805a6f4c7..0000000000000 --- a/src/test/debug-info/by-value-struct-argument.rs +++ /dev/null @@ -1,34 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags:-Z extra-debug-info -// debugger:break zzz -// debugger:run - -// debugger:finish -// debugger:print s -// check:$1 = {a = 1, b = 2.5} -// debugger:continue - -#[deriving(Clone)] -struct Struct { - a: int, - b: float -} - -fn fun(s: Struct) { - zzz(); -} - -fn main() { - fun(Struct { a: 1, b: 2.5 }); -} - -fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-managed-closure.rs b/src/test/debug-info/var-captured-in-managed-closure.rs index 37f5fef471b6d..002bfbd2242ae 100644 --- a/src/test/debug-info/var-captured-in-managed-closure.rs +++ b/src/test/debug-info/var-captured-in-managed-closure.rs @@ -8,8 +8,6 @@ // 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 diff --git a/src/test/debug-info/var-captured-in-nested-closure.rs b/src/test/debug-info/var-captured-in-nested-closure.rs new file mode 100644 index 0000000000000..60ad2a3544a3d --- /dev/null +++ b/src/test/debug-info/var-captured-in-nested-closure.rs @@ -0,0 +1,74 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print variable +// check:$1 = 1 +// debugger:print constant +// check:$2 = 2 +// debugger:print a_struct +// check:$3 = {a = -3, b = 4.5, c = 5} +// debugger:print *struct_ref +// check:$4 = {a = -3, b = 4.5, c = 5} +// debugger:print *owned +// check:$5 = 6 +// debugger:print managed->val +// check:$6 = 7 +// debugger:print closure_local +// check:$7 = 8 +// debugger:continue + +#[allow(unused_variable)]; + +struct Struct { + a: int, + b: float, + c: uint +} + +fn main() { + let mut variable = 1; + let constant = 2; + + let a_struct = Struct { + a: -3, + b: 4.5, + c: 5 + }; + + let struct_ref = &a_struct; + let owned = ~6; + let managed = @7; + + let closure = || { + let closure_local = 8; + + let nested_closure = || { + zzz(); + variable = constant + a_struct.a + struct_ref.a + *owned + *managed + closure_local; + }; + + // breaking here will yield a wrong value for 'constant'. In particular, GDB will + // read the value of the register that supposedly contains the pointer to 'constant' + // and try derefence it. The register, however, already contains the actual value, and + // not a pointer to it. -mw + // zzz(); + + nested_closure(); + }; + + closure(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-sendable-closure.rs b/src/test/debug-info/var-captured-in-sendable-closure.rs index c4568bd592fa6..01839ea783533 100644 --- a/src/test/debug-info/var-captured-in-sendable-closure.rs +++ b/src/test/debug-info/var-captured-in-sendable-closure.rs @@ -8,8 +8,6 @@ // 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 diff --git a/src/test/debug-info/var-captured-in-stack-closure.rs b/src/test/debug-info/var-captured-in-stack-closure.rs index 6694d5111a835..3ce7d6fd89bdd 100644 --- a/src/test/debug-info/var-captured-in-stack-closure.rs +++ b/src/test/debug-info/var-captured-in-stack-closure.rs @@ -8,8 +8,6 @@ // 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 From 6b2df76c244d1cd282dd724135c4bdcb6e28eb52 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 3 Sep 2013 11:53:06 +0200 Subject: [PATCH 4/7] debuginfo: Always copy args to allocas if debuginfo is enabled --- src/librustc/middle/trans/_match.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index ad0ab95ebf0f1..bc4cc2ce0e161 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -2000,19 +2000,17 @@ pub fn store_arg(mut bcx: @mut Block, let arg_ty = node_id_type(bcx, pat.id); add_clean(bcx, llval, arg_ty); - match simple_identifier(pat) { - Some(_) => { - // Optimized path for `x: T` case. This just adopts - // `llval` wholesale as the pointer for `x`, avoiding the - // general logic which may copy out of `llval`. - bcx.fcx.llargs.insert(pat.id, llval); - } + let fast_path = !bcx.ccx().sess.opts.extra_debuginfo && simple_identifier(pat).is_some(); - None => { - // General path. Copy out the values that are used in the - // pattern. - bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument); - } + if fast_path { + // Optimized path for `x: T` case. This just adopts + // `llval` wholesale as the pointer for `x`, avoiding the + // general logic which may copy out of `llval`. + bcx.fcx.llargs.insert(pat.id, llval); + } else { + // General path. Copy out the values that are used in the + // pattern. + bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument); } return bcx; From e0b63b0e2a83e9c5dca884ddaf1c745e49a597f7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 3 Sep 2013 12:15:56 +0200 Subject: [PATCH 5/7] debuginfo: Fixed some merge fallout --- src/librustc/middle/trans/debuginfo.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 1a39e0aa1a0f6..09956438bb4b4 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -124,7 +124,7 @@ pub enum FunctionDebugContext { } impl FunctionDebugContext { - fn get_ref<'a>(&'a self, cx: &CrateContext, span: span) -> &'a FunctionDebugContextData { + fn get_ref<'a>(&'a self, cx: &CrateContext, span: Span) -> &'a FunctionDebugContextData { match *self { FunctionDebugContext(~ref data) => data, DebugInfoDisabled => { @@ -140,7 +140,7 @@ impl FunctionDebugContext { fn get_mut_ref<'a>(&'a mut self, cx: &CrateContext, - span: span) + span: Span) -> &'a mut FunctionDebugContextData { match *self { FunctionDebugContext(~ref mut data) => data, @@ -229,7 +229,7 @@ pub fn create_local_var_metadata(bcx: @mut Block, pub fn create_captured_var_metadata(bcx: @mut Block, node_id: ast::NodeId, llptr: ValueRef, - span: span) { + span: Span) { if fn_should_be_ignored(bcx.fcx) { return; } @@ -270,7 +270,7 @@ pub fn create_match_binding_metadata(bcx: @mut Block, variable_ident: ast::Ident, node_id: ast::NodeId, variable_type: ty::t, - span: span) { + span: Span) { if fn_should_be_ignored(bcx.fcx) { return; } @@ -406,7 +406,7 @@ pub fn create_argument_metadata(bcx: @mut Block, /// reliably find the correct visibility scope for the code position. pub fn set_source_location(fcx: &FunctionContext, node_id: ast::NodeId, - span: span) { + span: Span) { if fn_should_be_ignored(fcx) { return; } @@ -784,12 +784,12 @@ fn compile_unit_metadata(cx: @mut CrateContext) { fn declare_local(bcx: @mut Block, llptr: ValueRef, - variable_ident: ast::ident, + variable_ident: ast::Ident, variable_type: ty::t, scope_metadata: DIScope, variable_access: VariableAccess, variable_kind: VariableKind, - span: span) { + span: Span) { let cx: &mut CrateContext = bcx.ccx(); let filename = span_start(cx, span).file.name; @@ -890,7 +890,7 @@ fn file_metadata(cx: &mut 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) + span: Span) -> DIScope { let scope_map = &fcx.debug_context.get_ref(fcx.ccx, span).scope_map; @@ -1428,7 +1428,7 @@ fn vec_slice_metadata(cx: &mut CrateContext, fn subroutine_type_metadata(cx: &mut CrateContext, signature: &ty::FnSig, - span: span) + span: Span) -> DICompositeType { let loc = span_start(cx, span); let file_metadata = file_metadata(cx, loc.file.name); From c49eb075dbb8b1921b3056e0fb1cb87fc0397e15 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 3 Sep 2013 18:23:59 +0200 Subject: [PATCH 6/7] debuginfo: Much improved handling of captured variables and by-value arguments. --- src/librustc/middle/trans/_match.rs | 3 + src/librustc/middle/trans/closure.rs | 23 ++- src/librustc/middle/trans/debuginfo.rs | 137 +++++++++++------- .../var-captured-in-nested-closure.rs | 23 ++- 4 files changed, 124 insertions(+), 62 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index bc4cc2ce0e161..39e3e97b48947 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -2000,6 +2000,9 @@ pub fn store_arg(mut bcx: @mut Block, let arg_ty = node_id_type(bcx, pat.id); add_clean(bcx, llval, arg_ty); + // Debug information (the llvm.dbg.declare intrinsic to be precise) always expects to get an + // alloca, which only is the case on the general path, so lets disable the optimized path when + // debug info is enabled. let fast_path = !bcx.ccx().sess.opts.extra_debuginfo && simple_identifier(pat).is_some(); if fast_path { diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index d25fedf2d8e6e..690d7343489e2 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -308,7 +308,17 @@ pub fn load_environment(fcx: @mut FunctionContext, // Load a pointer to the closure data, skipping over the box header: let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv); - // Populate the upvars from the environment. + // Store the pointer to closure data in an alloca for debug info because that's what the + // llvm.dbg.declare intrinsic expects + let env_pointer_alloca = if fcx.ccx.sess.opts.extra_debuginfo { + let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), cdata_ty), "__debuginfo_env_ptr"); + Store(bcx, llcdata, alloc); + Some(alloc) + } else { + None + }; + + // Populate the upvars from the environment let mut i = 0u; for cap_var in cap_vars.iter() { let mut upvarptr = GEPi(bcx, llcdata, [0u, i]); @@ -319,8 +329,15 @@ pub fn load_environment(fcx: @mut FunctionContext, let def_id = ast_util::def_id_of_def(cap_var.def); fcx.llupvars.insert(def_id.node, upvarptr); - if fcx.ccx.sess.opts.extra_debuginfo { - debuginfo::create_captured_var_metadata(bcx, def_id.node, upvarptr, cap_var.span); + for &env_pointer_alloca in env_pointer_alloca.iter() { + debuginfo::create_captured_var_metadata( + bcx, + def_id.node, + cdata_ty, + env_pointer_alloca, + i, + sigil, + cap_var.span); } i += 1u; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 09956438bb4b4..112595d5576b8 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -163,11 +163,12 @@ struct FunctionDebugContextData { source_locations_enabled: bool, } -enum VariableAccess { - // The value given is a pointer to the data (T*) - DirectVariable, - // The value given has to be dereferenced once to get the pointer to data (T**) - IndirectVariable +enum VariableAccess<'self> { + // The llptr given is an alloca containing the variable's value + DirectVariable { alloca: ValueRef }, + // The llptr given is an alloca containing the start of some pointer chain leading to the + // variable's content. + IndirectVariable { alloca: ValueRef, address_operations: &'self [ValueRef] } } enum VariableKind { @@ -213,11 +214,10 @@ pub fn create_local_var_metadata(bcx: @mut Block, let scope_metadata = scope_metadata(bcx.fcx, node_id, span); declare_local(bcx, - llptr, var_ident, var_type, scope_metadata, - DirectVariable, + DirectVariable { alloca: llptr }, LocalVariable, span); } @@ -228,7 +228,10 @@ pub fn create_local_var_metadata(bcx: @mut Block, /// Adds the created metadata nodes directly to the crate's IR. pub fn create_captured_var_metadata(bcx: @mut Block, node_id: ast::NodeId, - llptr: ValueRef, + env_data_type: ty::t, + env_pointer: ValueRef, + env_index: uint, + closure_sigil: ast::Sigil, span: Span) { if fn_should_be_ignored(bcx.fcx) { return; @@ -250,15 +253,39 @@ pub fn create_captured_var_metadata(bcx: @mut Block, Captured var-id refers to unexpected ast_map variant: %?", ast_item)); } }; + let variable_type = node_id_type(bcx, node_id); let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata; + let llvm_env_data_type = type_of::type_of(cx, env_data_type); + let byte_offset_of_var_in_env = machine::llelement_offset(cx, llvm_env_data_type, env_index); + + let address_operations = unsafe { + [llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()), + llvm::LLVMDIBuilderCreateOpPlus(Type::i64().to_ref()), + C_i64(byte_offset_of_var_in_env as i64), + llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref())] + }; + + let address_op_count = match closure_sigil { + ast::BorrowedSigil => { + address_operations.len() + } + ast::ManagedSigil | ast::OwnedSigil => { + address_operations.len() - 1 + } + }; + + let variable_access = IndirectVariable { + alloca: env_pointer, + address_operations: address_operations.slice_to(address_op_count) + }; + declare_local(bcx, - llptr, variable_ident, variable_type, scope_metadata, - IndirectVariable, + variable_access, CapturedVariable, span); } @@ -285,11 +312,10 @@ pub fn create_match_binding_metadata(bcx: @mut Block, let scope_metadata = scope_metadata(bcx.fcx, node_id, span); declare_local(bcx, - llptr, variable_ident, variable_type, scope_metadata, - DirectVariable, + DirectVariable { alloca: llptr }, LocalVariable, span); } @@ -333,14 +359,17 @@ pub fn create_self_argument_metadata(bcx: @mut Block, argument_index }; + let address_operations = &[unsafe { llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()) }]; + let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() { - DirectVariable + DirectVariable { alloca: llptr } } else { - IndirectVariable + // This is not stable and may break with future LLVM versions. llptr should really always + // be an alloca. Anything else is not supported and just works by chance. + IndirectVariable { alloca: llptr, address_operations: address_operations } }; declare_local(bcx, - llptr, special_idents::self_, type_of_self, scope_metadata, @@ -373,11 +402,10 @@ pub fn create_argument_metadata(bcx: @mut Block, } }; - let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() { - DirectVariable - } else { - IndirectVariable - }; + if unsafe { llvm::LLVMIsAAllocaInst(llptr) } == ptr::null() { + cx.sess.span_bug(span, "debuginfo::create_argument_metadata() - \ + Referenced variable location is not an alloca!"); + } let argument_type = node_id_type(bcx, node_id); let argument_ident = ast_util::path_to_ident(path_ref); @@ -390,11 +418,10 @@ pub fn create_argument_metadata(bcx: @mut Block, }; declare_local(bcx, - llptr, argument_ident, argument_type, scope_metadata, - variable_access, + DirectVariable { alloca: llptr }, ArgumentVariable(argument_index), span); } @@ -783,7 +810,6 @@ fn compile_unit_metadata(cx: @mut CrateContext) { } fn declare_local(bcx: @mut Block, - llptr: ValueRef, variable_ident: ast::Ident, variable_type: ty::t, scope_metadata: DIScope, @@ -805,37 +831,40 @@ fn declare_local(bcx: @mut Block, CapturedVariable => 0 } as c_uint; - let var_metadata = do name.with_c_str |name| { + let (var_alloca, var_metadata) = do name.with_c_str |name| { match variable_access { - DirectVariable => unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - DW_TAG_auto_variable, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess.opts.optimize != session::No, - 0, - argument_index) - }, - IndirectVariable => unsafe { - let address_op = llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()); - let address_op_count = 1; - - llvm::LLVMDIBuilderCreateComplexVariable( - DIB(cx), - DW_TAG_auto_variable, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - ptr::to_unsafe_ptr(&address_op), - address_op_count, - argument_index) - } + DirectVariable { alloca } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + DW_TAG_auto_variable, + scope_metadata, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess.opts.optimize != session::No, + 0, + argument_index) + } + ), + IndirectVariable { alloca, address_operations } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + DW_TAG_auto_variable, + scope_metadata, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + vec::raw::to_ptr(address_operations), + address_operations.len() as c_uint, + argument_index) + } + ) } }; @@ -843,7 +872,7 @@ fn declare_local(bcx: @mut Block, unsafe { let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( DIB(cx), - llptr, + var_alloca, var_metadata, bcx.llbb); diff --git a/src/test/debug-info/var-captured-in-nested-closure.rs b/src/test/debug-info/var-captured-in-nested-closure.rs index 60ad2a3544a3d..cd20209ddfd02 100644 --- a/src/test/debug-info/var-captured-in-nested-closure.rs +++ b/src/test/debug-info/var-captured-in-nested-closure.rs @@ -29,6 +29,23 @@ // check:$7 = 8 // debugger:continue +// debugger:finish +// debugger:print variable +// check:$8 = 1 +// debugger:print constant +// check:$9 = 2 +// debugger:print a_struct +// check:$10 = {a = -3, b = 4.5, c = 5} +// debugger:print *struct_ref +// check:$11 = {a = -3, b = 4.5, c = 5} +// debugger:print *owned +// check:$12 = 6 +// debugger:print managed->val +// check:$13 = 7 +// debugger:print closure_local +// check:$14 = 8 +// debugger:continue + #[allow(unused_variable)]; struct Struct { @@ -59,11 +76,7 @@ fn main() { variable = constant + a_struct.a + struct_ref.a + *owned + *managed + closure_local; }; - // breaking here will yield a wrong value for 'constant'. In particular, GDB will - // read the value of the register that supposedly contains the pointer to 'constant' - // and try derefence it. The register, however, already contains the actual value, and - // not a pointer to it. -mw - // zzz(); + zzz(); nested_closure(); }; From 5b94ae93f3d00f5afe3f1d957aad76173ed7e705 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 4 Sep 2013 19:31:13 +0200 Subject: [PATCH 7/7] debuginfo: Fixed some merge fallout --- src/librustc/middle/trans/debuginfo.rs | 2 +- src/libsyntax/ast_map.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 112595d5576b8..646f71ec28ad2 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -245,7 +245,7 @@ pub fn create_captured_var_metadata(bcx: @mut Block, cx.sess.span_bug(span, "debuginfo::create_captured_var_metadata() - NodeId not found"); } Some(ast_map::node_local(ident)) => ident, - Some(ast_map::node_arg(@ast::pat { node: ast::pat_ident(_, ref path, _), _ })) => { + Some(ast_map::node_arg(@ast::Pat { node: ast::PatIdent(_, ref path, _), _ })) => { ast_util::path_to_ident(path) } _ => { diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 518d0fb0c38ca..be67998ac5d51 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -73,7 +73,7 @@ pub enum ast_node { node_variant(variant, @item, @path), node_expr(@Expr), node_stmt(@Stmt), - node_arg(@pat), + node_arg(@Pat), node_local(Ident), node_block(Block), node_struct_ctor(@struct_def, @item, @path),