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}
;
25 use rustc_front
::hir
::{self, PatKind}
;
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 PatKind
::Ident(_
, 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 PatKind
::TupleStruct(_
, 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 PatKind
::Path(..) | PatKind
::QPath(..) => {
253 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
256 PatKind
::Struct(_
, 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 PatKind
::Tup(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 PatKind
::Box(ref sub_pat
) | PatKind
::Ref(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 PatKind
::Lit(ref exp
) => {
281 scope_map
.insert(pat
.id
, scope_stack
.last().unwrap().scope_metadata
);
282 walk_expr(cx
, &exp
, scope_stack
, scope_map
);
285 PatKind
::Range(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 PatKind
::Vec(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
::ExprType(ref sub_exp
, _
) |
324 hir
::ExprAddrOf(_
, ref sub_exp
) |
325 hir
::ExprField(ref sub_exp
, _
) |
326 hir
::ExprTupField(ref sub_exp
, _
) =>
327 walk_expr(cx
, &sub_exp
, scope_stack
, scope_map
),
329 hir
::ExprBox(ref sub_expr
) => {
330 walk_expr(cx
, &sub_expr
, scope_stack
, scope_map
);
333 hir
::ExprRet(ref exp_opt
) => match *exp_opt
{
334 Some(ref sub_exp
) => walk_expr(cx
, &sub_exp
, scope_stack
, scope_map
),
338 hir
::ExprUnary(_
, ref sub_exp
) => {
339 walk_expr(cx
, &sub_exp
, scope_stack
, scope_map
);
342 hir
::ExprAssignOp(_
, ref lhs
, ref rhs
) |
343 hir
::ExprIndex(ref lhs
, ref rhs
) |
344 hir
::ExprBinary(_
, ref lhs
, ref rhs
) => {
345 walk_expr(cx
, &lhs
, scope_stack
, scope_map
);
346 walk_expr(cx
, &rhs
, scope_stack
, scope_map
);
349 hir
::ExprRange(ref start
, ref end
) => {
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
));
354 hir
::ExprVec(ref init_expressions
) |
355 hir
::ExprTup(ref init_expressions
) => {
356 for ie
in init_expressions
{
357 walk_expr(cx
, &ie
, scope_stack
, scope_map
);
361 hir
::ExprAssign(ref sub_exp1
, ref sub_exp2
) |
362 hir
::ExprRepeat(ref sub_exp1
, ref sub_exp2
) => {
363 walk_expr(cx
, &sub_exp1
, scope_stack
, scope_map
);
364 walk_expr(cx
, &sub_exp2
, scope_stack
, scope_map
);
367 hir
::ExprIf(ref cond_exp
, ref then_block
, ref opt_else_exp
) => {
368 walk_expr(cx
, &cond_exp
, scope_stack
, scope_map
);
374 |cx
, scope_stack
, scope_map
| {
375 walk_block(cx
, &then_block
, scope_stack
, scope_map
);
378 match *opt_else_exp
{
379 Some(ref else_exp
) =>
380 walk_expr(cx
, &else_exp
, scope_stack
, scope_map
),
385 hir
::ExprWhile(ref cond_exp
, ref loop_body
, _
) => {
386 walk_expr(cx
, &cond_exp
, scope_stack
, scope_map
);
392 |cx
, scope_stack
, scope_map
| {
393 walk_block(cx
, &loop_body
, scope_stack
, scope_map
);
397 hir
::ExprLoop(ref block
, _
) |
398 hir
::ExprBlock(ref block
) => {
403 |cx
, scope_stack
, scope_map
| {
404 walk_block(cx
, &block
, scope_stack
, scope_map
);
408 hir
::ExprClosure(_
, ref decl
, ref block
) => {
413 |cx
, scope_stack
, scope_map
| {
414 for &hir
::Arg { pat: ref pattern, .. }
in &decl
.inputs
{
415 walk_pattern(cx
, &pattern
, scope_stack
, scope_map
);
418 walk_block(cx
, &block
, scope_stack
, scope_map
);
422 hir
::ExprCall(ref fn_exp
, ref args
) => {
423 walk_expr(cx
, &fn_exp
, scope_stack
, scope_map
);
425 for arg_exp
in args
{
426 walk_expr(cx
, &arg_exp
, scope_stack
, scope_map
);
430 hir
::ExprMethodCall(_
, _
, ref args
) => {
431 for arg_exp
in args
{
432 walk_expr(cx
, &arg_exp
, scope_stack
, scope_map
);
436 hir
::ExprMatch(ref discriminant_exp
, ref arms
, _
) => {
437 walk_expr(cx
, &discriminant_exp
, scope_stack
, scope_map
);
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.
444 for arm_ref
in arms
{
445 let arm_span
= arm_ref
.pats
[0].span
;
451 |cx
, scope_stack
, scope_map
| {
452 for pat
in &arm_ref
.pats
{
453 walk_pattern(cx
, &pat
, scope_stack
, scope_map
);
456 if let Some(ref guard_exp
) = arm_ref
.guard
{
457 walk_expr(cx
, &guard_exp
, scope_stack
, scope_map
)
460 walk_expr(cx
, &arm_ref
.body
, scope_stack
, scope_map
);
465 hir
::ExprStruct(_
, ref fields
, ref base_exp
) => {
466 for &hir
::Field { expr: ref exp, .. }
in fields
{
467 walk_expr(cx
, &exp
, scope_stack
, scope_map
);
471 Some(ref exp
) => walk_expr(cx
, &exp
, scope_stack
, scope_map
),
476 hir
::ExprInlineAsm(hir
::InlineAsm
{ ref inputs
,
479 // inputs, outputs: Vec<(String, P<Expr>)>
480 for &(_
, ref exp
) in inputs
{
481 walk_expr(cx
, &exp
, scope_stack
, scope_map
);
485 walk_expr(cx
, &out
.expr
, scope_stack
, scope_map
);