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_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
);
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
.borrow(), &*pat
) {
172 let name
= path1
.node
.unhygienic_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 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
::ExprRange(ref start
, ref end
) => {
349 start
.as_ref().map(|e
| walk_expr(cx
, &**e
, scope_stack
, scope_map
));
350 end
.as_ref().map(|e
| walk_expr(cx
, &**e
, scope_stack
, scope_map
));
353 hir
::ExprVec(ref init_expressions
) |
354 hir
::ExprTup(ref init_expressions
) => {
355 for ie
in init_expressions
{
356 walk_expr(cx
, &**ie
, scope_stack
, scope_map
);
360 hir
::ExprAssign(ref sub_exp1
, ref sub_exp2
) |
361 hir
::ExprRepeat(ref sub_exp1
, ref sub_exp2
) => {
362 walk_expr(cx
, &**sub_exp1
, scope_stack
, scope_map
);
363 walk_expr(cx
, &**sub_exp2
, scope_stack
, scope_map
);
366 hir
::ExprIf(ref cond_exp
, ref then_block
, ref opt_else_exp
) => {
367 walk_expr(cx
, &**cond_exp
, scope_stack
, scope_map
);
373 |cx
, scope_stack
, scope_map
| {
374 walk_block(cx
, &**then_block
, scope_stack
, scope_map
);
377 match *opt_else_exp
{
378 Some(ref else_exp
) =>
379 walk_expr(cx
, &**else_exp
, scope_stack
, scope_map
),
384 hir
::ExprWhile(ref cond_exp
, ref loop_body
, _
) => {
385 walk_expr(cx
, &**cond_exp
, scope_stack
, scope_map
);
391 |cx
, scope_stack
, scope_map
| {
392 walk_block(cx
, &**loop_body
, scope_stack
, scope_map
);
396 hir
::ExprLoop(ref block
, _
) |
397 hir
::ExprBlock(ref block
) => {
402 |cx
, scope_stack
, scope_map
| {
403 walk_block(cx
, &**block
, scope_stack
, scope_map
);
407 hir
::ExprClosure(_
, ref decl
, ref block
) => {
412 |cx
, scope_stack
, scope_map
| {
413 for &hir
::Arg { pat: ref pattern, .. }
in &decl
.inputs
{
414 walk_pattern(cx
, &**pattern
, scope_stack
, scope_map
);
417 walk_block(cx
, &**block
, scope_stack
, scope_map
);
421 hir
::ExprCall(ref fn_exp
, ref args
) => {
422 walk_expr(cx
, &**fn_exp
, scope_stack
, scope_map
);
424 for arg_exp
in args
{
425 walk_expr(cx
, &**arg_exp
, scope_stack
, scope_map
);
429 hir
::ExprMethodCall(_
, _
, ref args
) => {
430 for arg_exp
in args
{
431 walk_expr(cx
, &**arg_exp
, scope_stack
, scope_map
);
435 hir
::ExprMatch(ref discriminant_exp
, ref arms
, _
) => {
436 walk_expr(cx
, &**discriminant_exp
, scope_stack
, scope_map
);
438 // For each arm we have to first walk the pattern as these might
439 // introduce new artificial scopes. It should be sufficient to
440 // walk only one pattern per arm, as they all must contain the
441 // same binding names.
443 for arm_ref
in arms
{
444 let arm_span
= arm_ref
.pats
[0].span
;
450 |cx
, scope_stack
, scope_map
| {
451 for pat
in &arm_ref
.pats
{
452 walk_pattern(cx
, &**pat
, scope_stack
, scope_map
);
455 if let Some(ref guard_exp
) = arm_ref
.guard
{
456 walk_expr(cx
, &**guard_exp
, scope_stack
, scope_map
)
459 walk_expr(cx
, &*arm_ref
.body
, scope_stack
, scope_map
);
464 hir
::ExprStruct(_
, ref fields
, ref base_exp
) => {
465 for &hir
::Field { expr: ref exp, .. }
in fields
{
466 walk_expr(cx
, &**exp
, scope_stack
, scope_map
);
470 Some(ref exp
) => walk_expr(cx
, &**exp
, scope_stack
, scope_map
),
475 hir
::ExprInlineAsm(hir
::InlineAsm
{ ref inputs
,
478 // inputs, outputs: Vec<(String, P<Expr>)>
479 for &(_
, ref exp
) in inputs
{
480 walk_expr(cx
, &**exp
, scope_stack
, scope_map
);
483 for &(_
, ref exp
, _
) in outputs
{
484 walk_expr(cx
, &**exp
, scope_stack
, scope_map
);