Skip to content

Commit f06bab7

Browse files
committed
debuginfo: argument and upvar names for MIR.
1 parent 7fd2881 commit f06bab7

File tree

9 files changed

+176
-58
lines changed

9 files changed

+176
-58
lines changed

src/librustc/mir/repr.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ pub struct Mir<'tcx> {
5252
/// through the resulting reference.
5353
pub temp_decls: Vec<TempDecl<'tcx>>,
5454

55+
/// Names and capture modes of all the closure upvars, assuming
56+
/// the first argument is either the closure or a reference to it.
57+
pub upvar_decls: Vec<UpvarDecl>,
58+
5559
/// A span representing this MIR, for error reporting
5660
pub span: Span,
5761
}
@@ -197,7 +201,20 @@ pub struct ArgDecl<'tcx> {
197201

198202
/// If true, this argument is a tuple after monomorphization,
199203
/// and has to be collected from multiple actual arguments.
200-
pub spread: bool
204+
pub spread: bool,
205+
206+
/// Either special_idents::invalid or the name of a single-binding
207+
/// pattern associated with this argument. Useful for debuginfo.
208+
pub debug_name: Name
209+
}
210+
211+
/// A closure capture, with its name and mode.
212+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
213+
pub struct UpvarDecl {
214+
pub debug_name: Name,
215+
216+
/// If true, the capture is behind a reference.
217+
pub by_ref: bool
201218
}
202219

203220
///////////////////////////////////////////////////////////////////////////

src/librustc/mir/visit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ macro_rules! make_mir_visitor {
248248
ref $($mutability)* var_decls,
249249
ref $($mutability)* arg_decls,
250250
ref $($mutability)* temp_decls,
251+
upvar_decls: _,
251252
ref $($mutability)* span,
252253
} = *mir;
253254

@@ -599,7 +600,8 @@ macro_rules! make_mir_visitor {
599600
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
600601
let ArgDecl {
601602
ref $($mutability)* ty,
602-
spread: _
603+
spread: _,
604+
debug_name: _
603605
} = *arg_decl;
604606

605607
self.visit_ty(ty);

src/librustc_mir/build/mod.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010

1111
use hair::cx::Cx;
1212
use rustc::middle::region::{CodeExtent, CodeExtentData};
13-
use rustc::ty::{FnOutput, Ty};
13+
use rustc::ty::{self, FnOutput, Ty};
1414
use rustc::mir::repr::*;
1515
use rustc_data_structures::fnv::FnvHashMap;
1616
use rustc::hir;
17+
use rustc::hir::pat_util::pat_is_binding;
1718
use std::ops::{Index, IndexMut};
1819
use syntax::ast;
1920
use syntax::codemap::Span;
21+
use syntax::parse::token;
2022

2123
pub struct Builder<'a, 'tcx: 'a> {
2224
hir: Cx<'a, 'tcx>,
@@ -224,13 +226,37 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
224226
true
225227
}));
226228

229+
// Gather the upvars of a closure, if any.
230+
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
231+
freevars.iter().map(|fv| {
232+
let by_ref = tcx.upvar_capture(ty::UpvarId {
233+
var_id: fv.def.var_id(),
234+
closure_expr_id: fn_id
235+
}).map_or(false, |capture| match capture {
236+
ty::UpvarCapture::ByValue => false,
237+
ty::UpvarCapture::ByRef(..) => true
238+
});
239+
let mut decl = UpvarDecl {
240+
debug_name: token::special_idents::invalid.name,
241+
by_ref: by_ref
242+
};
243+
if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) {
244+
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
245+
decl.debug_name = ident.node.name;
246+
}
247+
}
248+
decl
249+
}).collect()
250+
});
251+
227252
(
228253
Mir {
229254
basic_blocks: builder.cfg.basic_blocks,
230255
scopes: builder.scope_datas,
231256
var_decls: builder.var_decls,
232257
arg_decls: arg_decls.take().expect("args never built?"),
233258
temp_decls: builder.temp_decls,
259+
upvar_decls: upvar_decls,
234260
return_ty: return_ty,
235261
span: span
236262
},
@@ -269,7 +295,20 @@ impl<'a,'tcx> Builder<'a,'tcx> {
269295
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
270296
argument_extent, &lvalue, ty);
271297

272-
ArgDecl { ty: ty, spread: false }
298+
let mut name = token::special_idents::invalid.name;
299+
if let Some(pat) = pattern {
300+
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
301+
if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
302+
name = ident.node.name;
303+
}
304+
}
305+
}
306+
307+
ArgDecl {
308+
ty: ty,
309+
spread: false,
310+
debug_name: name
311+
}
273312
})
274313
.collect();
275314

src/librustc_trans/debuginfo/create_scope_map.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,28 @@ fn make_mir_scope(ccx: &CrateContext,
120120
return;
121121
};
122122

123-
scopes[idx] = if !has_variables.contains(idx) {
123+
if !has_variables.contains(idx) {
124124
// Do not create a DIScope if there are no variables
125125
// defined in this MIR Scope, to avoid debuginfo bloat.
126-
parent_scope
127-
} else {
128-
let loc = span_start(ccx, scope_data.span);
129-
let file_metadata = file_metadata(ccx, &loc.file.name);
130-
unsafe {
131-
llvm::LLVMDIBuilderCreateLexicalBlock(
132-
DIB(ccx),
133-
parent_scope,
134-
file_metadata,
135-
loc.line as c_uint,
136-
loc.col.to_usize() as c_uint)
126+
127+
// However, we don't skip creating a nested scope if
128+
// our parent is the root, because we might want to
129+
// put arguments in the root and not have shadowing.
130+
if parent_scope != fn_metadata {
131+
scopes[idx] = parent_scope;
132+
return;
137133
}
134+
}
135+
136+
let loc = span_start(ccx, scope_data.span);
137+
let file_metadata = file_metadata(ccx, &loc.file.name);
138+
scopes[idx] = unsafe {
139+
llvm::LLVMDIBuilderCreateLexicalBlock(
140+
DIB(ccx),
141+
parent_scope,
142+
file_metadata,
143+
loc.line as c_uint,
144+
loc.col.to_usize() as c_uint)
138145
};
139146
}
140147

src/librustc_trans/mir/mod.rs

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
126126
let scopes = debuginfo::create_mir_scopes(fcx);
127127

128128
// Allocate variable and temp allocas
129+
let args = arg_value_refs(&bcx, &mir, &scopes);
129130
let vars = mir.var_decls.iter()
130131
.map(|decl| (bcx.monomorphize(&decl.ty), decl))
131132
.map(|(mty, decl)| {
@@ -156,7 +157,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
156157
TempRef::Operand(None)
157158
})
158159
.collect();
159-
let args = arg_value_refs(&bcx, &mir, &scopes);
160160

161161
// Allocate a `Block` for every basic block
162162
let block_bcxs: Vec<Block<'blk,'tcx>> =
@@ -278,15 +278,15 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
278278
let byte_offset_of_var_in_tuple =
279279
machine::llelement_offset(bcx.ccx(), lltuplety, i);
280280

281-
let address_operations = unsafe {
281+
let ops = unsafe {
282282
[llvm::LLVMDIBuilderCreateOpDeref(),
283283
llvm::LLVMDIBuilderCreateOpPlus(),
284284
byte_offset_of_var_in_tuple as i64]
285285
};
286286

287287
let variable_access = VariableAccess::IndirectVariable {
288288
alloca: lltemp,
289-
address_operations: &address_operations
289+
address_operations: &ops
290290
};
291291
declare_local(bcx, token::special_idents::invalid.name,
292292
tupled_arg_ty, scope, variable_access,
@@ -327,10 +327,78 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
327327
lltemp
328328
};
329329
bcx.with_block(|bcx| arg_scope.map(|scope| {
330-
declare_local(bcx, token::special_idents::invalid.name, arg_ty, scope,
331-
VariableAccess::DirectVariable { alloca: llval },
332-
VariableKind::ArgumentVariable(arg_index + 1),
333-
bcx.fcx().span.unwrap_or(DUMMY_SP));
330+
// Is this a regular argument?
331+
if arg_index > 0 || mir.upvar_decls.is_empty() {
332+
declare_local(bcx, arg_decl.debug_name, arg_ty, scope,
333+
VariableAccess::DirectVariable { alloca: llval },
334+
VariableKind::ArgumentVariable(arg_index + 1),
335+
bcx.fcx().span.unwrap_or(DUMMY_SP));
336+
return;
337+
}
338+
339+
// Or is it the closure environment?
340+
let (closure_ty, env_ref) = if let ty::TyRef(_, mt) = arg_ty.sty {
341+
(mt.ty, true)
342+
} else {
343+
(arg_ty, false)
344+
};
345+
let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty {
346+
&substs.upvar_tys[..]
347+
} else {
348+
bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty);
349+
};
350+
351+
// Store the pointer to closure data in an alloca for debuginfo
352+
// because that's what the llvm.dbg.declare intrinsic expects.
353+
354+
// FIXME(eddyb) this shouldn't be necessary but SROA seems to
355+
// mishandle DW_OP_plus not preceded by DW_OP_deref, i.e. it
356+
// doesn't actually strip the offset when splitting the closure
357+
// environment into its components so it ends up out of bounds.
358+
let env_ptr = if !env_ref {
359+
use base::*;
360+
use build::*;
361+
use common::*;
362+
let alloc = alloca(bcx, val_ty(llval), "__debuginfo_env_ptr");
363+
Store(bcx, llval, alloc);
364+
alloc
365+
} else {
366+
llval
367+
};
368+
369+
let llclosurety = type_of::type_of(bcx.ccx(), closure_ty);
370+
for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
371+
let byte_offset_of_var_in_env =
372+
machine::llelement_offset(bcx.ccx(), llclosurety, i);
373+
374+
let ops = unsafe {
375+
[llvm::LLVMDIBuilderCreateOpDeref(),
376+
llvm::LLVMDIBuilderCreateOpPlus(),
377+
byte_offset_of_var_in_env as i64,
378+
llvm::LLVMDIBuilderCreateOpDeref()]
379+
};
380+
381+
// The environment and the capture can each be indirect.
382+
383+
// FIXME(eddyb) see above why we have to keep
384+
// a pointer in an alloca for debuginfo atm.
385+
let mut ops = if env_ref || true { &ops[..] } else { &ops[1..] };
386+
387+
let ty = if let (true, &ty::TyRef(_, mt)) = (decl.by_ref, &ty.sty) {
388+
mt.ty
389+
} else {
390+
ops = &ops[..ops.len() - 1];
391+
ty
392+
};
393+
394+
let variable_access = VariableAccess::IndirectVariable {
395+
alloca: env_ptr,
396+
address_operations: &ops
397+
};
398+
declare_local(bcx, decl.debug_name, ty, scope, variable_access,
399+
VariableKind::CapturedVariable,
400+
bcx.fcx().span.unwrap_or(DUMMY_SP));
401+
}
334402
}));
335403
LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty))
336404
}).collect()

src/test/debuginfo/function-prologue-stepping-no-stack-check.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@
251251
#![omit_gdb_pretty_printer_section]
252252

253253
#[no_stack_check]
254-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
254+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
255255
fn immediate_args(a: isize, b: bool, c: f64) {
256256
println!("");
257257
}
@@ -268,51 +268,51 @@ struct BigStruct {
268268
}
269269

270270
#[no_stack_check]
271-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
271+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
272272
fn non_immediate_args(a: BigStruct, b: BigStruct) {
273273
println!("");
274274
}
275275

276276
#[no_stack_check]
277-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
277+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
278278
fn binding(a: i64, b: u64, c: f64) {
279279
let x = 0;
280280
println!("");
281281
}
282282

283283
#[no_stack_check]
284-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
284+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
285285
fn assignment(mut a: u64, b: u64, c: f64) {
286286
a = b;
287287
println!("");
288288
}
289289

290290
#[no_stack_check]
291-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
291+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
292292
fn function_call(x: u64, y: u64, z: f64) {
293293
println!("Hi!")
294294
}
295295

296296
#[no_stack_check]
297-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
297+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
298298
fn identifier(x: u64, y: u64, z: f64) -> u64 {
299299
x
300300
}
301301

302302
#[no_stack_check]
303-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
303+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
304304
fn return_expr(x: u64, y: u64, z: f64) -> u64 {
305305
return x;
306306
}
307307

308308
#[no_stack_check]
309-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
309+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
310310
fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
311311
x + y
312312
}
313313

314314
#[no_stack_check]
315-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
315+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
316316
fn if_expr(x: u64, y: u64, z: f64) -> u64 {
317317
if x + y < 1000 {
318318
x
@@ -322,7 +322,7 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
322322
}
323323

324324
#[no_stack_check]
325-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
325+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
326326
fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
327327
while x + y < 1000 {
328328
x += z
@@ -331,7 +331,7 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
331331
}
332332

333333
#[no_stack_check]
334-
#[rustc_no_mir] // FIXME(#31005) MIR debuginfo is missing argument names.
334+
#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
335335
fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
336336
loop {
337337
x += z;

0 commit comments

Comments
 (0)