Skip to content

Commit 45c3ca7

Browse files
committed
auto merge of #8855 : michaelwoerister/rust/captured_vars, r=jdm
This pull request includes * support for variables captured in closures*, * a fix for issue #8512: arguments of non-immediate type (structs, tuples, etc) passed by value can now be accessed correctly in GDB. (I managed to fix this by using `llvm::DIBuilder::createComplexVariable()`. ~~However, I am not sure if this relies on unstable implementation details of LLVM's debug info handling. I'll try to clarify this on the LLVM mailing list~~). * simplification of the `debuginfo` module's public interface: the caller of functions like `create_local_var_metadata()` doesn't have to know and catch all cases when it mustn't call the function, * a cleanup refactoring with unified handling for locals, [self] arguments, captured variables, and match bindings, * and proper span information for self arguments. \* However, see comment at https://github.com/michaelwoerister/rust/blob/1d916ace136a27e354d73d65f488603c65f65bd2/src/test/debug-info/var-captured-in-nested-closure.rs#L62 . This is the same problem as with the fix for issue #8512 above: We are probably using `llvm.dbg.declare` in an unsupported way that works today but might not work after the next LLVM update. Cheers, Michael Fixes #8512 Fixes #1341
2 parents d1f9055 + 5b94ae9 commit 45c3ca7

17 files changed

+896
-232
lines changed

src/librustc/lib/llvm.rs

+25
Original file line numberDiff line numberDiff line change
@@ -2084,6 +2084,31 @@ pub mod llvm {
20842084
ColumnNo: c_uint)
20852085
-> ValueRef;
20862086

2087+
#[fast_ffi]
2088+
pub fn LLVMDIBuilderCreateOpDeref(IntType: TypeRef) -> ValueRef;
2089+
2090+
#[fast_ffi]
2091+
pub fn LLVMDIBuilderCreateOpPlus(IntType: TypeRef) -> ValueRef;
2092+
2093+
#[fast_ffi]
2094+
pub fn LLVMDIBuilderCreateComplexVariable(Builder: DIBuilderRef,
2095+
Tag: c_uint,
2096+
Scope: ValueRef,
2097+
Name: *c_char,
2098+
File: ValueRef,
2099+
LineNo: c_uint,
2100+
Ty: ValueRef,
2101+
AddrOps: *ValueRef,
2102+
AddrOpsCount: c_uint,
2103+
ArgNo: c_uint)
2104+
-> ValueRef;
2105+
2106+
#[fast_ffi]
2107+
pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
2108+
2109+
#[fast_ffi]
2110+
pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef;
2111+
20872112
pub fn LLVMInitializeX86TargetInfo();
20882113
pub fn LLVMInitializeX86Target();
20892114
pub fn LLVMInitializeX86TargetMC();

src/librustc/middle/moves.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ use syntax::visit;
143143
use syntax::visit::Visitor;
144144
use syntax::codemap::Span;
145145

146-
#[deriving(Encodable, Decodable)]
146+
#[deriving(Eq, Encodable, Decodable)]
147147
pub enum CaptureMode {
148148
CapCopy, // Copy the value into the closure.
149149
CapMove, // Move the value into the closure.

src/librustc/middle/trans/_match.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -2000,19 +2000,20 @@ pub fn store_arg(mut bcx: @mut Block,
20002000
let arg_ty = node_id_type(bcx, pat.id);
20012001
add_clean(bcx, llval, arg_ty);
20022002

2003-
match simple_identifier(pat) {
2004-
Some(_) => {
2005-
// Optimized path for `x: T` case. This just adopts
2006-
// `llval` wholesale as the pointer for `x`, avoiding the
2007-
// general logic which may copy out of `llval`.
2008-
bcx.fcx.llargs.insert(pat.id, llval);
2009-
}
2010-
2011-
None => {
2012-
// General path. Copy out the values that are used in the
2013-
// pattern.
2014-
bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument);
2015-
}
2003+
// Debug information (the llvm.dbg.declare intrinsic to be precise) always expects to get an
2004+
// alloca, which only is the case on the general path, so lets disable the optimized path when
2005+
// debug info is enabled.
2006+
let fast_path = !bcx.ccx().sess.opts.extra_debuginfo && simple_identifier(pat).is_some();
2007+
2008+
if fast_path {
2009+
// Optimized path for `x: T` case. This just adopts
2010+
// `llval` wholesale as the pointer for `x`, avoiding the
2011+
// general logic which may copy out of `llval`.
2012+
bcx.fcx.llargs.insert(pat.id, llval);
2013+
} else {
2014+
// General path. Copy out the values that are used in the
2015+
// pattern.
2016+
bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument);
20162017
}
20172018

20182019
return bcx;

src/librustc/middle/trans/base.rs

+4-24
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,6 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
131131
_InsnCtxt { _x: () }
132132
}
133133

134-
fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
135-
match fcx.span {
136-
None => false,
137-
Some(span) => *span.lo != 0 || *span.hi != 0
138-
}
139-
}
140-
141-
fn span_is_empty(opt_span: &Option<Span>) -> bool {
142-
match *opt_span {
143-
None => true,
144-
Some(span) => *span.lo == 0 && *span.hi == 0
145-
}
146-
}
147-
148134
struct StatRecorder<'self> {
149135
ccx: @mut CrateContext,
150136
name: &'self str,
@@ -1132,8 +1118,7 @@ pub fn trans_stmt(cx: @mut Block, s: &ast::Stmt) -> @mut Block {
11321118
match d.node {
11331119
ast::DeclLocal(ref local) => {
11341120
bcx = init_local(bcx, *local);
1135-
if cx.sess().opts.extra_debuginfo
1136-
&& fcx_has_nonzero_span(bcx.fcx) {
1121+
if cx.sess().opts.extra_debuginfo {
11371122
debuginfo::create_local_var_metadata(bcx, *local);
11381123
}
11391124
}
@@ -1633,12 +1618,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16331618
}
16341619
};
16351620
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
1636-
1637-
let debug_context = if id != -1 && ccx.sess.opts.debuginfo && !span_is_empty(&sp) {
1638-
Some(debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl))
1639-
} else {
1640-
None
1641-
};
1621+
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
16421622

16431623
let fcx = @mut FunctionContext {
16441624
llfn: llfndecl,
@@ -1784,7 +1764,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
17841764
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
17851765
add_clean(bcx, self_val, slf.t);
17861766

1787-
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
1767+
if fcx.ccx.sess.opts.extra_debuginfo {
17881768
debuginfo::create_self_argument_metadata(bcx, slf.t, self_val);
17891769
}
17901770
}
@@ -1811,7 +1791,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
18111791
};
18121792
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
18131793

1814-
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
1794+
if fcx.ccx.sess.opts.extra_debuginfo {
18151795
debuginfo::create_argument_metadata(bcx, &args[arg_n]);
18161796
}
18171797
}

src/librustc/middle/trans/closure.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use middle::trans::base::*;
1717
use middle::trans::build::*;
1818
use middle::trans::common::*;
1919
use middle::trans::datum::{Datum, INIT};
20+
use middle::trans::debuginfo;
2021
use middle::trans::expr;
2122
use middle::trans::glue;
2223
use middle::trans::type_of::*;
@@ -307,7 +308,17 @@ pub fn load_environment(fcx: @mut FunctionContext,
307308
// Load a pointer to the closure data, skipping over the box header:
308309
let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv);
309310

310-
// Populate the upvars from the environment.
311+
// Store the pointer to closure data in an alloca for debug info because that's what the
312+
// llvm.dbg.declare intrinsic expects
313+
let env_pointer_alloca = if fcx.ccx.sess.opts.extra_debuginfo {
314+
let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), cdata_ty), "__debuginfo_env_ptr");
315+
Store(bcx, llcdata, alloc);
316+
Some(alloc)
317+
} else {
318+
None
319+
};
320+
321+
// Populate the upvars from the environment
311322
let mut i = 0u;
312323
for cap_var in cap_vars.iter() {
313324
let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
@@ -317,6 +328,18 @@ pub fn load_environment(fcx: @mut FunctionContext,
317328
}
318329
let def_id = ast_util::def_id_of_def(cap_var.def);
319330
fcx.llupvars.insert(def_id.node, upvarptr);
331+
332+
for &env_pointer_alloca in env_pointer_alloca.iter() {
333+
debuginfo::create_captured_var_metadata(
334+
bcx,
335+
def_id.node,
336+
cdata_ty,
337+
env_pointer_alloca,
338+
i,
339+
sigil,
340+
cap_var.span);
341+
}
342+
320343
i += 1u;
321344
}
322345
}

src/librustc/middle/trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ pub struct FunctionContext {
228228
ccx: @mut CrateContext,
229229

230230
// Used and maintained by the debuginfo module.
231-
debug_context: Option<~debuginfo::FunctionDebugContext>
231+
debug_context: debuginfo::FunctionDebugContext,
232232
}
233233

234234
impl FunctionContext {

src/librustc/middle/trans/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub struct CrateContext {
111111
// decl_gc_metadata knows whether to link to the module metadata, which
112112
// is not emitted by LLVM's GC pass when no functions use GC.
113113
uses_gc: bool,
114-
dbg_cx: Option<debuginfo::DebugContext>,
114+
dbg_cx: Option<debuginfo::CrateDebugContext>,
115115
do_not_commit_warning_issued: bool
116116
}
117117

@@ -161,7 +161,7 @@ impl CrateContext {
161161

162162
let crate_map = decl_crate_map(sess, link_meta, llmod);
163163
let dbg_cx = if sess.opts.debuginfo {
164-
Some(debuginfo::DebugContext::new(llmod, name.to_owned()))
164+
Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
165165
} else {
166166
None
167167
};

0 commit comments

Comments
 (0)