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.
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.
11 use super::metadata::file_metadata;
12 use super::utils::DIB;
15 use llvm::debuginfo::{DIScope, DISubprogram};
16 use trans::common::CrateContext;
18 use rustc::util::nodemap::NodeMap;
21 use syntax::codemap::{Span, Pos};
22 use syntax::{ast, codemap};
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.
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,
36 fn_entry_block: &hir::Block,
37 fn_metadata: DISubprogram,
38 fn_ast_id: ast::NodeId)
40 let mut scope_map = NodeMap();
42 let def_map = &cx.tcx().def_map;
44 let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
45 scope_map.insert(fn_ast_id, fn_metadata);
47 // Push argument identifiers onto the stack so arguments integrate nicely
48 // with variable shadowing.
50 pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
51 scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
52 name: Some(path1.node.name) });
53 scope_map.insert(node_id, fn_metadata);
57 // Clang creates a separate scope for function bodies, so let's do this too.
62 |cx, scope_stack, scope_map| {
63 walk_block(cx, fn_entry_block, scope_stack, scope_map);
69 // local helper functions for walking the AST.
70 fn with_new_scope<F>(cx: &CrateContext,
72 scope_stack: &mut Vec<ScopeStackEntry> ,
73 scope_map: &mut NodeMap<DIScope>,
75 F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
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;
82 let scope_metadata = unsafe {
83 llvm::LLVMDIBuilderCreateLexicalBlock(
88 loc.col.to_usize() as c_uint)
91 scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
93 inner_walk(cx, scope_stack, scope_map);
95 // pop artificial scopes
96 while scope_stack.last().unwrap().name.is_some() {
100 if scope_stack.last().unwrap().scope_metadata != scope_metadata {
101 cx.sess().span_bug(scope_span, "debuginfo: Inconsistency in scope management.");
107 struct ScopeStackEntry {
108 scope_metadata: DIScope,
109 name: Option<ast::Name>
112 fn walk_block(cx: &CrateContext,
114 scope_stack: &mut Vec<ScopeStackEntry> ,
115 scope_map: &mut NodeMap<DIScope>) {
116 scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
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);
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),
132 if let Some(ref exp) = block.expr {
133 walk_expr(cx, &**exp, scope_stack, scope_map);
137 fn walk_decl(cx: &CrateContext,
139 scope_stack: &mut Vec<ScopeStackEntry> ,
140 scope_map: &mut NodeMap<DIScope>) {
142 codemap::Spanned { node: hir::DeclLocal(ref local), .. } => {
143 scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
145 walk_pattern(cx, &*local.pat, scope_stack, scope_map);
147 if let Some(ref exp) = local.init {
148 walk_expr(cx, &**exp, scope_stack, scope_map);
155 fn walk_pattern(cx: &CrateContext,
157 scope_stack: &mut Vec<ScopeStackEntry> ,
158 scope_map: &mut NodeMap<DIScope>) {
160 let def_map = &cx.tcx().def_map;
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.
166 hir::PatIdent(_, ref path1, ref sub_pat_opt) => {
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, &*pat) {
172 let name = path1.node.name;
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.
179 // Otherwise the following error occurs:
183 // do_something(); // 'gdb print x' correctly prints 10
186 // do_something(); // 'gdb print x' prints 0, because it
187 // // already reads the uninitialized 'x'
188 // // from the next line...
190 // do_something(); // 'gdb print x' correctly prints 100
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
199 .any(|entry| entry.name == Some(name));
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;
207 let scope_metadata = unsafe {
208 llvm::LLVMDIBuilderCreateLexicalBlock(
213 loc.col.to_usize() as c_uint)
216 scope_stack.push(ScopeStackEntry {
217 scope_metadata: scope_metadata,
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,
231 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
233 if let Some(ref sub_pat) = *sub_pat_opt {
234 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
239 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
242 hir::PatEnum(_, ref sub_pats_opt) => {
243 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
245 if let Some(ref sub_pats) = *sub_pats_opt {
247 walk_pattern(cx, &**p, scope_stack, scope_map);
252 hir::PatQPath(..) => {
253 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
256 hir::PatStruct(_, ref field_pats, _) => {
257 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
259 for &codemap::Spanned {
260 node: hir::FieldPat { pat: ref sub_pat, .. },
263 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
267 hir::PatTup(ref sub_pats) => {
268 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
270 for sub_pat in sub_pats {
271 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
275 hir::PatBox(ref sub_pat) | hir::PatRegion(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);
280 hir::PatLit(ref exp) => {
281 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
282 walk_expr(cx, &**exp, scope_stack, scope_map);
285 hir::PatRange(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);
291 hir::PatVec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
292 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
294 for sub_pat in front_sub_pats {
295 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
298 if let Some(ref sub_pat) = *middle_sub_pats {
299 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
302 for sub_pat in back_sub_pats {
303 walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
309 fn walk_expr(cx: &CrateContext,
311 scope_stack: &mut Vec<ScopeStackEntry> ,
312 scope_map: &mut NodeMap<DIScope>) {
314 scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
320 hir::ExprPath(..) => {}
322 hir::ExprCast(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),
328 hir::ExprBox(ref place, ref sub_expr) => {
330 |e| walk_expr(cx, &**e, scope_stack, scope_map));
331 walk_expr(cx, &**sub_expr, scope_stack, scope_map);
334 hir::ExprRet(ref exp_opt) => match *exp_opt {
335 Some(ref sub_exp) => walk_expr(cx, &**sub_exp, scope_stack, scope_map),
339 hir::ExprUnary(_, ref sub_exp) => {
340 walk_expr(cx, &**sub_exp, scope_stack, scope_map);
343 hir::ExprAssignOp(_, ref lhs, ref rhs) |
344 hir::ExprIndex(ref lhs, ref rhs) |
345 hir::ExprBinary(_, ref lhs, ref rhs) => {
346 walk_expr(cx, &**lhs, scope_stack, scope_map);
347 walk_expr(cx, &**rhs, scope_stack, scope_map);
350 hir::ExprRange(ref start, ref end) => {
351 start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
352 end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
355 hir::ExprVec(ref init_expressions) |
356 hir::ExprTup(ref init_expressions) => {
357 for ie in init_expressions {
358 walk_expr(cx, &**ie, scope_stack, scope_map);
362 hir::ExprAssign(ref sub_exp1, ref sub_exp2) |
363 hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
364 walk_expr(cx, &**sub_exp1, scope_stack, scope_map);
365 walk_expr(cx, &**sub_exp2, scope_stack, scope_map);
368 hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
369 walk_expr(cx, &**cond_exp, scope_stack, scope_map);
375 |cx, scope_stack, scope_map| {
376 walk_block(cx, &**then_block, scope_stack, scope_map);
379 match *opt_else_exp {
380 Some(ref else_exp) =>
381 walk_expr(cx, &**else_exp, scope_stack, scope_map),
386 hir::ExprWhile(ref cond_exp, ref loop_body, _) => {
387 walk_expr(cx, &**cond_exp, scope_stack, scope_map);
393 |cx, scope_stack, scope_map| {
394 walk_block(cx, &**loop_body, scope_stack, scope_map);
398 hir::ExprLoop(ref block, _) |
399 hir::ExprBlock(ref block) => {
404 |cx, scope_stack, scope_map| {
405 walk_block(cx, &**block, scope_stack, scope_map);
409 hir::ExprClosure(_, ref decl, ref block) => {
414 |cx, scope_stack, scope_map| {
415 for &hir::Arg { pat: ref pattern, .. } in &decl.inputs {
416 walk_pattern(cx, &**pattern, scope_stack, scope_map);
419 walk_block(cx, &**block, scope_stack, scope_map);
423 hir::ExprCall(ref fn_exp, ref args) => {
424 walk_expr(cx, &**fn_exp, scope_stack, scope_map);
426 for arg_exp in args {
427 walk_expr(cx, &**arg_exp, scope_stack, scope_map);
431 hir::ExprMethodCall(_, _, ref args) => {
432 for arg_exp in args {
433 walk_expr(cx, &**arg_exp, scope_stack, scope_map);
437 hir::ExprMatch(ref discriminant_exp, ref arms, _) => {
438 walk_expr(cx, &**discriminant_exp, scope_stack, scope_map);
440 // For each arm we have to first walk the pattern as these might
441 // introduce new artificial scopes. It should be sufficient to
442 // walk only one pattern per arm, as they all must contain the
443 // same binding names.
445 for arm_ref in arms {
446 let arm_span = arm_ref.pats[0].span;
452 |cx, scope_stack, scope_map| {
453 for pat in &arm_ref.pats {
454 walk_pattern(cx, &**pat, scope_stack, scope_map);
457 if let Some(ref guard_exp) = arm_ref.guard {
458 walk_expr(cx, &**guard_exp, scope_stack, scope_map)
461 walk_expr(cx, &*arm_ref.body, scope_stack, scope_map);
466 hir::ExprStruct(_, ref fields, ref base_exp) => {
467 for &hir::Field { expr: ref exp, .. } in fields {
468 walk_expr(cx, &**exp, scope_stack, scope_map);
472 Some(ref exp) => walk_expr(cx, &**exp, scope_stack, scope_map),
477 hir::ExprInlineAsm(hir::InlineAsm { ref inputs,
480 // inputs, outputs: Vec<(String, P<Expr>)>
481 for &(_, ref exp) in inputs {
482 walk_expr(cx, &**exp, scope_stack, scope_map);
485 for &(_, ref exp, _) in outputs {
486 walk_expr(cx, &**exp, scope_stack, scope_map);