]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/debuginfo/create_scope_map.rs
hir, mir: Separate HIR expressions / MIR operands from InlineAsm.
[rust.git] / src / librustc_trans / 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::metadata::file_metadata;
12 use super::utils::DIB;
13
14 use llvm;
15 use llvm::debuginfo::{DIScope, DISubprogram};
16 use trans::common::CrateContext;
17 use middle::pat_util;
18 use rustc::util::nodemap::NodeMap;
19
20 use libc::c_uint;
21 use syntax::codemap::{Span, Pos};
22 use syntax::{ast, codemap};
23
24 use rustc_front;
25 use rustc_front::hir::{self, PatKind};
26
27 // This procedure builds the *scope map* for a given function, which maps any
28 // given ast::NodeId in the function's AST to the correct DIScope metadata instance.
29 //
30 // This builder procedure walks the AST in execution order and keeps track of
31 // what belongs to which scope, creating DIScope DIEs along the way, and
32 // introducing *artificial* lexical scope descriptors where necessary. These
33 // artificial scopes allow GDB to correctly handle name shadowing.
34 pub fn create_scope_map(cx: &CrateContext,
35                         args: &[hir::Arg],
36                         fn_entry_block: &hir::Block,
37                         fn_metadata: DISubprogram,
38                         fn_ast_id: ast::NodeId)
39                         -> NodeMap<DIScope> {
40     let mut scope_map = NodeMap();
41
42     let def_map = &cx.tcx().def_map;
43
44     let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
45     scope_map.insert(fn_ast_id, fn_metadata);
46
47     // Push argument identifiers onto the stack so arguments integrate nicely
48     // with variable shadowing.
49     for arg in args {
50         pat_util::pat_bindings_ident(def_map, &arg.pat, |_, node_id, _, path1| {
51             scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
52                                                name: Some(path1.node.unhygienic_name) });
53             scope_map.insert(node_id, fn_metadata);
54         })
55     }
56
57     // Clang creates a separate scope for function bodies, so let's do this too.
58     with_new_scope(cx,
59                    fn_entry_block.span,
60                    &mut scope_stack,
61                    &mut scope_map,
62                    |cx, scope_stack, scope_map| {
63         walk_block(cx, fn_entry_block, scope_stack, scope_map);
64     });
65
66     return scope_map;
67 }
68
69 // local helper functions for walking the AST.
70 fn with_new_scope<F>(cx: &CrateContext,
71                      scope_span: Span,
72                      scope_stack: &mut Vec<ScopeStackEntry> ,
73                      scope_map: &mut NodeMap<DIScope>,
74                      inner_walk: F) where
75     F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
76 {
77     // Create a new lexical scope and push it onto the stack
78     let loc = cx.sess().codemap().lookup_char_pos(scope_span.lo);
79     let file_metadata = file_metadata(cx, &loc.file.name);
80     let parent_scope = scope_stack.last().unwrap().scope_metadata;
81
82     let scope_metadata = unsafe {
83         llvm::LLVMDIBuilderCreateLexicalBlock(
84             DIB(cx),
85             parent_scope,
86             file_metadata,
87             loc.line as c_uint,
88             loc.col.to_usize() as c_uint)
89     };
90
91     scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
92
93     inner_walk(cx, scope_stack, scope_map);
94
95     // pop artificial scopes
96     while scope_stack.last().unwrap().name.is_some() {
97         scope_stack.pop();
98     }
99
100     if scope_stack.last().unwrap().scope_metadata != scope_metadata {
101         cx.sess().span_bug(scope_span, "debuginfo: Inconsistency in scope management.");
102     }
103
104     scope_stack.pop();
105 }
106
107 struct ScopeStackEntry {
108     scope_metadata: DIScope,
109     name: Option<ast::Name>
110 }
111
112 fn walk_block(cx: &CrateContext,
113               block: &hir::Block,
114               scope_stack: &mut Vec<ScopeStackEntry> ,
115               scope_map: &mut NodeMap<DIScope>) {
116     scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
117
118     // The interesting things here are statements and the concluding expression.
119     for statement in &block.stmts {
120         scope_map.insert(rustc_front::util::stmt_id(statement),
121                          scope_stack.last().unwrap().scope_metadata);
122
123         match statement.node {
124             hir::StmtDecl(ref decl, _) =>
125                 walk_decl(cx, &decl, scope_stack, scope_map),
126             hir::StmtExpr(ref exp, _) |
127             hir::StmtSemi(ref exp, _) =>
128                 walk_expr(cx, &exp, scope_stack, scope_map),
129         }
130     }
131
132     if let Some(ref exp) = block.expr {
133         walk_expr(cx, &exp, scope_stack, scope_map);
134     }
135 }
136
137 fn walk_decl(cx: &CrateContext,
138              decl: &hir::Decl,
139              scope_stack: &mut Vec<ScopeStackEntry> ,
140              scope_map: &mut NodeMap<DIScope>) {
141     match *decl {
142         codemap::Spanned { node: hir::DeclLocal(ref local), .. } => {
143             scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
144
145             walk_pattern(cx, &local.pat, scope_stack, scope_map);
146
147             if let Some(ref exp) = local.init {
148                 walk_expr(cx, &exp, scope_stack, scope_map);
149             }
150         }
151         _ => ()
152     }
153 }
154
155 fn walk_pattern(cx: &CrateContext,
156                 pat: &hir::Pat,
157                 scope_stack: &mut Vec<ScopeStackEntry> ,
158                 scope_map: &mut NodeMap<DIScope>) {
159
160     let def_map = &cx.tcx().def_map;
161
162     // Unfortunately, we cannot just use pat_util::pat_bindings() or
163     // ast_util::walk_pat() here because we have to visit *all* nodes in
164     // order to put them into the scope map. The above functions don't do that.
165     match pat.node {
166         PatKind::Ident(_, ref path1, ref sub_pat_opt) => {
167
168             // Check if this is a binding. If so we need to put it on the
169             // scope stack and maybe introduce an artificial scope
170             if pat_util::pat_is_binding(&def_map.borrow(), &pat) {
171
172                 let name = path1.node.unhygienic_name;
173
174                 // LLVM does not properly generate 'DW_AT_start_scope' fields
175                 // for variable DIEs. For this reason we have to introduce
176                 // an artificial scope at bindings whenever a variable with
177                 // the same name is declared in *any* parent scope.
178                 //
179                 // Otherwise the following error occurs:
180                 //
181                 // let x = 10;
182                 //
183                 // do_something(); // 'gdb print x' correctly prints 10
184                 //
185                 // {
186                 //     do_something(); // 'gdb print x' prints 0, because it
187                 //                     // already reads the uninitialized 'x'
188                 //                     // from the next line...
189                 //     let x = 100;
190                 //     do_something(); // 'gdb print x' correctly prints 100
191                 // }
192
193                 // Is there already a binding with that name?
194                 // N.B.: this comparison must be UNhygienic... because
195                 // gdb knows nothing about the context, so any two
196                 // variables with the same name will cause the problem.
197                 let need_new_scope = scope_stack
198                     .iter()
199                     .any(|entry| entry.name == Some(name));
200
201                 if need_new_scope {
202                     // Create a new lexical scope and push it onto the stack
203                     let loc = cx.sess().codemap().lookup_char_pos(pat.span.lo);
204                     let file_metadata = file_metadata(cx, &loc.file.name);
205                     let parent_scope = scope_stack.last().unwrap().scope_metadata;
206
207                     let scope_metadata = unsafe {
208                         llvm::LLVMDIBuilderCreateLexicalBlock(
209                             DIB(cx),
210                             parent_scope,
211                             file_metadata,
212                             loc.line as c_uint,
213                             loc.col.to_usize() as c_uint)
214                     };
215
216                     scope_stack.push(ScopeStackEntry {
217                         scope_metadata: scope_metadata,
218                         name: Some(name)
219                     });
220
221                 } else {
222                     // Push a new entry anyway so the name can be found
223                     let prev_metadata = scope_stack.last().unwrap().scope_metadata;
224                     scope_stack.push(ScopeStackEntry {
225                         scope_metadata: prev_metadata,
226                         name: Some(name)
227                     });
228                 }
229             }
230
231             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
232
233             if let Some(ref sub_pat) = *sub_pat_opt {
234                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
235             }
236         }
237
238         PatKind::Wild => {
239             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
240         }
241
242         PatKind::TupleStruct(_, ref sub_pats_opt) => {
243             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
244
245             if let Some(ref sub_pats) = *sub_pats_opt {
246                 for p in sub_pats {
247                     walk_pattern(cx, &p, scope_stack, scope_map);
248                 }
249             }
250         }
251
252         PatKind::Path(..) | PatKind::QPath(..) => {
253             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
254         }
255
256         PatKind::Struct(_, ref field_pats, _) => {
257             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
258
259             for &codemap::Spanned {
260                 node: hir::FieldPat { pat: ref sub_pat, .. },
261                 ..
262             } in field_pats {
263                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
264             }
265         }
266
267         PatKind::Tup(ref sub_pats) => {
268             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
269
270             for sub_pat in sub_pats {
271                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
272             }
273         }
274
275         PatKind::Box(ref sub_pat) | PatKind::Ref(ref sub_pat, _) => {
276             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
277             walk_pattern(cx, &sub_pat, scope_stack, scope_map);
278         }
279
280         PatKind::Lit(ref exp) => {
281             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
282             walk_expr(cx, &exp, scope_stack, scope_map);
283         }
284
285         PatKind::Range(ref exp1, ref exp2) => {
286             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
287             walk_expr(cx, &exp1, scope_stack, scope_map);
288             walk_expr(cx, &exp2, scope_stack, scope_map);
289         }
290
291         PatKind::Vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
292             scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
293
294             for sub_pat in front_sub_pats {
295                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
296             }
297
298             if let Some(ref sub_pat) = *middle_sub_pats {
299                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
300             }
301
302             for sub_pat in back_sub_pats {
303                 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
304             }
305         }
306     }
307 }
308
309 fn walk_expr(cx: &CrateContext,
310              exp: &hir::Expr,
311              scope_stack: &mut Vec<ScopeStackEntry> ,
312              scope_map: &mut NodeMap<DIScope>) {
313
314     scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
315
316     match exp.node {
317         hir::ExprLit(_)   |
318         hir::ExprBreak(_) |
319         hir::ExprAgain(_) |
320         hir::ExprPath(..) => {}
321
322         hir::ExprCast(ref sub_exp, _)     |
323         hir::ExprType(ref sub_exp, _) |
324         hir::ExprAddrOf(_, ref sub_exp)  |
325         hir::ExprField(ref sub_exp, _) |
326         hir::ExprTupField(ref sub_exp, _) =>
327             walk_expr(cx, &sub_exp, scope_stack, scope_map),
328
329         hir::ExprBox(ref sub_expr) => {
330             walk_expr(cx, &sub_expr, scope_stack, scope_map);
331         }
332
333         hir::ExprRet(ref exp_opt) => match *exp_opt {
334             Some(ref sub_exp) => walk_expr(cx, &sub_exp, scope_stack, scope_map),
335             None => ()
336         },
337
338         hir::ExprUnary(_, ref sub_exp) => {
339             walk_expr(cx, &sub_exp, scope_stack, scope_map);
340         }
341
342         hir::ExprAssignOp(_, ref lhs, ref rhs) |
343         hir::ExprIndex(ref lhs, ref rhs) |
344         hir::ExprBinary(_, ref lhs, ref rhs)    => {
345             walk_expr(cx, &lhs, scope_stack, scope_map);
346             walk_expr(cx, &rhs, scope_stack, scope_map);
347         }
348
349         hir::ExprVec(ref init_expressions) |
350         hir::ExprTup(ref init_expressions) => {
351             for ie in init_expressions {
352                 walk_expr(cx, &ie, scope_stack, scope_map);
353             }
354         }
355
356         hir::ExprAssign(ref sub_exp1, ref sub_exp2) |
357         hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
358             walk_expr(cx, &sub_exp1, scope_stack, scope_map);
359             walk_expr(cx, &sub_exp2, scope_stack, scope_map);
360         }
361
362         hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
363             walk_expr(cx, &cond_exp, scope_stack, scope_map);
364
365             with_new_scope(cx,
366                            then_block.span,
367                            scope_stack,
368                            scope_map,
369                            |cx, scope_stack, scope_map| {
370                 walk_block(cx, &then_block, scope_stack, scope_map);
371             });
372
373             match *opt_else_exp {
374                 Some(ref else_exp) =>
375                     walk_expr(cx, &else_exp, scope_stack, scope_map),
376                 _ => ()
377             }
378         }
379
380         hir::ExprWhile(ref cond_exp, ref loop_body, _) => {
381             walk_expr(cx, &cond_exp, scope_stack, scope_map);
382
383             with_new_scope(cx,
384                            loop_body.span,
385                            scope_stack,
386                            scope_map,
387                            |cx, scope_stack, scope_map| {
388                 walk_block(cx, &loop_body, scope_stack, scope_map);
389             })
390         }
391
392         hir::ExprLoop(ref block, _) |
393         hir::ExprBlock(ref block)   => {
394             with_new_scope(cx,
395                            block.span,
396                            scope_stack,
397                            scope_map,
398                            |cx, scope_stack, scope_map| {
399                 walk_block(cx, &block, scope_stack, scope_map);
400             })
401         }
402
403         hir::ExprClosure(_, ref decl, ref block) => {
404             with_new_scope(cx,
405                            block.span,
406                            scope_stack,
407                            scope_map,
408                            |cx, scope_stack, scope_map| {
409                 for &hir::Arg { pat: ref pattern, .. } in &decl.inputs {
410                     walk_pattern(cx, &pattern, scope_stack, scope_map);
411                 }
412
413                 walk_block(cx, &block, scope_stack, scope_map);
414             })
415         }
416
417         hir::ExprCall(ref fn_exp, ref args) => {
418             walk_expr(cx, &fn_exp, scope_stack, scope_map);
419
420             for arg_exp in args {
421                 walk_expr(cx, &arg_exp, scope_stack, scope_map);
422             }
423         }
424
425         hir::ExprMethodCall(_, _, ref args) => {
426             for arg_exp in args {
427                 walk_expr(cx, &arg_exp, scope_stack, scope_map);
428             }
429         }
430
431         hir::ExprMatch(ref discriminant_exp, ref arms, _) => {
432             walk_expr(cx, &discriminant_exp, scope_stack, scope_map);
433
434             // For each arm we have to first walk the pattern as these might
435             // introduce new artificial scopes. It should be sufficient to
436             // walk only one pattern per arm, as they all must contain the
437             // same binding names.
438
439             for arm_ref in arms {
440                 let arm_span = arm_ref.pats[0].span;
441
442                 with_new_scope(cx,
443                                arm_span,
444                                scope_stack,
445                                scope_map,
446                                |cx, scope_stack, scope_map| {
447                     for pat in &arm_ref.pats {
448                         walk_pattern(cx, &pat, scope_stack, scope_map);
449                     }
450
451                     if let Some(ref guard_exp) = arm_ref.guard {
452                         walk_expr(cx, &guard_exp, scope_stack, scope_map)
453                     }
454
455                     walk_expr(cx, &arm_ref.body, scope_stack, scope_map);
456                 })
457             }
458         }
459
460         hir::ExprStruct(_, ref fields, ref base_exp) => {
461             for &hir::Field { expr: ref exp, .. } in fields {
462                 walk_expr(cx, &exp, scope_stack, scope_map);
463             }
464
465             match *base_exp {
466                 Some(ref exp) => walk_expr(cx, &exp, scope_stack, scope_map),
467                 None => ()
468             }
469         }
470
471         hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
472             for output in outputs {
473                 walk_expr(cx, output, scope_stack, scope_map);
474             }
475
476             for input in inputs {
477                 walk_expr(cx, input, scope_stack, scope_map);
478             }
479         }
480     }
481 }