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