diff options
| -rw-r--r-- | src/librustc/mir/repr.rs | 19 | ||||
| -rw-r--r-- | src/librustc/mir/visit.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 43 | ||||
| -rw-r--r-- | src/librustc_trans/debuginfo/create_scope_map.rs | 31 | ||||
| -rw-r--r-- | src/librustc_trans/mir/mod.rs | 82 | ||||
| -rw-r--r-- | src/test/debuginfo/function-prologue-stepping-no-stack-check.rs | 22 | ||||
| -rw-r--r-- | src/test/debuginfo/var-captured-in-nested-closure.rs | 11 | ||||
| -rw-r--r-- | src/test/debuginfo/var-captured-in-sendable-closure.rs | 11 | ||||
| -rw-r--r-- | src/test/debuginfo/var-captured-in-stack-closure.rs | 11 |
9 files changed, 176 insertions, 58 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index aacb3aae81c..3bc65124d34 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -52,6 +52,10 @@ pub struct Mir<'tcx> { /// through the resulting reference. pub temp_decls: Vec<TempDecl<'tcx>>, + /// Names and capture modes of all the closure upvars, assuming + /// the first argument is either the closure or a reference to it. + pub upvar_decls: Vec<UpvarDecl>, + /// A span representing this MIR, for error reporting pub span: Span, } @@ -197,7 +201,20 @@ pub struct ArgDecl<'tcx> { /// If true, this argument is a tuple after monomorphization, /// and has to be collected from multiple actual arguments. - pub spread: bool + pub spread: bool, + + /// Either special_idents::invalid or the name of a single-binding + /// pattern associated with this argument. Useful for debuginfo. + pub debug_name: Name +} + +/// A closure capture, with its name and mode. +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct UpvarDecl { + pub debug_name: Name, + + /// If true, the capture is behind a reference. + pub by_ref: bool } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 87f01391049..10afd3dd953 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -248,6 +248,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* var_decls, ref $($mutability)* arg_decls, ref $($mutability)* temp_decls, + upvar_decls: _, ref $($mutability)* span, } = *mir; @@ -599,7 +600,8 @@ macro_rules! make_mir_visitor { arg_decl: & $($mutability)* ArgDecl<'tcx>) { let ArgDecl { ref $($mutability)* ty, - spread: _ + spread: _, + debug_name: _ } = *arg_decl; self.visit_ty(ty); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 2e5b6a952b7..5284a2ef395 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -10,13 +10,15 @@ use hair::cx::Cx; use rustc::middle::region::{CodeExtent, CodeExtentData}; -use rustc::ty::{FnOutput, Ty}; +use rustc::ty::{self, FnOutput, Ty}; use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::hir; +use rustc::hir::pat_util::pat_is_binding; use std::ops::{Index, IndexMut}; use syntax::ast; use syntax::codemap::Span; +use syntax::parse::token; pub struct Builder<'a, 'tcx: 'a> { hir: Cx<'a, 'tcx>, @@ -224,6 +226,29 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, true })); + // Gather the upvars of a closure, if any. + let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { + freevars.iter().map(|fv| { + let by_ref = tcx.upvar_capture(ty::UpvarId { + var_id: fv.def.var_id(), + closure_expr_id: fn_id + }).map_or(false, |capture| match capture { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true + }); + let mut decl = UpvarDecl { + debug_name: token::special_idents::invalid.name, + by_ref: by_ref + }; + if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) { + if let hir::PatKind::Ident(_, ref ident, _) = pat.node { + decl.debug_name = ident.node.name; + } + } + decl + }).collect() + }); + ( Mir { basic_blocks: builder.cfg.basic_blocks, @@ -231,6 +256,7 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, var_decls: builder.var_decls, arg_decls: arg_decls.take().expect("args never built?"), temp_decls: builder.temp_decls, + upvar_decls: upvar_decls, return_ty: return_ty, span: span }, @@ -269,7 +295,20 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), argument_extent, &lvalue, ty); - ArgDecl { ty: ty, spread: false } + let mut name = token::special_idents::invalid.name; + if let Some(pat) = pattern { + if let hir::PatKind::Ident(_, ref ident, _) = pat.node { + if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) { + name = ident.node.name; + } + } + } + + ArgDecl { + ty: ty, + spread: false, + debug_name: name + } }) .collect(); diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 3eebd1f5ea2..4b1292e4086 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -120,21 +120,28 @@ fn make_mir_scope(ccx: &CrateContext, return; }; - scopes[idx] = if !has_variables.contains(idx) { + if !has_variables.contains(idx) { // Do not create a DIScope if there are no variables // defined in this MIR Scope, to avoid debuginfo bloat. - parent_scope - } else { - let loc = span_start(ccx, scope_data.span); - let file_metadata = file_metadata(ccx, &loc.file.name); - unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( - DIB(ccx), - parent_scope, - file_metadata, - loc.line as c_uint, - loc.col.to_usize() as c_uint) + + // However, we don't skip creating a nested scope if + // our parent is the root, because we might want to + // put arguments in the root and not have shadowing. + if parent_scope != fn_metadata { + scopes[idx] = parent_scope; + return; } + } + + let loc = span_start(ccx, scope_data.span); + let file_metadata = file_metadata(ccx, &loc.file.name); + scopes[idx] = unsafe { + llvm::LLVMDIBuilderCreateLexicalBlock( + DIB(ccx), + parent_scope, + file_metadata, + loc.line as c_uint, + loc.col.to_usize() as c_uint) }; } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 1869845ccb1..3edbea88c05 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -126,6 +126,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let scopes = debuginfo::create_mir_scopes(fcx); // Allocate variable and temp allocas + let args = arg_value_refs(&bcx, &mir, &scopes); let vars = mir.var_decls.iter() .map(|decl| (bcx.monomorphize(&decl.ty), decl)) .map(|(mty, decl)| { @@ -156,7 +157,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { TempRef::Operand(None) }) .collect(); - let args = arg_value_refs(&bcx, &mir, &scopes); // Allocate a `Block` for every basic block let block_bcxs: Vec<Block<'blk,'tcx>> = @@ -278,7 +278,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, let byte_offset_of_var_in_tuple = machine::llelement_offset(bcx.ccx(), lltuplety, i); - let address_operations = unsafe { + let ops = unsafe { [llvm::LLVMDIBuilderCreateOpDeref(), llvm::LLVMDIBuilderCreateOpPlus(), byte_offset_of_var_in_tuple as i64] @@ -286,7 +286,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, let variable_access = VariableAccess::IndirectVariable { alloca: lltemp, - address_operations: &address_operations + address_operations: &ops }; declare_local(bcx, token::special_idents::invalid.name, tupled_arg_ty, scope, variable_access, @@ -327,10 +327,78 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, lltemp }; bcx.with_block(|bcx| arg_scope.map(|scope| { - declare_local(bcx, token::special_idents::invalid.name, arg_ty, scope, - VariableAccess::DirectVariable { alloca: llval }, - VariableKind::ArgumentVariable(arg_index + 1), - bcx.fcx().span.unwrap_or(DUMMY_SP)); + // Is this a regular argument? + if arg_index > 0 || mir.upvar_decls.is_empty() { + declare_local(bcx, arg_decl.debug_name, arg_ty, scope, + VariableAccess::DirectVariable { alloca: llval }, + VariableKind::ArgumentVariable(arg_index + 1), + bcx.fcx().span.unwrap_or(DUMMY_SP)); + return; + } + + // Or is it the closure environment? + let (closure_ty, env_ref) = if let ty::TyRef(_, mt) = arg_ty.sty { + (mt.ty, true) + } else { + (arg_ty, false) + }; + let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty { + &substs.upvar_tys[..] + } else { + bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty); + }; + + // Store the pointer to closure data in an alloca for debuginfo + // because that's what the llvm.dbg.declare intrinsic expects. + + // FIXME(eddyb) this shouldn't be necessary but SROA seems to + // mishandle DW_OP_plus not preceded by DW_OP_deref, i.e. it + // doesn't actually strip the offset when splitting the closure + // environment into its components so it ends up out of bounds. + let env_ptr = if !env_ref { + use base::*; + use build::*; + use common::*; + let alloc = alloca(bcx, val_ty(llval), "__debuginfo_env_ptr"); + Store(bcx, llval, alloc); + alloc + } else { + llval + }; + + let llclosurety = type_of::type_of(bcx.ccx(), closure_ty); + for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { + let byte_offset_of_var_in_env = + machine::llelement_offset(bcx.ccx(), llclosurety, i); + + let ops = unsafe { + [llvm::LLVMDIBuilderCreateOpDeref(), + llvm::LLVMDIBuilderCreateOpPlus(), + byte_offset_of_var_in_env as i64, + llvm::LLVMDIBuilderCreateOpDeref()] + }; + + // The environment and the capture can each be indirect. + + // FIXME(eddyb) see above why we have to keep + // a pointer in an alloca for debuginfo atm. + let mut ops = if env_ref || true { &ops[..] } else { &ops[1..] }; + + let ty = if let (true, &ty::TyRef(_, mt)) = (decl.by_ref, &ty.sty) { + mt.ty + } else { + ops = &ops[..ops.len() - 1]; + ty + }; + + let variable_access = VariableAccess::IndirectVariable { + alloca: env_ptr, + address_operations: &ops + }; + declare_local(bcx, decl.debug_name, ty, scope, variable_access, + VariableKind::CapturedVariable, + bcx.fcx().span.unwrap_or(DUMMY_SP)); + } })); LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty)) }).collect() diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs index e90f7d649f5..f0ecda92993 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs @@ -251,7 +251,7 @@ #![omit_gdb_pretty_printer_section] #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn immediate_args(a: isize, b: bool, c: f64) { println!(""); } @@ -268,51 +268,51 @@ struct BigStruct { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn non_immediate_args(a: BigStruct, b: BigStruct) { println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn binding(a: i64, b: u64, c: f64) { let x = 0; println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn assignment(mut a: u64, b: u64, c: f64) { a = b; println!(""); } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn function_call(x: u64, y: u64, z: f64) { println!("Hi!") } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn identifier(x: u64, y: u64, z: f64) -> u64 { x } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn return_expr(x: u64, y: u64, z: f64) -> u64 { return x; } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { x + y } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn if_expr(x: u64, y: u64, z: f64) -> u64 { if x + y < 1000 { x @@ -322,7 +322,7 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { while x + y < 1000 { x += z @@ -331,7 +331,7 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { } #[no_stack_check] -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names. +#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars. fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { loop { x += z; diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index d2af828a890..7090377e5db 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -78,7 +78,7 @@ // lldb-command:continue #![allow(unused_variables)] -#![feature(box_syntax, rustc_attrs, stmt_expr_attributes)] +#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -88,7 +88,6 @@ struct Struct { c: usize } -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. fn main() { let mut variable = 1; let constant = 2; @@ -102,14 +101,10 @@ fn main() { let struct_ref = &a_struct; let owned: Box<_> = box 6; - let mut closure = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - || { + let mut closure = || { let closure_local = 8; - let mut nested_closure = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - || { + let mut nested_closure = || { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned + closure_local; }; diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index 26d46040c20..aa269edadd8 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -40,7 +40,7 @@ // lldb-check:[...]$2 = 5 #![allow(unused_variables)] -#![feature(unboxed_closures, box_syntax, rustc_attrs, stmt_expr_attributes)] +#![feature(unboxed_closures, box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -50,7 +50,6 @@ struct Struct { c: usize } -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. fn main() { let constant = 1; @@ -62,9 +61,7 @@ fn main() { let owned: Box<_> = box 5; - let closure = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - move || { + let closure = move || { zzz(); // #break do_something(&constant, &a_struct.a, &*owned); }; @@ -76,9 +73,7 @@ fn main() { // The `self` argument of the following closure should be passed by value // to FnOnce::call_once(self, args), which gets translated a bit differently // than the regular case. Let's make sure this is supported too. - let immedate_env = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - move || { + let immedate_env = move || { zzz(); // #break return constant2; }; diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index a22fbebfd1a..6def5cf2859 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -69,7 +69,7 @@ // lldb-command:print *owned // lldb-check:[...]$9 = 6 -#![feature(unboxed_closures, box_syntax, rustc_attrs, stmt_expr_attributes)] +#![feature(unboxed_closures, box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -80,7 +80,6 @@ struct Struct { c: usize } -#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. fn main() { let mut variable = 1; let constant = 2; @@ -95,9 +94,7 @@ fn main() { let owned: Box<_> = box 6; { - let mut first_closure = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - || { + let mut first_closure = || { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned; }; @@ -106,9 +103,7 @@ fn main() { } { - let mut second_closure = - #[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing captures. - || { + let mut second_closure = || { zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned; }; |
