Skip to content

Commit e721194

Browse files
committed
auto merge of #8045 : michaelwoerister/rust/destructuring, r=jdm
As the title says, valid debug info is now generated for any kind of pattern-based bindings like an example from the automated tests: ```rust let ((u, v), ((w, (x, Struct { a: y, b: z})), Struct { a: ae, b: oe }), ue) = ((25, 26), ((27, (28, Struct { a: 29, b: 30})), Struct { a: 31, b: 32 }), 33); ``` (Not that you would necessarily want to do a thing like that :P ) Fixes #2533
2 parents 15310ba + d546155 commit e721194

File tree

7 files changed

+758
-125
lines changed

7 files changed

+758
-125
lines changed

src/librustc/middle/trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
17911791
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
17921792

17931793
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
1794-
debuginfo::create_argument_metadata(bcx, &args[arg_n], args[arg_n].ty.span);
1794+
debuginfo::create_argument_metadata(bcx, &args[arg_n]);
17951795
}
17961796
}
17971797

src/librustc/middle/trans/debuginfo.rs

+146-118
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use middle::trans::type_::Type;
6060
use middle::trans::adt;
6161
use middle::trans;
6262
use middle::ty;
63+
use middle::pat_util;
6364
use util::ppaux::ty_to_str;
6465

6566
use std::hashmap::HashMap;
@@ -71,15 +72,15 @@ use syntax::{ast, codemap, ast_util, ast_map};
7172

7273
static DW_LANG_RUST: int = 0x9000;
7374

74-
static DW_TAG_auto_variable: int = 0x100;
75-
static DW_TAG_arg_variable: int = 0x101;
75+
static DW_TAG_auto_variable: c_uint = 0x100;
76+
static DW_TAG_arg_variable: c_uint = 0x101;
7677

77-
static DW_ATE_boolean: int = 0x02;
78-
static DW_ATE_float: int = 0x04;
79-
static DW_ATE_signed: int = 0x05;
80-
static DW_ATE_signed_char: int = 0x06;
81-
static DW_ATE_unsigned: int = 0x07;
82-
static DW_ATE_unsigned_char: int = 0x08;
78+
static DW_ATE_boolean: c_uint = 0x02;
79+
static DW_ATE_float: c_uint = 0x04;
80+
static DW_ATE_signed: c_uint = 0x05;
81+
static DW_ATE_signed_char: c_uint = 0x06;
82+
static DW_ATE_unsigned: c_uint = 0x07;
83+
static DW_ATE_unsigned_char: c_uint = 0x08;
8384

8485

8586

@@ -90,14 +91,16 @@ static DW_ATE_unsigned_char: int = 0x08;
9091

9192
/// A context object for maintaining all state needed by the debuginfo module.
9293
pub struct DebugContext {
93-
crate_file: ~str,
94-
llcontext: ContextRef,
95-
builder: DIBuilderRef,
96-
curr_loc: (uint, uint),
97-
created_files: HashMap<~str, DIFile>,
98-
created_functions: HashMap<ast::node_id, DISubprogram>,
99-
created_blocks: HashMap<ast::node_id, DILexicalBlock>,
100-
created_types: HashMap<uint, DIType>
94+
priv crate_file: ~str,
95+
priv llcontext: ContextRef,
96+
priv builder: DIBuilderRef,
97+
priv curr_loc: (uint, uint),
98+
priv created_files: HashMap<~str, DIFile>,
99+
priv created_functions: HashMap<ast::node_id, DISubprogram>,
100+
priv created_blocks: HashMap<ast::node_id, DILexicalBlock>,
101+
priv created_types: HashMap<uint, DIType>,
102+
priv last_function_context_id: ast::node_id,
103+
priv argument_counter: uint,
101104
}
102105

103106
impl DebugContext {
@@ -115,6 +118,8 @@ impl DebugContext {
115118
created_functions: HashMap::new(),
116119
created_blocks: HashMap::new(),
117120
created_types: HashMap::new(),
121+
last_function_context_id: -1, // magic value :(
122+
argument_counter: 1,
118123
};
119124
}
120125
}
@@ -132,126 +137,147 @@ pub fn finalize(cx: @mut CrateContext) {
132137
/// Creates debug information for the given local variable.
133138
///
134139
/// Adds the created metadata nodes directly to the crate's IR.
135-
/// The return value should be ignored if called from outside of the debuginfo module.
136-
pub fn create_local_var_metadata(bcx: @mut Block, local: @ast::Local) -> DIVariable {
140+
pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) {
137141
let cx = bcx.ccx();
142+
let def_map = cx.tcx.def_map;
143+
let pattern = local.pat;
138144

139-
let ident = match local.pat.node {
140-
ast::pat_ident(_, ref pth, _) => ast_util::path_to_ident(pth),
141-
// FIXME this should be handled (#2533)
142-
_ => {
143-
bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI");
144-
return ptr::null();
145-
}
145+
let scope = match bcx.parent {
146+
None => create_function_metadata(bcx.fcx),
147+
Some(_) => lexical_block_metadata(bcx)
146148
};
147149

148-
let name: &str = cx.sess.str_of(ident);
149-
debug!("create_local_var_metadata: %s", name);
150+
let filename = span_start(cx, local.span).file.name;
151+
let file_metadata = file_metadata(cx, filename);
150152

151-
let loc = span_start(cx, local.span);
152-
let ty = node_id_type(bcx, local.id);
153-
let type_metadata = type_metadata(cx, ty, local.ty.span);
154-
let file_metadata = file_metadata(cx, loc.file.name);
153+
do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| {
155154

156-
let context = match bcx.parent {
157-
None => create_function_metadata(bcx.fcx),
158-
Some(_) => lexical_block_metadata(bcx)
159-
};
155+
let ident = ast_util::path_to_ident(path_ref);
156+
let name: &str = cx.sess.str_of(ident);
157+
debug!("create_local_var_metadata: %s", name);
158+
let loc = span_start(cx, span);
159+
let ty = node_id_type(bcx, node_id);
160+
let type_metadata = type_metadata(cx, ty, span);
161+
162+
let var_metadata = do name.as_c_str |name| {
163+
unsafe {
164+
llvm::LLVMDIBuilderCreateLocalVariable(
165+
DIB(cx),
166+
DW_TAG_auto_variable,
167+
scope,
168+
name,
169+
file_metadata,
170+
loc.line as c_uint,
171+
type_metadata,
172+
false,
173+
0,
174+
0)
175+
}
176+
};
177+
178+
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
179+
Some(v) => v,
180+
None => {
181+
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
182+
}
183+
};
160184

161-
let var_metadata = do name.as_c_str |name| {
185+
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
162186
unsafe {
163-
llvm::LLVMDIBuilderCreateLocalVariable(
187+
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
164188
DIB(cx),
165-
DW_TAG_auto_variable as u32,
166-
context,
167-
name,
168-
file_metadata,
169-
loc.line as c_uint,
170-
type_metadata,
171-
false,
172-
0,
173-
0)
174-
}
175-
};
189+
llptr,
190+
var_metadata,
191+
bcx.llbb);
176192

177-
// FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc
178-
let llptr = match bcx.fcx.lllocals.find_copy(&local.pat.id) {
179-
Some(v) => v,
180-
None => {
181-
bcx.tcx().sess.span_bug(
182-
local.span,
183-
fmt!("No entry in lllocals table for %?", local.id));
193+
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
184194
}
185-
};
186-
187-
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
188-
unsafe {
189-
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb);
190-
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
191195
}
192-
193-
return var_metadata;
194196
}
195197

196198
/// Creates debug information for the given function argument.
197199
///
198200
/// Adds the created metadata nodes directly to the crate's IR.
199-
/// The return value should be ignored if called from outside of the debuginfo module.
200-
pub fn create_argument_metadata(bcx: @mut Block, arg: &ast::arg, span: span) -> Option<DIVariable> {
201-
debug!("create_argument_metadata");
202-
if true {
203-
// XXX create_argument_metadata disabled for now because "node_id_type(bcx, arg.id)" below
204-
// blows up:
205-
// "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`"
206-
return None;
207-
}
208-
201+
pub fn create_argument_metadata(bcx: @mut Block,
202+
arg: &ast::arg) {
209203
let fcx = bcx.fcx;
210204
let cx = fcx.ccx;
211205

212-
let loc = span_start(cx, span);
213-
if "<intrinsic>" == loc.file.name {
214-
return None;
206+
let pattern = arg.pat;
207+
let filename = span_start(cx, pattern.span).file.name;
208+
209+
if fcx.id == -1 ||
210+
fcx.span.is_none() ||
211+
"<intrinsic>" == filename {
212+
return;
215213
}
216214

217-
let ty = node_id_type(bcx, arg.id);
218-
let type_metadata = type_metadata(cx, ty, arg.ty.span);
219-
let file_metadata = file_metadata(cx, loc.file.name);
220-
let context = create_function_metadata(fcx);
221-
222-
match arg.pat.node {
223-
ast::pat_ident(_, ref path, _) => {
224-
// XXX: This is wrong; it should work for multiple bindings.
225-
let ident = path.idents.last();
226-
let name: &str = cx.sess.str_of(*ident);
227-
let var_metadata = do name.as_c_str |name| {
228-
unsafe {
229-
llvm::LLVMDIBuilderCreateLocalVariable(
230-
DIB(cx),
231-
DW_TAG_arg_variable as u32,
232-
context,
233-
name,
234-
file_metadata,
235-
loc.line as c_uint,
236-
type_metadata,
237-
false,
238-
0,
239-
0)
240-
// XXX need to pass in a real argument number
241-
}
242-
};
215+
// Limited the scope within which `debug_context` is live,
216+
// otherwise => borrowing errors
217+
{
218+
let debug_context = dbg_cx(cx);
219+
220+
// If this is a new function, reset the counter. llvm::DIBuilder
221+
// wants arguments to be indexed starting from 1.
222+
if fcx.id != debug_context.last_function_context_id {
223+
debug_context.argument_counter = 1;
224+
}
225+
// Keep track of the function we are in
226+
debug_context.last_function_context_id = fcx.id;
227+
}
228+
229+
let def_map = cx.tcx.def_map;
230+
let file_metadata = file_metadata(cx, filename);
231+
let scope = create_function_metadata(fcx);
232+
233+
do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| {
234+
235+
let ty = node_id_type(bcx, node_id);
236+
let type_metadata = type_metadata(cx, ty, codemap::dummy_sp());
237+
let loc = span_start(cx, span);
238+
let ident = ast_util::path_to_ident(path_ref);
239+
let name: &str = cx.sess.str_of(ident);
240+
debug!("create_argument_metadata: %s", name);
241+
242+
let argument_index = {
243+
let debug_context = dbg_cx(cx);
244+
let argument_index = debug_context.argument_counter;
245+
debug_context.argument_counter += 1;
246+
argument_index as c_uint
247+
};
243248

244-
let llptr = fcx.llargs.get_copy(&arg.id);
245-
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
249+
let arg_metadata = do name.as_c_str |name| {
246250
unsafe {
247-
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
248-
DIB(cx), llptr, var_metadata, bcx.llbb);
249-
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
251+
llvm::LLVMDIBuilderCreateLocalVariable(
252+
DIB(cx),
253+
DW_TAG_arg_variable,
254+
scope,
255+
name,
256+
file_metadata,
257+
loc.line as c_uint,
258+
type_metadata,
259+
false,
260+
0,
261+
argument_index)
250262
}
251-
return Some(var_metadata);
252-
}
253-
_ => {
254-
return None;
263+
};
264+
265+
let llptr = match bcx.fcx.llargs.find_copy(&node_id) {
266+
Some(v) => v,
267+
None => {
268+
bcx.tcx().sess.span_bug(span, fmt!("No entry in llargs table for %?", node_id));
269+
}
270+
};
271+
272+
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
273+
unsafe {
274+
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
275+
DIB(cx),
276+
llptr,
277+
arg_metadata,
278+
bcx.llbb);
279+
280+
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
255281
}
256282
}
257283
}
@@ -274,7 +300,6 @@ pub fn update_source_pos(bcx: @mut Block, span: span) {
274300
/// The return value should be ignored if called from outside of the debuginfo module.
275301
pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
276302
let cx = fcx.ccx;
277-
let span = fcx.span.get();
278303

279304
let fnitem = cx.tcx.items.get_copy(&fcx.id);
280305
let (ident, ret_ty, id) = match fnitem {
@@ -320,14 +345,19 @@ pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
320345
_) => {
321346
(ident, ty, id)
322347
}
323-
_ => fcx.ccx.sess.bug("create_function_metadata: unexpected sort of node")
348+
_ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
324349
};
325350

326351
match dbg_cx(cx).created_functions.find(&id) {
327352
Some(fn_metadata) => return *fn_metadata,
328353
None => ()
329354
}
330355

356+
let span = match fcx.span {
357+
Some(value) => value,
358+
None => codemap::dummy_sp()
359+
};
360+
331361
debug!("create_function_metadata: %s, %s",
332362
cx.sess.str_of(ident),
333363
cx.sess.codemap.span_to_str(span));
@@ -527,7 +557,7 @@ fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
527557
name,
528558
bytes_to_bits(size),
529559
bytes_to_bits(align),
530-
encoding as c_uint)
560+
encoding)
531561
}
532562
};
533563

@@ -608,8 +638,6 @@ fn tuple_metadata(cx: &mut CrateContext,
608638
fn enum_metadata(cx: &mut CrateContext,
609639
enum_type: ty::t,
610640
enum_def_id: ast::def_id,
611-
// _substs is only needed in the other version. Will go away with new snapshot.
612-
_substs: &ty::substs,
613641
span: span)
614642
-> DIType {
615643

@@ -1113,8 +1141,8 @@ fn type_metadata(cx: &mut CrateContext,
11131141
}
11141142
}
11151143
},
1116-
ty::ty_enum(def_id, ref substs) => {
1117-
enum_metadata(cx, t, def_id, substs, span)
1144+
ty::ty_enum(def_id, _) => {
1145+
enum_metadata(cx, t, def_id, span)
11181146
},
11191147
ty::ty_box(ref mt) => {
11201148
create_pointer_to_box_metadata(cx, t, mt.ty)

0 commit comments

Comments
 (0)