mirror of
https://github.com/rust-lang/rust
synced 2024-10-14 12:33:57 +00:00
debuginfo: argument and upvar names for MIR.
This commit is contained in:
parent
7fd2881ed4
commit
f06bab7758
|
@ -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
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -248,6 +248,7 @@ fn super_mir(&mut self,
|
|||
ref $($mutability)* var_decls,
|
||||
ref $($mutability)* arg_decls,
|
||||
ref $($mutability)* temp_decls,
|
||||
upvar_decls: _,
|
||||
ref $($mutability)* span,
|
||||
} = *mir;
|
||||
|
||||
|
@ -599,7 +600,8 @@ fn super_arg_decl(&mut self,
|
|||
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
|
||||
let ArgDecl {
|
||||
ref $($mutability)* ty,
|
||||
spread: _
|
||||
spread: _,
|
||||
debug_name: _
|
||||
} = *arg_decl;
|
||||
|
||||
self.visit_ty(ty);
|
||||
|
|
|
@ -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 @@ fn args_and_body(&mut self,
|
|||
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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue