Skip to content

Commit

Permalink
debuginfo: Make variables captured in unboxed closures available in d…
Browse files Browse the repository at this point in the history
…ebuginfo.
  • Loading branch information
michaelwoerister committed Nov 27, 2014
1 parent 82fc1aa commit 251386c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
46 changes: 37 additions & 9 deletions src/librustc_trans/trans/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,21 +272,24 @@ fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let mut i = 0u;
for freevar in freevars.iter() {
let mut upvarptr = GEPi(bcx, llcdata, &[0u, i]);
match store {
ty::RegionTraitStore(..) => { upvarptr = Load(bcx, upvarptr); }
ty::UniqTraitStore => {}
}
let captured_by_ref = match store {
ty::RegionTraitStore(..) => {
upvarptr = Load(bcx, upvarptr);
true
}
ty::UniqTraitStore => false
};
let def_id = freevar.def.def_id();

bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
for &env_pointer_alloca in env_pointer_alloca.iter() {
if let Some(env_pointer_alloca) = env_pointer_alloca {
debuginfo::create_captured_var_metadata(
bcx,
def_id.node,
cdata_ty,
env_pointer_alloca,
i,
store,
captured_by_ref,
freevar.span);
}

Expand Down Expand Up @@ -320,11 +323,25 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
bcx.fcx.llenv.unwrap()
};

// 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 bcx.sess().opts.debuginfo == FullDebugInfo {
let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), self_type), "__debuginfo_env_ptr");
Store(bcx, llenv, alloc);
Some(alloc)
} else {
None
};

for (i, freevar) in freevars.iter().enumerate() {
let mut upvar_ptr = GEPi(bcx, llenv, &[0, i]);
if freevar_mode == ast::CaptureByRef {
upvar_ptr = Load(bcx, upvar_ptr);
}
let captured_by_ref = match freevar_mode {
ast::CaptureByRef => {
upvar_ptr = Load(bcx, upvar_ptr);
true
}
ast::CaptureByValue => false
};
let def_id = freevar.def.def_id();
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);

Expand All @@ -333,6 +350,17 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
upvar_ptr,
node_id_type(bcx, def_id.node))
}

if let Some(env_pointer_alloca) = env_pointer_alloca {
debuginfo::create_captured_var_metadata(
bcx,
def_id.node,
self_type,
env_pointer_alloca,
i,
captured_by_ref,
freevar.span);
}
}

bcx
Expand Down
13 changes: 5 additions & 8 deletions src/librustc_trans/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
env_data_type: Ty<'tcx>,
env_pointer: ValueRef,
env_index: uint,
closure_store: ty::TraitStore,
captured_by_ref: bool,
span: Span) {
if fn_should_be_ignored(bcx.fcx) {
return;
Expand Down Expand Up @@ -940,13 +940,10 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llvm::LLVMDIBuilderCreateOpDeref(Type::i64(cx).to_ref())]
};

let address_op_count = match closure_store {
ty::RegionTraitStore(..) => {
address_operations.len()
}
ty::UniqTraitStore => {
address_operations.len() - 1
}
let address_op_count = if captured_by_ref {
address_operations.len()
} else {
address_operations.len() - 1
};

let variable_access = IndirectVariable {
Expand Down
19 changes: 18 additions & 1 deletion src/test/debuginfo/var-captured-in-sendable-closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
// gdb-check:$2 = {a = -2, b = 3.5, c = 4}
// gdb-command:print *owned
// gdb-check:$3 = 5
// gdb-command:continue

// gdb-command:print constant2
// gdb-check:$4 = 6
// gdb-command:continue

// === LLDB TESTS ==================================================================================

Expand All @@ -37,6 +41,7 @@
// lldb-check:[...]$2 = 5

#![allow(unused_variables)]
#![feature(unboxed_closures)]

struct Struct {
a: int,
Expand All @@ -55,12 +60,24 @@ fn main() {

let owned = box 5;

let closure: proc() = proc() {
let closure = move |:| {
zzz(); // #break
do_something(&constant, &a_struct.a, &*owned);
};

closure();

let constant2 = 6u;

// 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 = move |:| {
zzz(); // #break
return constant2;
};

immedate_env();
}

fn do_something(_: &int, _:&int, _:&int) {
Expand Down

0 comments on commit 251386c

Please sign in to comment.