]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: extract utils.rs
authorNick Cameron <ncameron@mozilla.com>
Fri, 24 Apr 2015 03:36:43 +0000 (15:36 +1200)
committerNick Cameron <ncameron@mozilla.com>
Wed, 29 Apr 2015 05:26:22 +0000 (17:26 +1200)
src/librustc_trans/trans/debuginfo/mod.rs
src/librustc_trans/trans/debuginfo/utils.rs [new file with mode: 0644]

index e3b7ffb3f397a91752dfd1272ebf06bf819e7d1a..306bed6785a2c373cf436c4518ce3b705feef743 100644 (file)
 mod doc;
 
 pub mod gdb;
+mod utils;
+
+use self::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align_of,
+                  assert_type_for_node_id, get_namespace_and_span_for_item, fn_should_be_ignored,
+                  contains_nodebug_attribute, create_scope_map};
 
 use self::VariableAccess::*;
 use self::VariableKind::*;
@@ -2978,569 +2983,6 @@ fn set_debug_location(cx: &CrateContext, debug_location: InternalDebugLocation)
     debug_context(cx).current_debug_location.set(debug_location);
 }
 
-//=-----------------------------------------------------------------------------
-//  Utility Functions
-//=-----------------------------------------------------------------------------
-
-fn contains_nodebug_attribute(attributes: &[ast::Attribute]) -> bool {
-    attributes.iter().any(|attr| {
-        let meta_item: &ast::MetaItem = &*attr.node.value;
-        match meta_item.node {
-            ast::MetaWord(ref value) => &value[..] == "no_debug",
-            _ => false
-        }
-    })
-}
-
-/// Return codemap::Loc corresponding to the beginning of the span
-fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
-    cx.sess().codemap().lookup_char_pos(span.lo)
-}
-
-fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
-    (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type) as u64)
-}
-
-fn bytes_to_bits(bytes: u64) -> u64 {
-    bytes * 8
-}
-
-#[inline]
-fn debug_context<'a, 'tcx>(cx: &'a CrateContext<'a, 'tcx>)
-                           -> &'a CrateDebugContext<'tcx> {
-    let debug_context: &'a CrateDebugContext<'tcx> = cx.dbg_cx().as_ref().unwrap();
-    debug_context
-}
-
-#[inline]
-#[allow(non_snake_case)]
-fn DIB(cx: &CrateContext) -> DIBuilderRef {
-    cx.dbg_cx().as_ref().unwrap().builder
-}
-
-fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
-    match fcx.debug_context {
-        FunctionDebugContext::RegularContext(_) => false,
-        _ => true
-    }
-}
-
-fn assert_type_for_node_id(cx: &CrateContext,
-                           node_id: ast::NodeId,
-                           error_reporting_span: Span) {
-    if !cx.tcx().node_types().contains_key(&node_id) {
-        cx.sess().span_bug(error_reporting_span,
-                           "debuginfo: Could not find type for node id!");
-    }
-}
-
-fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: ast::DefId)
-                                   -> (DIScope, Span) {
-    let containing_scope = namespace_for_item(cx, def_id).scope;
-    let definition_span = if def_id.krate == ast::LOCAL_CRATE {
-        cx.tcx().map.span(def_id.node)
-    } else {
-        // For external items there is no span information
-        codemap::DUMMY_SP
-    };
-
-    (containing_scope, definition_span)
-}
-
-// This procedure builds the *scope map* for a given function, which maps any
-// given ast::NodeId in the function's AST to the correct DIScope metadata instance.
-//
-// This builder procedure walks the AST in execution order and keeps track of
-// what belongs to which scope, creating DIScope DIEs along the way, and
-// introducing *artificial* lexical scope descriptors where necessary. These
-// artificial scopes allow GDB to correctly handle name shadowing.
-fn create_scope_map(cx: &CrateContext,
-                    args: &[ast::Arg],
-                    fn_entry_block: &ast::Block,
-                    fn_metadata: DISubprogram,
-                    fn_ast_id: ast::NodeId)
-                 -> NodeMap<DIScope> {
-    let mut scope_map = NodeMap();
-
-    let def_map = &cx.tcx().def_map;
-
-    struct ScopeStackEntry {
-        scope_metadata: DIScope,
-        name: Option<ast::Name>
-    }
-
-    let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
-    scope_map.insert(fn_ast_id, fn_metadata);
-
-    // Push argument identifiers onto the stack so arguments integrate nicely
-    // with variable shadowing.
-    for arg in args {
-        pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
-            scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
-                                               name: Some(path1.node.name) });
-            scope_map.insert(node_id, fn_metadata);
-        })
-    }
-
-    // Clang creates a separate scope for function bodies, so let's do this too.
-    with_new_scope(cx,
-                   fn_entry_block.span,
-                   &mut scope_stack,
-                   &mut scope_map,
-                   |cx, scope_stack, scope_map| {
-        walk_block(cx, fn_entry_block, scope_stack, scope_map);
-    });
-
-    return scope_map;
-
-
-    // local helper functions for walking the AST.
-    fn with_new_scope<F>(cx: &CrateContext,
-                         scope_span: Span,
-                         scope_stack: &mut Vec<ScopeStackEntry> ,
-                         scope_map: &mut NodeMap<DIScope>,
-                         inner_walk: F) where
-        F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
-    {
-        // Create a new lexical scope and push it onto the stack
-        let loc = cx.sess().codemap().lookup_char_pos(scope_span.lo);
-        let file_metadata = file_metadata(cx, &loc.file.name);
-        let parent_scope = scope_stack.last().unwrap().scope_metadata;
-
-        let scope_metadata = unsafe {
-            llvm::LLVMDIBuilderCreateLexicalBlock(
-                DIB(cx),
-                parent_scope,
-                file_metadata,
-                loc.line as c_uint,
-                loc.col.to_usize() as c_uint)
-        };
-
-        scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
-
-        inner_walk(cx, scope_stack, scope_map);
-
-        // pop artificial scopes
-        while scope_stack.last().unwrap().name.is_some() {
-            scope_stack.pop();
-        }
-
-        if scope_stack.last().unwrap().scope_metadata != scope_metadata {
-            cx.sess().span_bug(scope_span, "debuginfo: Inconsistency in scope management.");
-        }
-
-        scope_stack.pop();
-    }
-
-    fn walk_block(cx: &CrateContext,
-                  block: &ast::Block,
-                  scope_stack: &mut Vec<ScopeStackEntry> ,
-                  scope_map: &mut NodeMap<DIScope>) {
-        scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
-
-        // The interesting things here are statements and the concluding expression.
-        for statement in &block.stmts {
-            scope_map.insert(ast_util::stmt_id(&**statement),
-                             scope_stack.last().unwrap().scope_metadata);
-
-            match statement.node {
-                ast::StmtDecl(ref decl, _) =>
-                    walk_decl(cx, &**decl, scope_stack, scope_map),
-                ast::StmtExpr(ref exp, _) |
-                ast::StmtSemi(ref exp, _) =>
-                    walk_expr(cx, &**exp, scope_stack, scope_map),
-                ast::StmtMac(..) => () // Ignore macros (which should be expanded anyway).
-            }
-        }
-
-        if let Some(ref exp) = block.expr {
-            walk_expr(cx, &**exp, scope_stack, scope_map);
-        }
-    }
-
-    fn walk_decl(cx: &CrateContext,
-                 decl: &ast::Decl,
-                 scope_stack: &mut Vec<ScopeStackEntry> ,
-                 scope_map: &mut NodeMap<DIScope>) {
-        match *decl {
-            codemap::Spanned { node: ast::DeclLocal(ref local), .. } => {
-                scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
-
-                walk_pattern(cx, &*local.pat, scope_stack, scope_map);
-
-                if let Some(ref exp) = local.init {
-                    walk_expr(cx, &**exp, scope_stack, scope_map);
-                }
-            }
-            _ => ()
-        }
-    }
-
-    fn walk_pattern(cx: &CrateContext,
-                    pat: &ast::Pat,
-                    scope_stack: &mut Vec<ScopeStackEntry> ,
-                    scope_map: &mut NodeMap<DIScope>) {
-
-        let def_map = &cx.tcx().def_map;
-
-        // Unfortunately, we cannot just use pat_util::pat_bindings() or
-        // ast_util::walk_pat() here because we have to visit *all* nodes in
-        // order to put them into the scope map. The above functions don't do that.
-        match pat.node {
-            ast::PatIdent(_, ref path1, ref sub_pat_opt) => {
-
-                // Check if this is a binding. If so we need to put it on the
-                // scope stack and maybe introduce an artificial scope
-                if pat_util::pat_is_binding(def_map, &*pat) {
-
-                    let name = path1.node.name;
-
-                    // LLVM does not properly generate 'DW_AT_start_scope' fields
-                    // for variable DIEs. For this reason we have to introduce
-                    // an artificial scope at bindings whenever a variable with
-                    // the same name is declared in *any* parent scope.
-                    //
-                    // Otherwise the following error occurs:
-                    //
-                    // let x = 10;
-                    //
-                    // do_something(); // 'gdb print x' correctly prints 10
-                    //
-                    // {
-                    //     do_something(); // 'gdb print x' prints 0, because it
-                    //                     // already reads the uninitialized 'x'
-                    //                     // from the next line...
-                    //     let x = 100;
-                    //     do_something(); // 'gdb print x' correctly prints 100
-                    // }
-
-                    // Is there already a binding with that name?
-                    // N.B.: this comparison must be UNhygienic... because
-                    // gdb knows nothing about the context, so any two
-                    // variables with the same name will cause the problem.
-                    let need_new_scope = scope_stack
-                        .iter()
-                        .any(|entry| entry.name == Some(name));
-
-                    if need_new_scope {
-                        // Create a new lexical scope and push it onto the stack
-                        let loc = cx.sess().codemap().lookup_char_pos(pat.span.lo);
-                        let file_metadata = file_metadata(cx, &loc.file.name);
-                        let parent_scope = scope_stack.last().unwrap().scope_metadata;
-
-                        let scope_metadata = unsafe {
-                            llvm::LLVMDIBuilderCreateLexicalBlock(
-                                DIB(cx),
-                                parent_scope,
-                                file_metadata,
-                                loc.line as c_uint,
-                                loc.col.to_usize() as c_uint)
-                        };
-
-                        scope_stack.push(ScopeStackEntry {
-                            scope_metadata: scope_metadata,
-                            name: Some(name)
-                        });
-
-                    } else {
-                        // Push a new entry anyway so the name can be found
-                        let prev_metadata = scope_stack.last().unwrap().scope_metadata;
-                        scope_stack.push(ScopeStackEntry {
-                            scope_metadata: prev_metadata,
-                            name: Some(name)
-                        });
-                    }
-                }
-
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-                if let Some(ref sub_pat) = *sub_pat_opt {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-            }
-
-            ast::PatWild(_) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-            }
-
-            ast::PatEnum(_, ref sub_pats_opt) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-                if let Some(ref sub_pats) = *sub_pats_opt {
-                    for p in sub_pats {
-                        walk_pattern(cx, &**p, scope_stack, scope_map);
-                    }
-                }
-            }
-
-            ast::PatQPath(..) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-            }
-
-            ast::PatStruct(_, ref field_pats, _) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-                for &codemap::Spanned {
-                    node: ast::FieldPat { pat: ref sub_pat, .. },
-                    ..
-                } in field_pats.iter() {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-            }
-
-            ast::PatTup(ref sub_pats) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-                for sub_pat in sub_pats {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-            }
-
-            ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-                walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-            }
-
-            ast::PatLit(ref exp) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-                walk_expr(cx, &**exp, scope_stack, scope_map);
-            }
-
-            ast::PatRange(ref exp1, ref exp2) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-                walk_expr(cx, &**exp1, scope_stack, scope_map);
-                walk_expr(cx, &**exp2, scope_stack, scope_map);
-            }
-
-            ast::PatVec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
-                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-                for sub_pat in front_sub_pats {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-
-                if let Some(ref sub_pat) = *middle_sub_pats {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-
-                for sub_pat in back_sub_pats {
-                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
-                }
-            }
-
-            ast::PatMac(_) => {
-                cx.sess().span_bug(pat.span, "debuginfo::create_scope_map() - \
-                                              Found unexpanded macro.");
-            }
-        }
-    }
-
-    fn walk_expr(cx: &CrateContext,
-                 exp: &ast::Expr,
-                 scope_stack: &mut Vec<ScopeStackEntry> ,
-                 scope_map: &mut NodeMap<DIScope>) {
-
-        scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
-
-        match exp.node {
-            ast::ExprLit(_)   |
-            ast::ExprBreak(_) |
-            ast::ExprAgain(_) |
-            ast::ExprPath(..) => {}
-
-            ast::ExprCast(ref sub_exp, _)     |
-            ast::ExprAddrOf(_, ref sub_exp)  |
-            ast::ExprField(ref sub_exp, _) |
-            ast::ExprTupField(ref sub_exp, _) |
-            ast::ExprParen(ref sub_exp) =>
-                walk_expr(cx, &**sub_exp, scope_stack, scope_map),
-
-            ast::ExprBox(ref place, ref sub_expr) => {
-                place.as_ref().map(
-                    |e| walk_expr(cx, &**e, scope_stack, scope_map));
-                walk_expr(cx, &**sub_expr, scope_stack, scope_map);
-            }
-
-            ast::ExprRet(ref exp_opt) => match *exp_opt {
-                Some(ref sub_exp) => walk_expr(cx, &**sub_exp, scope_stack, scope_map),
-                None => ()
-            },
-
-            ast::ExprUnary(_, ref sub_exp) => {
-                walk_expr(cx, &**sub_exp, scope_stack, scope_map);
-            }
-
-            ast::ExprAssignOp(_, ref lhs, ref rhs) |
-            ast::ExprIndex(ref lhs, ref rhs) |
-            ast::ExprBinary(_, ref lhs, ref rhs)    => {
-                walk_expr(cx, &**lhs, scope_stack, scope_map);
-                walk_expr(cx, &**rhs, scope_stack, scope_map);
-            }
-
-            ast::ExprRange(ref start, ref end) => {
-                start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
-                end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
-            }
-
-            ast::ExprVec(ref init_expressions) |
-            ast::ExprTup(ref init_expressions) => {
-                for ie in init_expressions {
-                    walk_expr(cx, &**ie, scope_stack, scope_map);
-                }
-            }
-
-            ast::ExprAssign(ref sub_exp1, ref sub_exp2) |
-            ast::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
-                walk_expr(cx, &**sub_exp1, scope_stack, scope_map);
-                walk_expr(cx, &**sub_exp2, scope_stack, scope_map);
-            }
-
-            ast::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
-                walk_expr(cx, &**cond_exp, scope_stack, scope_map);
-
-                with_new_scope(cx,
-                               then_block.span,
-                               scope_stack,
-                               scope_map,
-                               |cx, scope_stack, scope_map| {
-                    walk_block(cx, &**then_block, scope_stack, scope_map);
-                });
-
-                match *opt_else_exp {
-                    Some(ref else_exp) =>
-                        walk_expr(cx, &**else_exp, scope_stack, scope_map),
-                    _ => ()
-                }
-            }
-
-            ast::ExprIfLet(..) => {
-                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
-                                              Found unexpanded if-let.");
-            }
-
-            ast::ExprWhile(ref cond_exp, ref loop_body, _) => {
-                walk_expr(cx, &**cond_exp, scope_stack, scope_map);
-
-                with_new_scope(cx,
-                               loop_body.span,
-                               scope_stack,
-                               scope_map,
-                               |cx, scope_stack, scope_map| {
-                    walk_block(cx, &**loop_body, scope_stack, scope_map);
-                })
-            }
-
-            ast::ExprWhileLet(..) => {
-                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
-                                              Found unexpanded while-let.");
-            }
-
-            ast::ExprForLoop(..) => {
-                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
-                                              Found unexpanded for loop.");
-            }
-
-            ast::ExprMac(_) => {
-                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
-                                              Found unexpanded macro.");
-            }
-
-            ast::ExprLoop(ref block, _) |
-            ast::ExprBlock(ref block)   => {
-                with_new_scope(cx,
-                               block.span,
-                               scope_stack,
-                               scope_map,
-                               |cx, scope_stack, scope_map| {
-                    walk_block(cx, &**block, scope_stack, scope_map);
-                })
-            }
-
-            ast::ExprClosure(_, ref decl, ref block) => {
-                with_new_scope(cx,
-                               block.span,
-                               scope_stack,
-                               scope_map,
-                               |cx, scope_stack, scope_map| {
-                    for &ast::Arg { pat: ref pattern, .. } in &decl.inputs {
-                        walk_pattern(cx, &**pattern, scope_stack, scope_map);
-                    }
-
-                    walk_block(cx, &**block, scope_stack, scope_map);
-                })
-            }
-
-            ast::ExprCall(ref fn_exp, ref args) => {
-                walk_expr(cx, &**fn_exp, scope_stack, scope_map);
-
-                for arg_exp in args {
-                    walk_expr(cx, &**arg_exp, scope_stack, scope_map);
-                }
-            }
-
-            ast::ExprMethodCall(_, _, ref args) => {
-                for arg_exp in args {
-                    walk_expr(cx, &**arg_exp, scope_stack, scope_map);
-                }
-            }
-
-            ast::ExprMatch(ref discriminant_exp, ref arms, _) => {
-                walk_expr(cx, &**discriminant_exp, scope_stack, scope_map);
-
-                // For each arm we have to first walk the pattern as these might
-                // introduce new artificial scopes. It should be sufficient to
-                // walk only one pattern per arm, as they all must contain the
-                // same binding names.
-
-                for arm_ref in arms {
-                    let arm_span = arm_ref.pats[0].span;
-
-                    with_new_scope(cx,
-                                   arm_span,
-                                   scope_stack,
-                                   scope_map,
-                                   |cx, scope_stack, scope_map| {
-                        for pat in &arm_ref.pats {
-                            walk_pattern(cx, &**pat, scope_stack, scope_map);
-                        }
-
-                        if let Some(ref guard_exp) = arm_ref.guard {
-                            walk_expr(cx, &**guard_exp, scope_stack, scope_map)
-                        }
-
-                        walk_expr(cx, &*arm_ref.body, scope_stack, scope_map);
-                    })
-                }
-            }
-
-            ast::ExprStruct(_, ref fields, ref base_exp) => {
-                for &ast::Field { expr: ref exp, .. } in fields {
-                    walk_expr(cx, &**exp, scope_stack, scope_map);
-                }
-
-                match *base_exp {
-                    Some(ref exp) => walk_expr(cx, &**exp, scope_stack, scope_map),
-                    None => ()
-                }
-            }
-
-            ast::ExprInlineAsm(ast::InlineAsm { ref inputs,
-                                                ref outputs,
-                                                .. }) => {
-                // inputs, outputs: Vec<(String, P<Expr>)>
-                for &(_, ref exp) in inputs {
-                    walk_expr(cx, &**exp, scope_stack, scope_map);
-                }
-
-                for &(_, ref exp, _) in outputs {
-                    walk_expr(cx, &**exp, scope_stack, scope_map);
-                }
-            }
-        }
-    }
-}
-
-
 //=-----------------------------------------------------------------------------
 // Type Names for Debug Info
 //=-----------------------------------------------------------------------------
diff --git a/src/librustc_trans/trans/debuginfo/utils.rs b/src/librustc_trans/trans/debuginfo/utils.rs
new file mode 100644 (file)
index 0000000..1611282
--- /dev/null
@@ -0,0 +1,584 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://!rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://!www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://!opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Utility Functions.
+
+use super::{FunctionDebugContext, CrateDebugContext, namespace_for_item, file_metadata};
+
+use llvm;
+use llvm::debuginfo::{DIScope, DISubprogram, DIBuilderRef};
+use trans::machine;
+use trans::common::{CrateContext, FunctionContext};
+use trans::type_::Type;
+use middle::pat_util;
+use util::nodemap::NodeMap;
+
+use libc::c_uint;
+use syntax::codemap::{Span, Pos};
+use syntax::{ast, codemap, ast_util};
+
+
+pub fn contains_nodebug_attribute(attributes: &[ast::Attribute]) -> bool {
+    attributes.iter().any(|attr| {
+        let meta_item: &ast::MetaItem = &*attr.node.value;
+        match meta_item.node {
+            ast::MetaWord(ref value) => &value[..] == "no_debug",
+            _ => false
+        }
+    })
+}
+
+/// Return codemap::Loc corresponding to the beginning of the span
+pub fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
+    cx.sess().codemap().lookup_char_pos(span.lo)
+}
+
+pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
+    (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type) as u64)
+}
+
+pub fn bytes_to_bits(bytes: u64) -> u64 {
+    bytes * 8
+}
+
+#[inline]
+pub fn debug_context<'a, 'tcx>(cx: &'a CrateContext<'a, 'tcx>)
+                           -> &'a CrateDebugContext<'tcx> {
+    let debug_context: &'a CrateDebugContext<'tcx> = cx.dbg_cx().as_ref().unwrap();
+    debug_context
+}
+
+#[inline]
+#[allow(non_snake_case)]
+pub fn DIB(cx: &CrateContext) -> DIBuilderRef {
+    cx.dbg_cx().as_ref().unwrap().builder
+}
+
+pub fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
+    match fcx.debug_context {
+        FunctionDebugContext::RegularContext(_) => false,
+        _ => true
+    }
+}
+
+pub fn assert_type_for_node_id(cx: &CrateContext,
+                           node_id: ast::NodeId,
+                           error_reporting_span: Span) {
+    if !cx.tcx().node_types().contains_key(&node_id) {
+        cx.sess().span_bug(error_reporting_span,
+                           "debuginfo: Could not find type for node id!");
+    }
+}
+
+pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: ast::DefId)
+                                   -> (DIScope, Span) {
+    let containing_scope = namespace_for_item(cx, def_id).scope;
+    let definition_span = if def_id.krate == ast::LOCAL_CRATE {
+        cx.tcx().map.span(def_id.node)
+    } else {
+        // For external items there is no span information
+        codemap::DUMMY_SP
+    };
+
+    (containing_scope, definition_span)
+}
+
+// This procedure builds the *scope map* for a given function, which maps any
+// given ast::NodeId in the function's AST to the correct DIScope metadata instance.
+//
+// This builder procedure walks the AST in execution order and keeps track of
+// what belongs to which scope, creating DIScope DIEs along the way, and
+// introducing *artificial* lexical scope descriptors where necessary. These
+// artificial scopes allow GDB to correctly handle name shadowing.
+pub fn create_scope_map(cx: &CrateContext,
+                        args: &[ast::Arg],
+                        fn_entry_block: &ast::Block,
+                        fn_metadata: DISubprogram,
+                        fn_ast_id: ast::NodeId)
+                        -> NodeMap<DIScope> {
+    let mut scope_map = NodeMap();
+
+    let def_map = &cx.tcx().def_map;
+
+    struct ScopeStackEntry {
+        scope_metadata: DIScope,
+        name: Option<ast::Name>
+    }
+
+    let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
+    scope_map.insert(fn_ast_id, fn_metadata);
+
+    // Push argument identifiers onto the stack so arguments integrate nicely
+    // with variable shadowing.
+    for arg in args {
+        pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
+            scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
+                                               name: Some(path1.node.name) });
+            scope_map.insert(node_id, fn_metadata);
+        })
+    }
+
+    // Clang creates a separate scope for function bodies, so let's do this too.
+    with_new_scope(cx,
+                   fn_entry_block.span,
+                   &mut scope_stack,
+                   &mut scope_map,
+                   |cx, scope_stack, scope_map| {
+        walk_block(cx, fn_entry_block, scope_stack, scope_map);
+    });
+
+    return scope_map;
+
+
+    // local helper functions for walking the AST.
+    fn with_new_scope<F>(cx: &CrateContext,
+                         scope_span: Span,
+                         scope_stack: &mut Vec<ScopeStackEntry> ,
+                         scope_map: &mut NodeMap<DIScope>,
+                         inner_walk: F) where
+        F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
+    {
+        // Create a new lexical scope and push it onto the stack
+        let loc = cx.sess().codemap().lookup_char_pos(scope_span.lo);
+        let file_metadata = file_metadata(cx, &loc.file.name);
+        let parent_scope = scope_stack.last().unwrap().scope_metadata;
+
+        let scope_metadata = unsafe {
+            llvm::LLVMDIBuilderCreateLexicalBlock(
+                DIB(cx),
+                parent_scope,
+                file_metadata,
+                loc.line as c_uint,
+                loc.col.to_usize() as c_uint)
+        };
+
+        scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
+
+        inner_walk(cx, scope_stack, scope_map);
+
+        // pop artificial scopes
+        while scope_stack.last().unwrap().name.is_some() {
+            scope_stack.pop();
+        }
+
+        if scope_stack.last().unwrap().scope_metadata != scope_metadata {
+            cx.sess().span_bug(scope_span, "debuginfo: Inconsistency in scope management.");
+        }
+
+        scope_stack.pop();
+    }
+
+    fn walk_block(cx: &CrateContext,
+                  block: &ast::Block,
+                  scope_stack: &mut Vec<ScopeStackEntry> ,
+                  scope_map: &mut NodeMap<DIScope>) {
+        scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
+
+        // The interesting things here are statements and the concluding expression.
+        for statement in &block.stmts {
+            scope_map.insert(ast_util::stmt_id(&**statement),
+                             scope_stack.last().unwrap().scope_metadata);
+
+            match statement.node {
+                ast::StmtDecl(ref decl, _) =>
+                    walk_decl(cx, &**decl, scope_stack, scope_map),
+                ast::StmtExpr(ref exp, _) |
+                ast::StmtSemi(ref exp, _) =>
+                    walk_expr(cx, &**exp, scope_stack, scope_map),
+                ast::StmtMac(..) => () // Ignore macros (which should be expanded anyway).
+            }
+        }
+
+        if let Some(ref exp) = block.expr {
+            walk_expr(cx, &**exp, scope_stack, scope_map);
+        }
+    }
+
+    fn walk_decl(cx: &CrateContext,
+                 decl: &ast::Decl,
+                 scope_stack: &mut Vec<ScopeStackEntry> ,
+                 scope_map: &mut NodeMap<DIScope>) {
+        match *decl {
+            codemap::Spanned { node: ast::DeclLocal(ref local), .. } => {
+                scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
+
+                walk_pattern(cx, &*local.pat, scope_stack, scope_map);
+
+                if let Some(ref exp) = local.init {
+                    walk_expr(cx, &**exp, scope_stack, scope_map);
+                }
+            }
+            _ => ()
+        }
+    }
+
+    fn walk_pattern(cx: &CrateContext,
+                    pat: &ast::Pat,
+                    scope_stack: &mut Vec<ScopeStackEntry> ,
+                    scope_map: &mut NodeMap<DIScope>) {
+
+        let def_map = &cx.tcx().def_map;
+
+        // Unfortunately, we cannot just use pat_util::pat_bindings() or
+        // ast_util::walk_pat() here because we have to visit *all* nodes in
+        // order to put them into the scope map. The above functions don't do that.
+        match pat.node {
+            ast::PatIdent(_, ref path1, ref sub_pat_opt) => {
+
+                // Check if this is a binding. If so we need to put it on the
+                // scope stack and maybe introduce an artificial scope
+                if pat_util::pat_is_binding(def_map, &*pat) {
+
+                    let name = path1.node.name;
+
+                    // LLVM does not properly generate 'DW_AT_start_scope' fields
+                    // for variable DIEs. For this reason we have to introduce
+                    // an artificial scope at bindings whenever a variable with
+                    // the same name is declared in *any* parent scope.
+                    //
+                    // Otherwise the following error occurs:
+                    //
+                    // let x = 10;
+                    //
+                    // do_something(); // 'gdb print x' correctly prints 10
+                    //
+                    // {
+                    //     do_something(); // 'gdb print x' prints 0, because it
+                    //                     // already reads the uninitialized 'x'
+                    //                     // from the next line...
+                    //     let x = 100;
+                    //     do_something(); // 'gdb print x' correctly prints 100
+                    // }
+
+                    // Is there already a binding with that name?
+                    // N.B.: this comparison must be UNhygienic... because
+                    // gdb knows nothing about the context, so any two
+                    // variables with the same name will cause the problem.
+                    let need_new_scope = scope_stack
+                        .iter()
+                        .any(|entry| entry.name == Some(name));
+
+                    if need_new_scope {
+                        // Create a new lexical scope and push it onto the stack
+                        let loc = cx.sess().codemap().lookup_char_pos(pat.span.lo);
+                        let file_metadata = file_metadata(cx, &loc.file.name);
+                        let parent_scope = scope_stack.last().unwrap().scope_metadata;
+
+                        let scope_metadata = unsafe {
+                            llvm::LLVMDIBuilderCreateLexicalBlock(
+                                DIB(cx),
+                                parent_scope,
+                                file_metadata,
+                                loc.line as c_uint,
+                                loc.col.to_usize() as c_uint)
+                        };
+
+                        scope_stack.push(ScopeStackEntry {
+                            scope_metadata: scope_metadata,
+                            name: Some(name)
+                        });
+
+                    } else {
+                        // Push a new entry anyway so the name can be found
+                        let prev_metadata = scope_stack.last().unwrap().scope_metadata;
+                        scope_stack.push(ScopeStackEntry {
+                            scope_metadata: prev_metadata,
+                            name: Some(name)
+                        });
+                    }
+                }
+
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+
+                if let Some(ref sub_pat) = *sub_pat_opt {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+            }
+
+            ast::PatWild(_) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+            }
+
+            ast::PatEnum(_, ref sub_pats_opt) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+
+                if let Some(ref sub_pats) = *sub_pats_opt {
+                    for p in sub_pats {
+                        walk_pattern(cx, &**p, scope_stack, scope_map);
+                    }
+                }
+            }
+
+            ast::PatQPath(..) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+            }
+
+            ast::PatStruct(_, ref field_pats, _) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+
+                for &codemap::Spanned {
+                    node: ast::FieldPat { pat: ref sub_pat, .. },
+                    ..
+                } in field_pats.iter() {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+            }
+
+            ast::PatTup(ref sub_pats) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+
+                for sub_pat in sub_pats {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+            }
+
+            ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+                walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+            }
+
+            ast::PatLit(ref exp) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+                walk_expr(cx, &**exp, scope_stack, scope_map);
+            }
+
+            ast::PatRange(ref exp1, ref exp2) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+                walk_expr(cx, &**exp1, scope_stack, scope_map);
+                walk_expr(cx, &**exp2, scope_stack, scope_map);
+            }
+
+            ast::PatVec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+
+                for sub_pat in front_sub_pats {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+
+                if let Some(ref sub_pat) = *middle_sub_pats {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+
+                for sub_pat in back_sub_pats {
+                    walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
+                }
+            }
+
+            ast::PatMac(_) => {
+                cx.sess().span_bug(pat.span, "debuginfo::create_scope_map() - \
+                                              Found unexpanded macro.");
+            }
+        }
+    }
+
+    fn walk_expr(cx: &CrateContext,
+                 exp: &ast::Expr,
+                 scope_stack: &mut Vec<ScopeStackEntry> ,
+                 scope_map: &mut NodeMap<DIScope>) {
+
+        scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
+
+        match exp.node {
+            ast::ExprLit(_)   |
+            ast::ExprBreak(_) |
+            ast::ExprAgain(_) |
+            ast::ExprPath(..) => {}
+
+            ast::ExprCast(ref sub_exp, _)     |
+            ast::ExprAddrOf(_, ref sub_exp)  |
+            ast::ExprField(ref sub_exp, _) |
+            ast::ExprTupField(ref sub_exp, _) |
+            ast::ExprParen(ref sub_exp) =>
+                walk_expr(cx, &**sub_exp, scope_stack, scope_map),
+
+            ast::ExprBox(ref place, ref sub_expr) => {
+                place.as_ref().map(
+                    |e| walk_expr(cx, &**e, scope_stack, scope_map));
+                walk_expr(cx, &**sub_expr, scope_stack, scope_map);
+            }
+
+            ast::ExprRet(ref exp_opt) => match *exp_opt {
+                Some(ref sub_exp) => walk_expr(cx, &**sub_exp, scope_stack, scope_map),
+                None => ()
+            },
+
+            ast::ExprUnary(_, ref sub_exp) => {
+                walk_expr(cx, &**sub_exp, scope_stack, scope_map);
+            }
+
+            ast::ExprAssignOp(_, ref lhs, ref rhs) |
+            ast::ExprIndex(ref lhs, ref rhs) |
+            ast::ExprBinary(_, ref lhs, ref rhs)    => {
+                walk_expr(cx, &**lhs, scope_stack, scope_map);
+                walk_expr(cx, &**rhs, scope_stack, scope_map);
+            }
+
+            ast::ExprRange(ref start, ref end) => {
+                start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
+                end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
+            }
+
+            ast::ExprVec(ref init_expressions) |
+            ast::ExprTup(ref init_expressions) => {
+                for ie in init_expressions {
+                    walk_expr(cx, &**ie, scope_stack, scope_map);
+                }
+            }
+
+            ast::ExprAssign(ref sub_exp1, ref sub_exp2) |
+            ast::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
+                walk_expr(cx, &**sub_exp1, scope_stack, scope_map);
+                walk_expr(cx, &**sub_exp2, scope_stack, scope_map);
+            }
+
+            ast::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
+                walk_expr(cx, &**cond_exp, scope_stack, scope_map);
+
+                with_new_scope(cx,
+                               then_block.span,
+                               scope_stack,
+                               scope_map,
+                               |cx, scope_stack, scope_map| {
+                    walk_block(cx, &**then_block, scope_stack, scope_map);
+                });
+
+                match *opt_else_exp {
+                    Some(ref else_exp) =>
+                        walk_expr(cx, &**else_exp, scope_stack, scope_map),
+                    _ => ()
+                }
+            }
+
+            ast::ExprIfLet(..) => {
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
+                                              Found unexpanded if-let.");
+            }
+
+            ast::ExprWhile(ref cond_exp, ref loop_body, _) => {
+                walk_expr(cx, &**cond_exp, scope_stack, scope_map);
+
+                with_new_scope(cx,
+                               loop_body.span,
+                               scope_stack,
+                               scope_map,
+                               |cx, scope_stack, scope_map| {
+                    walk_block(cx, &**loop_body, scope_stack, scope_map);
+                })
+            }
+
+            ast::ExprWhileLet(..) => {
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
+                                              Found unexpanded while-let.");
+            }
+
+            ast::ExprForLoop(..) => {
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
+                                              Found unexpanded for loop.");
+            }
+
+            ast::ExprMac(_) => {
+                cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
+                                              Found unexpanded macro.");
+            }
+
+            ast::ExprLoop(ref block, _) |
+            ast::ExprBlock(ref block)   => {
+                with_new_scope(cx,
+                               block.span,
+                               scope_stack,
+                               scope_map,
+                               |cx, scope_stack, scope_map| {
+                    walk_block(cx, &**block, scope_stack, scope_map);
+                })
+            }
+
+            ast::ExprClosure(_, ref decl, ref block) => {
+                with_new_scope(cx,
+                               block.span,
+                               scope_stack,
+                               scope_map,
+                               |cx, scope_stack, scope_map| {
+                    for &ast::Arg { pat: ref pattern, .. } in &decl.inputs {
+                        walk_pattern(cx, &**pattern, scope_stack, scope_map);
+                    }
+
+                    walk_block(cx, &**block, scope_stack, scope_map);
+                })
+            }
+
+            ast::ExprCall(ref fn_exp, ref args) => {
+                walk_expr(cx, &**fn_exp, scope_stack, scope_map);
+
+                for arg_exp in args {
+                    walk_expr(cx, &**arg_exp, scope_stack, scope_map);
+                }
+            }
+
+            ast::ExprMethodCall(_, _, ref args) => {
+                for arg_exp in args {
+                    walk_expr(cx, &**arg_exp, scope_stack, scope_map);
+                }
+            }
+
+            ast::ExprMatch(ref discriminant_exp, ref arms, _) => {
+                walk_expr(cx, &**discriminant_exp, scope_stack, scope_map);
+
+                // For each arm we have to first walk the pattern as these might
+                // introduce new artificial scopes. It should be sufficient to
+                // walk only one pattern per arm, as they all must contain the
+                // same binding names.
+
+                for arm_ref in arms {
+                    let arm_span = arm_ref.pats[0].span;
+
+                    with_new_scope(cx,
+                                   arm_span,
+                                   scope_stack,
+                                   scope_map,
+                                   |cx, scope_stack, scope_map| {
+                        for pat in &arm_ref.pats {
+                            walk_pattern(cx, &**pat, scope_stack, scope_map);
+                        }
+
+                        if let Some(ref guard_exp) = arm_ref.guard {
+                            walk_expr(cx, &**guard_exp, scope_stack, scope_map)
+                        }
+
+                        walk_expr(cx, &*arm_ref.body, scope_stack, scope_map);
+                    })
+                }
+            }
+
+            ast::ExprStruct(_, ref fields, ref base_exp) => {
+                for &ast::Field { expr: ref exp, .. } in fields {
+                    walk_expr(cx, &**exp, scope_stack, scope_map);
+                }
+
+                match *base_exp {
+                    Some(ref exp) => walk_expr(cx, &**exp, scope_stack, scope_map),
+                    None => ()
+                }
+            }
+
+            ast::ExprInlineAsm(ast::InlineAsm { ref inputs,
+                                                ref outputs,
+                                                .. }) => {
+                // inputs, outputs: Vec<(String, P<Expr>)>
+                for &(_, ref exp) in inputs {
+                    walk_expr(cx, &**exp, scope_stack, scope_map);
+                }
+
+                for &(_, ref exp, _) in outputs {
+                    walk_expr(cx, &**exp, scope_stack, scope_map);
+                }
+            }
+        }
+    }
+}