]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/debuginfo/create_scope_map.rs
Changed issue number to 36105
[rust.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 }