]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/debuginfo/create_scope_map.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_trans / debuginfo / create_scope_map.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use super::FunctionDebugContext;
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
14
15 use llvm;
16 use llvm::debuginfo::{DIScope, DISubprogram};
17 use common::{CrateContext, FunctionContext};
18 use rustc::hir::pat_util;
19 use rustc::mir::repr::{Mir, VisibilityScope};
20 use rustc::util::nodemap::NodeMap;
21
22 use libc::c_uint;
23 use std::ptr;
24
25 use syntax_pos::{Span, Pos};
26 use syntax::{ast, codemap};
27
28 use rustc_data_structures::bitvec::BitVector;
29 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
30 use rustc::hir::{self, PatKind};
31
32 // This procedure builds the *scope map* for a given function, which maps any
33 // given ast::NodeId in the function's AST to the correct DIScope metadata instance.
34 //
35 // This builder procedure walks the AST in execution order and keeps track of
36 // what belongs to which scope, creating DIScope DIEs along the way, and
37 // introducing *artificial* lexical scope descriptors where necessary. These
38 // artificial scopes allow GDB to correctly handle name shadowing.
39 pub fn create_scope_map(cx: &CrateContext,
40 args: &[hir::Arg],
41 fn_entry_block: &hir::Block,
42 fn_metadata: DISubprogram,
43 fn_ast_id: ast::NodeId)
44 -> NodeMap<DIScope> {
45 let mut scope_map = NodeMap();
46 let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
47 scope_map.insert(fn_ast_id, fn_metadata);
48
49 // Push argument identifiers onto the stack so arguments integrate nicely
50 // with variable shadowing.
51 for arg in args {
52 pat_util::pat_bindings(&arg.pat, |_, node_id, _, path1| {
53 scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
54 name: Some(path1.node) });
55 scope_map.insert(node_id, fn_metadata);
56 })
57 }
58
59 // Clang creates a separate scope for function bodies, so let's do this too.
60 with_new_scope(cx,
61 fn_entry_block.span,
62 &mut scope_stack,
63 &mut scope_map,
64 |cx, scope_stack, scope_map| {
65 walk_block(cx, fn_entry_block, scope_stack, scope_map);
66 });
67
68 return scope_map;
69 }
70
71 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
72 /// If debuginfo is disabled, the returned vector is empty.
73 pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
74 let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
75 let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes);
76
77 let fn_metadata = match fcx.debug_context {
78 FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
79 FunctionDebugContext::DebugInfoDisabled |
80 FunctionDebugContext::FunctionWithoutDebugInfo => {
81 return scopes;
82 }
83 };
84
85 // Find all the scopes with variables defined in them.
86 let mut has_variables = BitVector::new(mir.visibility_scopes.len());
87 for var in &mir.var_decls {
88 has_variables.insert(var.source_info.scope.index());
89 }
90
91 // Instantiate all scopes.
92 for idx in 0..mir.visibility_scopes.len() {
93 let scope = VisibilityScope::new(idx);
94 make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
95 }
96
97 scopes
98 }
99
100 fn make_mir_scope(ccx: &CrateContext,
101 mir: &Mir,
102 has_variables: &BitVector,
103 fn_metadata: DISubprogram,
104 scope: VisibilityScope,
105 scopes: &mut IndexVec<VisibilityScope, DIScope>) {
106 if !scopes[scope].is_null() {
107 return;
108 }
109
110 let scope_data = &mir.visibility_scopes[scope];
111 let parent_scope = if let Some(parent) = scope_data.parent_scope {
112 make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
113 scopes[parent]
114 } else {
115 // The root is the function itself.
116 scopes[scope] = fn_metadata;
117 return;
118 };
119
120 if !has_variables.contains(scope.index()) {
121 // Do not create a DIScope if there are no variables
122 // defined in this MIR Scope, to avoid debuginfo bloat.
123
124 // However, we don't skip creating a nested scope if
125 // our parent is the root, because we might want to
126 // put arguments in the root and not have shadowing.
127 if parent_scope != fn_metadata {
128 scopes[scope] = parent_scope;
129 return;
130 }
131 }
132
133 let loc = span_start(ccx, scope_data.span);
134 scopes[scope] = unsafe {
135 let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
136 llvm::LLVMRustDIBuilderCreateLexicalBlock(
137 DIB(ccx),
138 parent_scope,
139 file_metadata,
140 loc.line as c_uint,
141 loc.col.to_usize() as c_uint)
142 };
143 }
144
145 // local helper functions for walking the AST.
146 fn with_new_scope<F>(cx: &CrateContext,
147 scope_span: Span,
148 scope_stack: &mut Vec<ScopeStackEntry> ,
149 scope_map: &mut NodeMap<DIScope>,
150 inner_walk: F) where
151 F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
152 {
153 // Create a new lexical scope and push it onto the stack
154 let loc = span_start(cx, scope_span);
155 let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
156 let parent_scope = scope_stack.last().unwrap().scope_metadata;
157
158 let scope_metadata = unsafe {
159 llvm::LLVMRustDIBuilderCreateLexicalBlock(
160 DIB(cx),
161 parent_scope,
162 file_metadata,
163 loc.line as c_uint,
164 loc.col.to_usize() as c_uint)
165 };
166
167 scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
168
169 inner_walk(cx, scope_stack, scope_map);
170
171 // pop artificial scopes
172 while scope_stack.last().unwrap().name.is_some() {
173 scope_stack.pop();
174 }
175
176 if scope_stack.last().unwrap().scope_metadata != scope_metadata {
177 span_bug!(scope_span, "debuginfo: Inconsistency in scope management.");
178 }
179
180 scope_stack.pop();
181 }
182
183 struct ScopeStackEntry {
184 scope_metadata: DIScope,
185 name: Option<ast::Name>
186 }
187
188 fn walk_block(cx: &CrateContext,
189 block: &hir::Block,
190 scope_stack: &mut Vec<ScopeStackEntry> ,
191 scope_map: &mut NodeMap<DIScope>) {
192 scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
193
194 // The interesting things here are statements and the concluding expression.
195 for statement in &block.stmts {
196 scope_map.insert(statement.node.id(),
197 scope_stack.last().unwrap().scope_metadata);
198
199 match statement.node {
200 hir::StmtDecl(ref decl, _) =>
201 walk_decl(cx, &decl, scope_stack, scope_map),
202 hir::StmtExpr(ref exp, _) |
203 hir::StmtSemi(ref exp, _) =>
204 walk_expr(cx, &exp, scope_stack, scope_map),
205 }
206 }
207
208 if let Some(ref exp) = block.expr {
209 walk_expr(cx, &exp, scope_stack, scope_map);
210 }
211 }
212
213 fn walk_decl(cx: &CrateContext,
214 decl: &hir::Decl,
215 scope_stack: &mut Vec<ScopeStackEntry> ,
216 scope_map: &mut NodeMap<DIScope>) {
217 match *decl {
218 codemap::Spanned { node: hir::DeclLocal(ref local), .. } => {
219 scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
220
221 walk_pattern(cx, &local.pat, scope_stack, scope_map);
222
223 if let Some(ref exp) = local.init {
224 walk_expr(cx, &exp, scope_stack, scope_map);
225 }
226 }
227 _ => ()
228 }
229 }
230
231 fn walk_pattern(cx: &CrateContext,
232 pat: &hir::Pat,
233 scope_stack: &mut Vec<ScopeStackEntry> ,
234 scope_map: &mut NodeMap<DIScope>) {
235 // Unfortunately, we cannot just use pat_util::pat_bindings() or
236 // ast_util::walk_pat() here because we have to visit *all* nodes in
237 // order to put them into the scope map. The above functions don't do that.
238 match pat.node {
239 PatKind::Binding(_, ref path1, ref sub_pat_opt) => {
240 // LLVM does not properly generate 'DW_AT_start_scope' fields
241 // for variable DIEs. For this reason we have to introduce
242 // an artificial scope at bindings whenever a variable with
243 // the same name is declared in *any* parent scope.
244 //
245 // Otherwise the following error occurs:
246 //
247 // let x = 10;
248 //
249 // do_something(); // 'gdb print x' correctly prints 10
250 //
251 // {
252 // do_something(); // 'gdb print x' prints 0, because it
253 // // already reads the uninitialized 'x'
254 // // from the next line...
255 // let x = 100;
256 // do_something(); // 'gdb print x' correctly prints 100
257 // }
258
259 // Is there already a binding with that name?
260 // N.B.: this comparison must be UNhygienic... because
261 // gdb knows nothing about the context, so any two
262 // variables with the same name will cause the problem.
263 let name = path1.node;
264 let need_new_scope = scope_stack
265 .iter()
266 .any(|entry| entry.name == Some(name));
267
268 if need_new_scope {
269 // Create a new lexical scope and push it onto the stack
270 let loc = span_start(cx, pat.span);
271 let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
272 let parent_scope = scope_stack.last().unwrap().scope_metadata;
273
274 let scope_metadata = unsafe {
275 llvm::LLVMRustDIBuilderCreateLexicalBlock(
276 DIB(cx),
277 parent_scope,
278 file_metadata,
279 loc.line as c_uint,
280 loc.col.to_usize() as c_uint)
281 };
282
283 scope_stack.push(ScopeStackEntry {
284 scope_metadata: scope_metadata,
285 name: Some(name)
286 });
287
288 } else {
289 // Push a new entry anyway so the name can be found
290 let prev_metadata = scope_stack.last().unwrap().scope_metadata;
291 scope_stack.push(ScopeStackEntry {
292 scope_metadata: prev_metadata,
293 name: Some(name)
294 });
295 }
296
297 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
298
299 if let Some(ref sub_pat) = *sub_pat_opt {
300 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
301 }
302 }
303
304 PatKind::Wild => {
305 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
306 }
307
308 PatKind::TupleStruct(_, ref sub_pats, _) => {
309 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
310
311 for p in sub_pats {
312 walk_pattern(cx, &p, scope_stack, scope_map);
313 }
314 }
315
316 PatKind::Path(..) => {
317 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
318 }
319
320 PatKind::Struct(_, ref field_pats, _) => {
321 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
322
323 for &codemap::Spanned {
324 node: hir::FieldPat { pat: ref sub_pat, .. },
325 ..
326 } in field_pats {
327 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
328 }
329 }
330
331 PatKind::Tuple(ref sub_pats, _) => {
332 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
333
334 for sub_pat in sub_pats {
335 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
336 }
337 }
338
339 PatKind::Box(ref sub_pat) | PatKind::Ref(ref sub_pat, _) => {
340 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
341 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
342 }
343
344 PatKind::Lit(ref exp) => {
345 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
346 walk_expr(cx, &exp, scope_stack, scope_map);
347 }
348
349 PatKind::Range(ref exp1, ref exp2) => {
350 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
351 walk_expr(cx, &exp1, scope_stack, scope_map);
352 walk_expr(cx, &exp2, scope_stack, scope_map);
353 }
354
355 PatKind::Vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
356 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
357
358 for sub_pat in front_sub_pats {
359 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
360 }
361
362 if let Some(ref sub_pat) = *middle_sub_pats {
363 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
364 }
365
366 for sub_pat in back_sub_pats {
367 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
368 }
369 }
370 }
371 }
372
373 fn walk_expr(cx: &CrateContext,
374 exp: &hir::Expr,
375 scope_stack: &mut Vec<ScopeStackEntry> ,
376 scope_map: &mut NodeMap<DIScope>) {
377
378 scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
379
380 match exp.node {
381 hir::ExprLit(_) |
382 hir::ExprBreak(_) |
383 hir::ExprAgain(_) |
384 hir::ExprPath(..) => {}
385
386 hir::ExprCast(ref sub_exp, _) |
387 hir::ExprType(ref sub_exp, _) |
388 hir::ExprAddrOf(_, ref sub_exp) |
389 hir::ExprField(ref sub_exp, _) |
390 hir::ExprTupField(ref sub_exp, _) =>
391 walk_expr(cx, &sub_exp, scope_stack, scope_map),
392
393 hir::ExprBox(ref sub_expr) => {
394 walk_expr(cx, &sub_expr, scope_stack, scope_map);
395 }
396
397 hir::ExprRet(ref exp_opt) => match *exp_opt {
398 Some(ref sub_exp) => walk_expr(cx, &sub_exp, scope_stack, scope_map),
399 None => ()
400 },
401
402 hir::ExprUnary(_, ref sub_exp) => {
403 walk_expr(cx, &sub_exp, scope_stack, scope_map);
404 }
405
406 hir::ExprAssignOp(_, ref lhs, ref rhs) |
407 hir::ExprIndex(ref lhs, ref rhs) |
408 hir::ExprBinary(_, ref lhs, ref rhs) => {
409 walk_expr(cx, &lhs, scope_stack, scope_map);
410 walk_expr(cx, &rhs, scope_stack, scope_map);
411 }
412
413 hir::ExprVec(ref init_expressions) |
414 hir::ExprTup(ref init_expressions) => {
415 for ie in init_expressions {
416 walk_expr(cx, &ie, scope_stack, scope_map);
417 }
418 }
419
420 hir::ExprAssign(ref sub_exp1, ref sub_exp2) |
421 hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
422 walk_expr(cx, &sub_exp1, scope_stack, scope_map);
423 walk_expr(cx, &sub_exp2, scope_stack, scope_map);
424 }
425
426 hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
427 walk_expr(cx, &cond_exp, scope_stack, scope_map);
428
429 with_new_scope(cx,
430 then_block.span,
431 scope_stack,
432 scope_map,
433 |cx, scope_stack, scope_map| {
434 walk_block(cx, &then_block, scope_stack, scope_map);
435 });
436
437 match *opt_else_exp {
438 Some(ref else_exp) =>
439 walk_expr(cx, &else_exp, scope_stack, scope_map),
440 _ => ()
441 }
442 }
443
444 hir::ExprWhile(ref cond_exp, ref loop_body, _) => {
445 walk_expr(cx, &cond_exp, scope_stack, scope_map);
446
447 with_new_scope(cx,
448 loop_body.span,
449 scope_stack,
450 scope_map,
451 |cx, scope_stack, scope_map| {
452 walk_block(cx, &loop_body, scope_stack, scope_map);
453 })
454 }
455
456 hir::ExprLoop(ref block, _) |
457 hir::ExprBlock(ref block) => {
458 with_new_scope(cx,
459 block.span,
460 scope_stack,
461 scope_map,
462 |cx, scope_stack, scope_map| {
463 walk_block(cx, &block, scope_stack, scope_map);
464 })
465 }
466
467 hir::ExprClosure(_, ref decl, ref block, _) => {
468 with_new_scope(cx,
469 block.span,
470 scope_stack,
471 scope_map,
472 |cx, scope_stack, scope_map| {
473 for &hir::Arg { pat: ref pattern, .. } in &decl.inputs {
474 walk_pattern(cx, &pattern, scope_stack, scope_map);
475 }
476
477 walk_block(cx, &block, scope_stack, scope_map);
478 })
479 }
480
481 hir::ExprCall(ref fn_exp, ref args) => {
482 walk_expr(cx, &fn_exp, scope_stack, scope_map);
483
484 for arg_exp in args {
485 walk_expr(cx, &arg_exp, scope_stack, scope_map);
486 }
487 }
488
489 hir::ExprMethodCall(_, _, ref args) => {
490 for arg_exp in args {
491 walk_expr(cx, &arg_exp, scope_stack, scope_map);
492 }
493 }
494
495 hir::ExprMatch(ref discriminant_exp, ref arms, _) => {
496 walk_expr(cx, &discriminant_exp, scope_stack, scope_map);
497
498 // For each arm we have to first walk the pattern as these might
499 // introduce new artificial scopes. It should be sufficient to
500 // walk only one pattern per arm, as they all must contain the
501 // same binding names.
502
503 for arm_ref in arms {
504 let arm_span = arm_ref.pats[0].span;
505
506 with_new_scope(cx,
507 arm_span,
508 scope_stack,
509 scope_map,
510 |cx, scope_stack, scope_map| {
511 for pat in &arm_ref.pats {
512 walk_pattern(cx, &pat, scope_stack, scope_map);
513 }
514
515 if let Some(ref guard_exp) = arm_ref.guard {
516 walk_expr(cx, &guard_exp, scope_stack, scope_map)
517 }
518
519 walk_expr(cx, &arm_ref.body, scope_stack, scope_map);
520 })
521 }
522 }
523
524 hir::ExprStruct(_, ref fields, ref base_exp) => {
525 for &hir::Field { expr: ref exp, .. } in fields {
526 walk_expr(cx, &exp, scope_stack, scope_map);
527 }
528
529 match *base_exp {
530 Some(ref exp) => walk_expr(cx, &exp, scope_stack, scope_map),
531 None => ()
532 }
533 }
534
535 hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
536 for output in outputs {
537 walk_expr(cx, output, scope_stack, scope_map);
538 }
539
540 for input in inputs {
541 walk_expr(cx, input, scope_stack, scope_map);
542 }
543 }
544 }
545 }