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 common
::CrateContext
;
17 use rustc
::hir
::pat_util
;
18 use rustc
::util
::nodemap
::NodeMap
;
21 use syntax
::codemap
::{Span, Pos}
;
22 use syntax
::{ast, codemap}
;
24 use rustc
::hir
::{self, PatKind}
;
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.
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
,
35 fn_entry_block
: &hir
::Block
,
36 fn_metadata
: DISubprogram
,
37 fn_ast_id
: ast
::NodeId
)
39 let mut scope_map
= NodeMap();
41 let def_map
= &cx
.tcx().def_map
;
43 let mut scope_stack
= vec
!(ScopeStackEntry { scope_metadata: fn_metadata, name: None }
);
44 scope_map
.insert(fn_ast_id
, fn_metadata
);
46 // Push argument identifiers onto the stack so arguments integrate nicely
47 // with variable shadowing.
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
);
56 // Clang creates a separate scope for function bodies, so let's do this too.
61 |cx
, scope_stack
, scope_map
| {
62 walk_block(cx
, fn_entry_block
, scope_stack
, scope_map
);
68 // local helper functions for walking the AST.
69 fn with_new_scope
<F
>(cx
: &CrateContext
,
71 scope_stack
: &mut Vec
<ScopeStackEntry
> ,
72 scope_map
: &mut NodeMap
<DIScope
>,
74 F
: FnOnce(&CrateContext
, &mut Vec
<ScopeStackEntry
>, &mut NodeMap
<DIScope
>),
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
;
81 let scope_metadata
= unsafe {
82 llvm
::LLVMDIBuilderCreateLexicalBlock(
87 loc
.col
.to_usize() as c_uint
)
90 scope_stack
.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None }
);
92 inner_walk(cx
, scope_stack
, scope_map
);
94 // pop artificial scopes
95 while scope_stack
.last().unwrap().name
.is_some() {
99 if scope_stack
.last().unwrap().scope_metadata
!= scope_metadata
{
100 span_bug
!(scope_span
, "debuginfo: Inconsistency in scope management.");
106 struct ScopeStackEntry
{
107 scope_metadata
: DIScope
,
108 name
: Option
<ast
::Name
>
111 fn walk_block(cx
: &CrateContext
,
113 scope_stack
: &mut Vec
<ScopeStackEntry
> ,
114 scope_map
: &mut NodeMap
<DIScope
>) {
115 scope_map
.insert(block
.id
, scope_stack
.last().unwrap().scope_metadata
);
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
);
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
),
131 if let Some(ref exp
) = block
.expr
{
132 walk_expr(cx
, &exp
, scope_stack
, scope_map
);
136 fn walk_decl(cx
: &CrateContext
,
138 scope_stack
: &mut Vec
<ScopeStackEntry
> ,
139 scope_map
: &mut NodeMap
<DIScope
>) {
141 codemap
::Spanned { node: hir::DeclLocal(ref local), .. }
=> {
142 scope_map
.insert(local
.id
, scope_stack
.last().unwrap().scope_metadata
);
144 walk_pattern(cx
, &local
.pat
, scope_stack
, scope_map
);
146 if let Some(ref exp
) = local
.init
{
147 walk_expr(cx
, &exp
, scope_stack
, scope_map
);
154 fn walk_pattern(cx
: &CrateContext
,
156 scope_stack
: &mut Vec
<ScopeStackEntry
> ,
157 scope_map
: &mut NodeMap
<DIScope
>) {
159 let def_map
= &cx
.tcx().def_map
;
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.
165 PatKind
::Ident(_
, ref path1
, ref sub_pat_opt
) => {
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
) {
171 let name
= path1
.node
.unhygienic_name
;
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.
178 // Otherwise the following error occurs:
182 // do_something(); // 'gdb print x' correctly prints 10
185 // do_something(); // 'gdb print x' prints 0, because it
186 // // already reads the uninitialized 'x'
187 // // from the next line...
189 // do_something(); // 'gdb print x' correctly prints 100
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
198 .any(|entry
| entry
.name
== Some(name
));
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
;
206 let scope_metadata
= unsafe {
207 llvm
::LLVMDIBuilderCreateLexicalBlock(
212 loc
.col
.to_usize() as c_uint
)
215 scope_stack
.push(ScopeStackEntry
{
216 scope_metadata
: scope_metadata
,
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
,
230 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
232 if let Some(ref sub_pat
) = *sub_pat_opt
{
233 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
238 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
241 PatKind
::TupleStruct(_
, ref sub_pats_opt
) => {
242 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
244 if let Some(ref sub_pats
) = *sub_pats_opt
{
246 walk_pattern(cx
, &p
, scope_stack
, scope_map
);
251 PatKind
::Path(..) | PatKind
::QPath(..) => {
252 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
255 PatKind
::Struct(_
, ref field_pats
, _
) => {
256 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
258 for &codemap
::Spanned
{
259 node
: hir
::FieldPat { pat: ref sub_pat, .. }
,
262 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
266 PatKind
::Tup(ref sub_pats
) => {
267 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
269 for sub_pat
in sub_pats
{
270 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
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
);
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
);
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
);
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
);
293 for sub_pat
in front_sub_pats
{
294 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
297 if let Some(ref sub_pat
) = *middle_sub_pats
{
298 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
301 for sub_pat
in back_sub_pats
{
302 walk_pattern(cx
, &sub_pat
, scope_stack
, scope_map
);
308 fn walk_expr(cx
: &CrateContext
,
310 scope_stack
: &mut Vec
<ScopeStackEntry
> ,
311 scope_map
: &mut NodeMap
<DIScope
>) {
313 scope_map
.insert(exp
.id
, scope_stack
.last().unwrap().scope_metadata
);
319 hir
::ExprPath(..) => {}
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
),
328 hir
::ExprBox(ref sub_expr
) => {
329 walk_expr(cx
, &sub_expr
, scope_stack
, scope_map
);
332 hir
::ExprRet(ref exp_opt
) => match *exp_opt
{
333 Some(ref sub_exp
) => walk_expr(cx
, &sub_exp
, scope_stack
, scope_map
),
337 hir
::ExprUnary(_
, ref sub_exp
) => {
338 walk_expr(cx
, &sub_exp
, scope_stack
, scope_map
);
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
);
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
);
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
);
361 hir
::ExprIf(ref cond_exp
, ref then_block
, ref opt_else_exp
) => {
362 walk_expr(cx
, &cond_exp
, scope_stack
, scope_map
);
368 |cx
, scope_stack
, scope_map
| {
369 walk_block(cx
, &then_block
, scope_stack
, scope_map
);
372 match *opt_else_exp
{
373 Some(ref else_exp
) =>
374 walk_expr(cx
, &else_exp
, scope_stack
, scope_map
),
379 hir
::ExprWhile(ref cond_exp
, ref loop_body
, _
) => {
380 walk_expr(cx
, &cond_exp
, scope_stack
, scope_map
);
386 |cx
, scope_stack
, scope_map
| {
387 walk_block(cx
, &loop_body
, scope_stack
, scope_map
);
391 hir
::ExprLoop(ref block
, _
) |
392 hir
::ExprBlock(ref block
) => {
397 |cx
, scope_stack
, scope_map
| {
398 walk_block(cx
, &block
, scope_stack
, scope_map
);
402 hir
::ExprClosure(_
, ref decl
, ref block
) => {
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
);
412 walk_block(cx
, &block
, scope_stack
, scope_map
);
416 hir
::ExprCall(ref fn_exp
, ref args
) => {
417 walk_expr(cx
, &fn_exp
, scope_stack
, scope_map
);
419 for arg_exp
in args
{
420 walk_expr(cx
, &arg_exp
, scope_stack
, scope_map
);
424 hir
::ExprMethodCall(_
, _
, ref args
) => {
425 for arg_exp
in args
{
426 walk_expr(cx
, &arg_exp
, scope_stack
, scope_map
);
430 hir
::ExprMatch(ref discriminant_exp
, ref arms
, _
) => {
431 walk_expr(cx
, &discriminant_exp
, scope_stack
, scope_map
);
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.
438 for arm_ref
in arms
{
439 let arm_span
= arm_ref
.pats
[0].span
;
445 |cx
, scope_stack
, scope_map
| {
446 for pat
in &arm_ref
.pats
{
447 walk_pattern(cx
, &pat
, scope_stack
, scope_map
);
450 if let Some(ref guard_exp
) = arm_ref
.guard
{
451 walk_expr(cx
, &guard_exp
, scope_stack
, scope_map
)
454 walk_expr(cx
, &arm_ref
.body
, scope_stack
, scope_map
);
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
);
465 Some(ref exp
) => walk_expr(cx
, &exp
, scope_stack
, scope_map
),
470 hir
::ExprInlineAsm(_
, ref outputs
, ref inputs
) => {
471 for output
in outputs
{
472 walk_expr(cx
, output
, scope_stack
, scope_map
);
475 for input
in inputs
{
476 walk_expr(cx
, input
, scope_stack
, scope_map
);