]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/debuginfo/create_scope_map.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / trans / debuginfo / create_scope_map.rs
CommitLineData
d9579d0f
AL
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
11use super::metadata::file_metadata;
12use super::utils::DIB;
13
14use llvm;
15use llvm::debuginfo::{DIScope, DISubprogram};
16use trans::common::CrateContext;
17use middle::pat_util;
e9174d1e 18use rustc::util::nodemap::NodeMap;
d9579d0f
AL
19
20use libc::c_uint;
21use syntax::codemap::{Span, Pos};
e9174d1e
SL
22use syntax::{ast, codemap};
23
24use rustc_front;
7453a54e 25use rustc_front::hir::{self, PatKind};
d9579d0f
AL
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.
34pub fn create_scope_map(cx: &CrateContext,
e9174d1e
SL
35 args: &[hir::Arg],
36 fn_entry_block: &hir::Block,
d9579d0f
AL
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 {
7453a54e 50 pat_util::pat_bindings_ident(def_map, &arg.pat, |_, node_id, _, path1| {
d9579d0f 51 scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
92a42be0 52 name: Some(path1.node.unhygienic_name) });
d9579d0f
AL
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.
70fn 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
107struct ScopeStackEntry {
108 scope_metadata: DIScope,
109 name: Option<ast::Name>
110}
111
112fn walk_block(cx: &CrateContext,
e9174d1e 113 block: &hir::Block,
d9579d0f
AL
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 {
92a42be0 120 scope_map.insert(rustc_front::util::stmt_id(statement),
d9579d0f
AL
121 scope_stack.last().unwrap().scope_metadata);
122
123 match statement.node {
e9174d1e 124 hir::StmtDecl(ref decl, _) =>
7453a54e 125 walk_decl(cx, &decl, scope_stack, scope_map),
e9174d1e
SL
126 hir::StmtExpr(ref exp, _) |
127 hir::StmtSemi(ref exp, _) =>
7453a54e 128 walk_expr(cx, &exp, scope_stack, scope_map),
d9579d0f
AL
129 }
130 }
131
132 if let Some(ref exp) = block.expr {
7453a54e 133 walk_expr(cx, &exp, scope_stack, scope_map);
d9579d0f
AL
134 }
135}
136
137fn walk_decl(cx: &CrateContext,
e9174d1e 138 decl: &hir::Decl,
d9579d0f
AL
139 scope_stack: &mut Vec<ScopeStackEntry> ,
140 scope_map: &mut NodeMap<DIScope>) {
141 match *decl {
e9174d1e 142 codemap::Spanned { node: hir::DeclLocal(ref local), .. } => {
d9579d0f
AL
143 scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
144
7453a54e 145 walk_pattern(cx, &local.pat, scope_stack, scope_map);
d9579d0f
AL
146
147 if let Some(ref exp) = local.init {
7453a54e 148 walk_expr(cx, &exp, scope_stack, scope_map);
d9579d0f
AL
149 }
150 }
151 _ => ()
152 }
153}
154
155fn walk_pattern(cx: &CrateContext,
e9174d1e 156 pat: &hir::Pat,
d9579d0f
AL
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 {
7453a54e 166 PatKind::Ident(_, ref path1, ref sub_pat_opt) => {
d9579d0f
AL
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
7453a54e 170 if pat_util::pat_is_binding(&def_map.borrow(), &pat) {
d9579d0f 171
92a42be0 172 let name = path1.node.unhygienic_name;
d9579d0f
AL
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 {
7453a54e 234 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
235 }
236 }
237
7453a54e 238 PatKind::Wild => {
d9579d0f
AL
239 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
240 }
241
7453a54e 242 PatKind::TupleStruct(_, ref sub_pats_opt) => {
d9579d0f
AL
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 {
7453a54e 247 walk_pattern(cx, &p, scope_stack, scope_map);
d9579d0f
AL
248 }
249 }
250 }
251
7453a54e 252 PatKind::Path(..) | PatKind::QPath(..) => {
d9579d0f
AL
253 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
254 }
255
7453a54e 256 PatKind::Struct(_, ref field_pats, _) => {
d9579d0f
AL
257 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
258
259 for &codemap::Spanned {
e9174d1e 260 node: hir::FieldPat { pat: ref sub_pat, .. },
d9579d0f 261 ..
62682a34 262 } in field_pats {
7453a54e 263 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
264 }
265 }
266
7453a54e 267 PatKind::Tup(ref sub_pats) => {
d9579d0f
AL
268 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
269
270 for sub_pat in sub_pats {
7453a54e 271 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
272 }
273 }
274
7453a54e 275 PatKind::Box(ref sub_pat) | PatKind::Ref(ref sub_pat, _) => {
d9579d0f 276 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
7453a54e 277 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
278 }
279
7453a54e 280 PatKind::Lit(ref exp) => {
d9579d0f 281 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
7453a54e 282 walk_expr(cx, &exp, scope_stack, scope_map);
d9579d0f
AL
283 }
284
7453a54e 285 PatKind::Range(ref exp1, ref exp2) => {
d9579d0f 286 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
7453a54e
SL
287 walk_expr(cx, &exp1, scope_stack, scope_map);
288 walk_expr(cx, &exp2, scope_stack, scope_map);
d9579d0f
AL
289 }
290
7453a54e 291 PatKind::Vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
d9579d0f
AL
292 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
293
294 for sub_pat in front_sub_pats {
7453a54e 295 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
296 }
297
298 if let Some(ref sub_pat) = *middle_sub_pats {
7453a54e 299 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
300 }
301
302 for sub_pat in back_sub_pats {
7453a54e 303 walk_pattern(cx, &sub_pat, scope_stack, scope_map);
d9579d0f
AL
304 }
305 }
d9579d0f
AL
306 }
307}
308
309fn walk_expr(cx: &CrateContext,
e9174d1e 310 exp: &hir::Expr,
d9579d0f
AL
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 {
e9174d1e
SL
317 hir::ExprLit(_) |
318 hir::ExprBreak(_) |
319 hir::ExprAgain(_) |
320 hir::ExprPath(..) => {}
321
322 hir::ExprCast(ref sub_exp, _) |
9cc50fc6 323 hir::ExprType(ref sub_exp, _) |
e9174d1e
SL
324 hir::ExprAddrOf(_, ref sub_exp) |
325 hir::ExprField(ref sub_exp, _) |
b039eaaf 326 hir::ExprTupField(ref sub_exp, _) =>
7453a54e 327 walk_expr(cx, &sub_exp, scope_stack, scope_map),
d9579d0f 328
b039eaaf 329 hir::ExprBox(ref sub_expr) => {
7453a54e 330 walk_expr(cx, &sub_expr, scope_stack, scope_map);
d9579d0f
AL
331 }
332
e9174d1e 333 hir::ExprRet(ref exp_opt) => match *exp_opt {
7453a54e 334 Some(ref sub_exp) => walk_expr(cx, &sub_exp, scope_stack, scope_map),
d9579d0f
AL
335 None => ()
336 },
337
e9174d1e 338 hir::ExprUnary(_, ref sub_exp) => {
7453a54e 339 walk_expr(cx, &sub_exp, scope_stack, scope_map);
d9579d0f
AL
340 }
341
e9174d1e
SL
342 hir::ExprAssignOp(_, ref lhs, ref rhs) |
343 hir::ExprIndex(ref lhs, ref rhs) |
344 hir::ExprBinary(_, ref lhs, ref rhs) => {
7453a54e
SL
345 walk_expr(cx, &lhs, scope_stack, scope_map);
346 walk_expr(cx, &rhs, scope_stack, scope_map);
d9579d0f
AL
347 }
348
e9174d1e 349 hir::ExprRange(ref start, ref end) => {
7453a54e
SL
350 start.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map));
351 end.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map));
d9579d0f
AL
352 }
353
e9174d1e
SL
354 hir::ExprVec(ref init_expressions) |
355 hir::ExprTup(ref init_expressions) => {
d9579d0f 356 for ie in init_expressions {
7453a54e 357 walk_expr(cx, &ie, scope_stack, scope_map);
d9579d0f
AL
358 }
359 }
360
e9174d1e
SL
361 hir::ExprAssign(ref sub_exp1, ref sub_exp2) |
362 hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
7453a54e
SL
363 walk_expr(cx, &sub_exp1, scope_stack, scope_map);
364 walk_expr(cx, &sub_exp2, scope_stack, scope_map);
d9579d0f
AL
365 }
366
e9174d1e 367 hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
7453a54e 368 walk_expr(cx, &cond_exp, scope_stack, scope_map);
d9579d0f
AL
369
370 with_new_scope(cx,
371 then_block.span,
372 scope_stack,
373 scope_map,
374 |cx, scope_stack, scope_map| {
7453a54e 375 walk_block(cx, &then_block, scope_stack, scope_map);
d9579d0f
AL
376 });
377
378 match *opt_else_exp {
379 Some(ref else_exp) =>
7453a54e 380 walk_expr(cx, &else_exp, scope_stack, scope_map),
d9579d0f
AL
381 _ => ()
382 }
383 }
384
e9174d1e 385 hir::ExprWhile(ref cond_exp, ref loop_body, _) => {
7453a54e 386 walk_expr(cx, &cond_exp, scope_stack, scope_map);
d9579d0f
AL
387
388 with_new_scope(cx,
389 loop_body.span,
390 scope_stack,
391 scope_map,
392 |cx, scope_stack, scope_map| {
7453a54e 393 walk_block(cx, &loop_body, scope_stack, scope_map);
d9579d0f
AL
394 })
395 }
396
e9174d1e
SL
397 hir::ExprLoop(ref block, _) |
398 hir::ExprBlock(ref block) => {
d9579d0f
AL
399 with_new_scope(cx,
400 block.span,
401 scope_stack,
402 scope_map,
403 |cx, scope_stack, scope_map| {
7453a54e 404 walk_block(cx, &block, scope_stack, scope_map);
d9579d0f
AL
405 })
406 }
407
e9174d1e 408 hir::ExprClosure(_, ref decl, ref block) => {
d9579d0f
AL
409 with_new_scope(cx,
410 block.span,
411 scope_stack,
412 scope_map,
413 |cx, scope_stack, scope_map| {
e9174d1e 414 for &hir::Arg { pat: ref pattern, .. } in &decl.inputs {
7453a54e 415 walk_pattern(cx, &pattern, scope_stack, scope_map);
d9579d0f
AL
416 }
417
7453a54e 418 walk_block(cx, &block, scope_stack, scope_map);
d9579d0f
AL
419 })
420 }
421
e9174d1e 422 hir::ExprCall(ref fn_exp, ref args) => {
7453a54e 423 walk_expr(cx, &fn_exp, scope_stack, scope_map);
d9579d0f
AL
424
425 for arg_exp in args {
7453a54e 426 walk_expr(cx, &arg_exp, scope_stack, scope_map);
d9579d0f
AL
427 }
428 }
429
e9174d1e 430 hir::ExprMethodCall(_, _, ref args) => {
d9579d0f 431 for arg_exp in args {
7453a54e 432 walk_expr(cx, &arg_exp, scope_stack, scope_map);
d9579d0f
AL
433 }
434 }
435
e9174d1e 436 hir::ExprMatch(ref discriminant_exp, ref arms, _) => {
7453a54e 437 walk_expr(cx, &discriminant_exp, scope_stack, scope_map);
d9579d0f
AL
438
439 // For each arm we have to first walk the pattern as these might
440 // introduce new artificial scopes. It should be sufficient to
441 // walk only one pattern per arm, as they all must contain the
442 // same binding names.
443
444 for arm_ref in arms {
445 let arm_span = arm_ref.pats[0].span;
446
447 with_new_scope(cx,
448 arm_span,
449 scope_stack,
450 scope_map,
451 |cx, scope_stack, scope_map| {
452 for pat in &arm_ref.pats {
7453a54e 453 walk_pattern(cx, &pat, scope_stack, scope_map);
d9579d0f
AL
454 }
455
456 if let Some(ref guard_exp) = arm_ref.guard {
7453a54e 457 walk_expr(cx, &guard_exp, scope_stack, scope_map)
d9579d0f
AL
458 }
459
7453a54e 460 walk_expr(cx, &arm_ref.body, scope_stack, scope_map);
d9579d0f
AL
461 })
462 }
463 }
464
e9174d1e
SL
465 hir::ExprStruct(_, ref fields, ref base_exp) => {
466 for &hir::Field { expr: ref exp, .. } in fields {
7453a54e 467 walk_expr(cx, &exp, scope_stack, scope_map);
d9579d0f
AL
468 }
469
470 match *base_exp {
7453a54e 471 Some(ref exp) => walk_expr(cx, &exp, scope_stack, scope_map),
d9579d0f
AL
472 None => ()
473 }
474 }
475
e9174d1e 476 hir::ExprInlineAsm(hir::InlineAsm { ref inputs,
d9579d0f
AL
477 ref outputs,
478 .. }) => {
479 // inputs, outputs: Vec<(String, P<Expr>)>
480 for &(_, ref exp) in inputs {
7453a54e 481 walk_expr(cx, &exp, scope_stack, scope_map);
d9579d0f
AL
482 }
483
9cc50fc6 484 for out in outputs {
7453a54e 485 walk_expr(cx, &out.expr, scope_stack, scope_map);
d9579d0f
AL
486 }
487 }
488 }
92a42be0 489}