about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm/debuginfo
diff options
context:
space:
mode:
authorIrina Popa <irinagpopa@gmail.com>2018-05-08 16:10:16 +0300
committerIrina Popa <irinagpopa@gmail.com>2018-05-17 15:08:30 +0300
commitb63d7e2b1c4019e40051036bcb1fd5f254a8f6e2 (patch)
tree314792e2f467d17181d29d4988550058197ac029 /src/librustc_codegen_llvm/debuginfo
parente3150564f889a3bad01795d9fcb31d4f14d58a99 (diff)
downloadrust-b63d7e2b1c4019e40051036bcb1fd5f254a8f6e2.tar.gz
rust-b63d7e2b1c4019e40051036bcb1fd5f254a8f6e2.zip
Rename trans to codegen everywhere.
Diffstat (limited to 'src/librustc_codegen_llvm/debuginfo')
-rw-r--r--src/librustc_codegen_llvm/debuginfo/create_scope_map.rs136
-rw-r--r--src/librustc_codegen_llvm/debuginfo/doc.rs189
-rw-r--r--src/librustc_codegen_llvm/debuginfo/gdb.rs88
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs1773
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs542
-rw-r--r--src/librustc_codegen_llvm/debuginfo/namespace.rs66
-rw-r--r--src/librustc_codegen_llvm/debuginfo/source_loc.rs107
-rw-r--r--src/librustc_codegen_llvm/debuginfo/type_names.rs224
-rw-r--r--src/librustc_codegen_llvm/debuginfo/utils.rs65
9 files changed, 3190 insertions, 0 deletions
diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
new file mode 100644
index 00000000000..bddb3d90940
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
@@ -0,0 +1,136 @@
+// 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.
+
+use super::{FunctionDebugContext, FunctionDebugContextData};
+use super::metadata::file_metadata;
+use super::utils::{DIB, span_start};
+
+use llvm;
+use llvm::debuginfo::DIScope;
+use common::CodegenCx;
+use rustc::mir::{Mir, VisibilityScope};
+
+use libc::c_uint;
+use std::ptr;
+
+use syntax_pos::Pos;
+
+use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+
+use syntax_pos::BytePos;
+
+#[derive(Clone, Copy, Debug)]
+pub struct MirDebugScope {
+    pub scope_metadata: DIScope,
+    // Start and end offsets of the file to which this DIScope belongs.
+    // These are used to quickly determine whether some span refers to the same file.
+    pub file_start_pos: BytePos,
+    pub file_end_pos: BytePos,
+}
+
+impl MirDebugScope {
+    pub fn is_valid(&self) -> bool {
+        !self.scope_metadata.is_null()
+    }
+}
+
+/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
+/// If debuginfo is disabled, the returned vector is empty.
+pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebugContext)
+    -> IndexVec<VisibilityScope, MirDebugScope> {
+    let null_scope = MirDebugScope {
+        scope_metadata: ptr::null_mut(),
+        file_start_pos: BytePos(0),
+        file_end_pos: BytePos(0)
+    };
+    let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
+
+    let debug_context = match *debug_context {
+        FunctionDebugContext::RegularContext(ref data) => data,
+        FunctionDebugContext::DebugInfoDisabled |
+        FunctionDebugContext::FunctionWithoutDebugInfo => {
+            return scopes;
+        }
+    };
+
+    // Find all the scopes with variables defined in them.
+    let mut has_variables = BitVector::new(mir.visibility_scopes.len());
+    for var in mir.vars_iter() {
+        let decl = &mir.local_decls[var];
+        has_variables.insert(decl.source_info.scope.index());
+    }
+
+    // Instantiate all scopes.
+    for idx in 0..mir.visibility_scopes.len() {
+        let scope = VisibilityScope::new(idx);
+        make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
+    }
+
+    scopes
+}
+
+fn make_mir_scope(cx: &CodegenCx,
+                  mir: &Mir,
+                  has_variables: &BitVector,
+                  debug_context: &FunctionDebugContextData,
+                  scope: VisibilityScope,
+                  scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
+    if scopes[scope].is_valid() {
+        return;
+    }
+
+    let scope_data = &mir.visibility_scopes[scope];
+    let parent_scope = if let Some(parent) = scope_data.parent_scope {
+        make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
+        scopes[parent]
+    } else {
+        // The root is the function itself.
+        let loc = span_start(cx, mir.span);
+        scopes[scope] = MirDebugScope {
+            scope_metadata: debug_context.fn_metadata,
+            file_start_pos: loc.file.start_pos,
+            file_end_pos: loc.file.end_pos,
+        };
+        return;
+    };
+
+    if !has_variables.contains(scope.index()) {
+        // Do not create a DIScope if there are no variables
+        // defined in this MIR Scope, to avoid debuginfo bloat.
+
+        // However, we don't skip creating a nested scope if
+        // our parent is the root, because we might want to
+        // put arguments in the root and not have shadowing.
+        if parent_scope.scope_metadata != debug_context.fn_metadata {
+            scopes[scope] = parent_scope;
+            return;
+        }
+    }
+
+    let loc = span_start(cx, scope_data.span);
+    let file_metadata = file_metadata(cx,
+                                      &loc.file.name,
+                                      debug_context.defining_crate);
+
+    let scope_metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateLexicalBlock(
+            DIB(cx),
+            parent_scope.scope_metadata,
+            file_metadata,
+            loc.line as c_uint,
+            loc.col.to_usize() as c_uint)
+    };
+    scopes[scope] = MirDebugScope {
+        scope_metadata,
+        file_start_pos: loc.file.start_pos,
+        file_end_pos: loc.file.end_pos,
+    };
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs
new file mode 100644
index 00000000000..ce0476b07eb
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/doc.rs
@@ -0,0 +1,189 @@
+// 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.
+
+//! # Debug Info Module
+//!
+//! This module serves the purpose of generating debug symbols. We use LLVM's
+//! [source level debugging](http://!llvm.org/docs/SourceLevelDebugging.html)
+//! features for generating the debug information. The general principle is
+//! this:
+//!
+//! Given the right metadata in the LLVM IR, the LLVM code generator is able to
+//! create DWARF debug symbols for the given code. The
+//! [metadata](http://!llvm.org/docs/LangRef.html#metadata-type) is structured
+//! much like DWARF *debugging information entries* (DIE), representing type
+//! information such as datatype layout, function signatures, block layout,
+//! variable location and scope information, etc. It is the purpose of this
+//! module to generate correct metadata and insert it into the LLVM IR.
+//!
+//! As the exact format of metadata trees may change between different LLVM
+//! versions, we now use LLVM
+//! [DIBuilder](http://!llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
+//! to create metadata where possible. This will hopefully ease the adaption of
+//! this module to future LLVM versions.
+//!
+//! The public API of the module is a set of functions that will insert the
+//! correct metadata into the LLVM IR when called with the right parameters.
+//! The module is thus driven from an outside client with functions like
+//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`.
+//!
+//! Internally the module will try to reuse already created metadata by
+//! utilizing a cache. The way to get a shared metadata node when needed is
+//! thus to just call the corresponding function in this module:
+//!
+//!     let file_metadata = file_metadata(crate_context, path);
+//!
+//! The function will take care of probing the cache for an existing node for
+//! that exact file path.
+//!
+//! All private state used by the module is stored within either the
+//! CrateDebugContext struct (owned by the CodegenCx) or the
+//! FunctionDebugContext (owned by the FunctionCx).
+//!
+//! This file consists of three conceptual sections:
+//! 1. The public interface of the module
+//! 2. Module-internal metadata creation functions
+//! 3. Minor utility functions
+//!
+//!
+//! ## Recursive Types
+//!
+//! Some kinds of types, such as structs and enums can be recursive. That means
+//! that the type definition of some type X refers to some other type which in
+//! turn (transitively) refers to X. This introduces cycles into the type
+//! referral graph. A naive algorithm doing an on-demand, depth-first traversal
+//! of this graph when describing types, can get trapped in an endless loop
+//! when it reaches such a cycle.
+//!
+//! For example, the following simple type for a singly-linked list...
+//!
+//! ```
+//! struct List {
+//!     value: i32,
+//!     tail: Option<Box<List>>,
+//! }
+//! ```
+//!
+//! will generate the following callstack with a naive DFS algorithm:
+//!
+//! ```
+//! describe(t = List)
+//!   describe(t = i32)
+//!   describe(t = Option<Box<List>>)
+//!     describe(t = Box<List>)
+//!       describe(t = List) // at the beginning again...
+//!       ...
+//! ```
+//!
+//! To break cycles like these, we use "forward declarations". That is, when
+//! the algorithm encounters a possibly recursive type (any struct or enum), it
+//! immediately creates a type description node and inserts it into the cache
+//! *before* describing the members of the type. This type description is just
+//! a stub (as type members are not described and added to it yet) but it
+//! allows the algorithm to already refer to the type. After the stub is
+//! inserted into the cache, the algorithm continues as before. If it now
+//! encounters a recursive reference, it will hit the cache and does not try to
+//! describe the type anew.
+//!
+//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum,
+//! which represents a kind of continuation, storing all state needed to
+//! continue traversal at the type members after the type has been registered
+//! with the cache. (This implementation approach might be a tad over-
+//! engineered and may change in the future)
+//!
+//!
+//! ## Source Locations and Line Information
+//!
+//! In addition to data type descriptions the debugging information must also
+//! allow to map machine code locations back to source code locations in order
+//! to be useful. This functionality is also handled in this module. The
+//! following functions allow to control source mappings:
+//!
+//! + set_source_location()
+//! + clear_source_location()
+//! + start_emitting_source_locations()
+//!
+//! `set_source_location()` allows to set the current source location. All IR
+//! instructions created after a call to this function will be linked to the
+//! given source location, until another location is specified with
+//! `set_source_location()` or the source location is cleared with
+//! `clear_source_location()`. In the later case, subsequent IR instruction
+//! will not be linked to any source location. As you can see, this is a
+//! stateful API (mimicking the one in LLVM), so be careful with source
+//! locations set by previous calls. It's probably best to not rely on any
+//! specific state being present at a given point in code.
+//!
+//! One topic that deserves some extra attention is *function prologues*. At
+//! the beginning of a function's machine code there are typically a few
+//! instructions for loading argument values into allocas and checking if
+//! there's enough stack space for the function to execute. This *prologue* is
+//! not visible in the source code and LLVM puts a special PROLOGUE END marker
+//! into the line table at the first non-prologue instruction of the function.
+//! In order to find out where the prologue ends, LLVM looks for the first
+//! instruction in the function body that is linked to a source location. So,
+//! when generating prologue instructions we have to make sure that we don't
+//! emit source location information until the 'real' function body begins. For
+//! this reason, source location emission is disabled by default for any new
+//! function being codegened and is only activated after a call to the third
+//! function from the list above, `start_emitting_source_locations()`. This
+//! function should be called right before regularly starting to codegen the
+//! top-level block of the given function.
+//!
+//! There is one exception to the above rule: `llvm.dbg.declare` instruction
+//! must be linked to the source location of the variable being declared. For
+//! function parameters these `llvm.dbg.declare` instructions typically occur
+//! in the middle of the prologue, however, they are ignored by LLVM's prologue
+//! detection. The `create_argument_metadata()` and related functions take care
+//! of linking the `llvm.dbg.declare` instructions to the correct source
+//! locations even while source location emission is still disabled, so there
+//! is no need to do anything special with source location handling here.
+//!
+//! ## Unique Type Identification
+//!
+//! In order for link-time optimization to work properly, LLVM needs a unique
+//! type identifier that tells it across compilation units which types are the
+//! same as others. This type identifier is created by
+//! TypeMap::get_unique_type_id_of_type() using the following algorithm:
+//!
+//! (1) Primitive types have their name as ID
+//! (2) Structs, enums and traits have a multipart identifier
+//!
+//!     (1) The first part is the SVH (strict version hash) of the crate they
+//!          were originally defined in
+//!
+//!     (2) The second part is the ast::NodeId of the definition in their
+//!          original crate
+//!
+//!     (3) The final part is a concatenation of the type IDs of their concrete
+//!          type arguments if they are generic types.
+//!
+//! (3) Tuple-, pointer and function types are structurally identified, which
+//!     means that they are equivalent if their component types are equivalent
+//!     (i.e. (i32, i32) is the same regardless in which crate it is used).
+//!
+//! This algorithm also provides a stable ID for types that are defined in one
+//! crate but instantiated from metadata within another crate. We just have to
+//! take care to always map crate and node IDs back to the original crate
+//! context.
+//!
+//! As a side-effect these unique type IDs also help to solve a problem arising
+//! from lifetime parameters. Since lifetime parameters are completely omitted
+//! in debuginfo, more than one `Ty` instance may map to the same debuginfo
+//! type metadata, that is, some struct `Struct<'a>` may have N instantiations
+//! with different concrete substitutions for `'a`, and thus there will be N
+//! `Ty` instances for the type `Struct<'a>` even though it is not generic
+//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as
+//! cheap identifier for type metadata---we have done this in the past, but it
+//! led to unnecessary metadata duplication in the best case and LLVM
+//! assertions in the worst. However, the unique type ID as described above
+//! *can* be used as identifier. Since it is comparatively expensive to
+//! construct, though, `ty::type_id()` is still used additionally as an
+//! optimization for cases where the exact same type has been seen before
+//! (which is most of the time).
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
new file mode 100644
index 00000000000..0b4858c7ab0
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -0,0 +1,88 @@
+// 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.
+
+// .debug_gdb_scripts binary section.
+
+use llvm;
+
+use common::{C_bytes, CodegenCx, C_i32};
+use builder::Builder;
+use declare;
+use type_::Type;
+use rustc::session::config::NoDebugInfo;
+
+use std::ptr;
+use syntax::attr;
+
+
+/// Inserts a side-effect free instruction sequence that makes sure that the
+/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
+pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &Builder) {
+    if needs_gdb_debug_scripts_section(bx.cx) {
+        let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx.cx);
+        // Load just the first byte as that's all that's necessary to force
+        // LLVM to keep around the reference to the global.
+        let indices = [C_i32(bx.cx, 0), C_i32(bx.cx, 0)];
+        let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices);
+        let volative_load_instruction = bx.volatile_load(element);
+        unsafe {
+            llvm::LLVMSetAlignment(volative_load_instruction, 1);
+        }
+    }
+}
+
+/// Allocates the global variable responsible for the .debug_gdb_scripts binary
+/// section.
+pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx)
+                                                  -> llvm::ValueRef {
+    let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
+    let section_var_name = &c_section_var_name[..c_section_var_name.len()-1];
+
+    let section_var = unsafe {
+        llvm::LLVMGetNamedGlobal(cx.llmod,
+                                 c_section_var_name.as_ptr() as *const _)
+    };
+
+    if section_var == ptr::null_mut() {
+        let section_name = b".debug_gdb_scripts\0";
+        let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
+
+        unsafe {
+            let llvm_type = Type::array(&Type::i8(cx),
+                                        section_contents.len() as u64);
+
+            let section_var = declare::define_global(cx, section_var_name,
+                                                     llvm_type).unwrap_or_else(||{
+                bug!("symbol `{}` is already defined", section_var_name)
+            });
+            llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
+            llvm::LLVMSetInitializer(section_var, C_bytes(cx, section_contents));
+            llvm::LLVMSetGlobalConstant(section_var, llvm::True);
+            llvm::LLVMSetUnnamedAddr(section_var, llvm::True);
+            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            // This should make sure that the whole section is not larger than
+            // the string it contains. Otherwise we get a warning from GDB.
+            llvm::LLVMSetAlignment(section_var, 1);
+            section_var
+        }
+    } else {
+        section_var
+    }
+}
+
+pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx) -> bool {
+    let omit_gdb_pretty_printer_section =
+        attr::contains_name(&cx.tcx.hir.krate_attrs(),
+                            "omit_gdb_pretty_printer_section");
+
+    !omit_gdb_pretty_printer_section &&
+    cx.sess().opts.debuginfo != NoDebugInfo &&
+    cx.sess().target.target.options.emit_debug_gdb_scripts
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
new file mode 100644
index 00000000000..ee60711c11d
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -0,0 +1,1773 @@
+// 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.
+
+use self::RecursiveTypeDescription::*;
+use self::MemberDescriptionFactory::*;
+use self::EnumDiscriminantInfo::*;
+
+use super::utils::{debug_context, DIB, span_start,
+                   get_namespace_for_item, create_DIArray, is_node_local_to_unit};
+use super::namespace::mangled_name_of_instance;
+use super::type_names::compute_debuginfo_type_name;
+use super::{CrateDebugContext};
+use abi;
+
+use llvm::{self, ValueRef};
+use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
+                      DICompositeType, DILexicalBlock, DIFlags};
+
+use rustc::hir::CodegenFnAttrFlags;
+use rustc::hir::def::CtorKind;
+use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
+use rustc::ty::fold::TypeVisitor;
+use rustc::ty::util::TypeIdHasher;
+use rustc::ich::Fingerprint;
+use rustc::ty::Instance;
+use common::CodegenCx;
+use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
+use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout};
+use rustc::session::config;
+use rustc::util::nodemap::FxHashMap;
+use rustc::util::common::path2cstr;
+
+use libc::{c_uint, c_longlong};
+use std::ffi::CString;
+use std::fmt::Write;
+use std::ptr;
+use std::path::{Path, PathBuf};
+use syntax::ast;
+use syntax::symbol::{Interner, InternedString, Symbol};
+use syntax_pos::{self, Span, FileName};
+
+
+// From DWARF 5.
+// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1
+const DW_LANG_RUST: c_uint = 0x1c;
+#[allow(non_upper_case_globals)]
+const DW_ATE_boolean: c_uint = 0x02;
+#[allow(non_upper_case_globals)]
+const DW_ATE_float: c_uint = 0x04;
+#[allow(non_upper_case_globals)]
+const DW_ATE_signed: c_uint = 0x05;
+#[allow(non_upper_case_globals)]
+const DW_ATE_unsigned: c_uint = 0x07;
+#[allow(non_upper_case_globals)]
+const DW_ATE_unsigned_char: c_uint = 0x08;
+
+pub const UNKNOWN_LINE_NUMBER: c_uint = 0;
+pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+
+// ptr::null() doesn't work :(
+pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope);
+
+#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
+pub struct UniqueTypeId(ast::Name);
+
+// The TypeMap is where the CrateDebugContext holds the type metadata nodes
+// created so far. The metadata nodes are indexed by UniqueTypeId, and, for
+// faster lookup, also by Ty. The TypeMap is responsible for creating
+// UniqueTypeIds.
+pub struct TypeMap<'tcx> {
+    // The UniqueTypeIds created so far
+    unique_id_interner: Interner,
+    // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
+    unique_id_to_metadata: FxHashMap<UniqueTypeId, DIType>,
+    // A map from types to debuginfo metadata. This is a N:1 mapping.
+    type_to_metadata: FxHashMap<Ty<'tcx>, DIType>,
+    // A map from types to UniqueTypeId. This is a N:1 mapping.
+    type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>
+}
+
+impl<'tcx> TypeMap<'tcx> {
+    pub fn new() -> TypeMap<'tcx> {
+        TypeMap {
+            unique_id_interner: Interner::new(),
+            type_to_metadata: FxHashMap(),
+            unique_id_to_metadata: FxHashMap(),
+            type_to_unique_id: FxHashMap(),
+        }
+    }
+
+    // Adds a Ty to metadata mapping to the TypeMap. The method will fail if
+    // the mapping already exists.
+    fn register_type_with_metadata<'a>(&mut self,
+                                       type_: Ty<'tcx>,
+                                       metadata: DIType) {
+        if self.type_to_metadata.insert(type_, metadata).is_some() {
+            bug!("Type metadata for Ty '{}' is already in the TypeMap!", type_);
+        }
+    }
+
+    // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will
+    // fail if the mapping already exists.
+    fn register_unique_id_with_metadata(&mut self,
+                                        unique_type_id: UniqueTypeId,
+                                        metadata: DIType) {
+        if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() {
+            bug!("Type metadata for unique id '{}' is already in the TypeMap!",
+                 self.get_unique_type_id_as_string(unique_type_id));
+        }
+    }
+
+    fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<DIType> {
+        self.type_to_metadata.get(&type_).cloned()
+    }
+
+    fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
+        self.unique_id_to_metadata.get(&unique_type_id).cloned()
+    }
+
+    // Get the string representation of a UniqueTypeId. This method will fail if
+    // the id is unknown.
+    fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str {
+        let UniqueTypeId(interner_key) = unique_type_id;
+        self.unique_id_interner.get(interner_key)
+    }
+
+    // Get the UniqueTypeId for the given type. If the UniqueTypeId for the given
+    // type has been requested before, this is just a table lookup. Otherwise an
+    // ID will be generated and stored for later lookup.
+    fn get_unique_type_id_of_type<'a>(&mut self, cx: &CodegenCx<'a, 'tcx>,
+                                      type_: Ty<'tcx>) -> UniqueTypeId {
+        // Let's see if we already have something in the cache
+        match self.type_to_unique_id.get(&type_).cloned() {
+            Some(unique_type_id) => return unique_type_id,
+            None => { /* generate one */}
+        };
+
+        // The hasher we are using to generate the UniqueTypeId. We want
+        // something that provides more than the 64 bits of the DefaultHasher.
+        let mut type_id_hasher = TypeIdHasher::<Fingerprint>::new(cx.tcx);
+        type_id_hasher.visit_ty(type_);
+        let unique_type_id = type_id_hasher.finish().to_hex();
+
+        let key = self.unique_id_interner.intern(&unique_type_id);
+        self.type_to_unique_id.insert(type_, UniqueTypeId(key));
+
+        return UniqueTypeId(key);
+    }
+
+    // Get the UniqueTypeId for an enum variant. Enum variants are not really
+    // types of their own, so they need special handling. We still need a
+    // UniqueTypeId for them, since to debuginfo they *are* real types.
+    fn get_unique_type_id_of_enum_variant<'a>(&mut self,
+                                              cx: &CodegenCx<'a, 'tcx>,
+                                              enum_type: Ty<'tcx>,
+                                              variant_name: &str)
+                                              -> UniqueTypeId {
+        let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
+        let enum_variant_type_id = format!("{}::{}",
+                                           self.get_unique_type_id_as_string(enum_type_id),
+                                           variant_name);
+        let interner_key = self.unique_id_interner.intern(&enum_variant_type_id);
+        UniqueTypeId(interner_key)
+    }
+}
+
+// A description of some recursive type. It can either be already finished (as
+// with FinalMetadata) or it is not yet finished, but contains all information
+// needed to generate the missing parts of the description. See the
+// documentation section on Recursive Types at the top of this file for more
+// information.
+enum RecursiveTypeDescription<'tcx> {
+    UnfinishedMetadata {
+        unfinished_type: Ty<'tcx>,
+        unique_type_id: UniqueTypeId,
+        metadata_stub: DICompositeType,
+        member_description_factory: MemberDescriptionFactory<'tcx>,
+    },
+    FinalMetadata(DICompositeType)
+}
+
+fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>(
+    cx: &CodegenCx<'a, 'tcx>,
+    unfinished_type: Ty<'tcx>,
+    unique_type_id: UniqueTypeId,
+    metadata_stub: DICompositeType,
+    member_description_factory: MemberDescriptionFactory<'tcx>)
+ -> RecursiveTypeDescription<'tcx> {
+
+    // Insert the stub into the TypeMap in order to allow for recursive references
+    let mut type_map = debug_context(cx).type_map.borrow_mut();
+    type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub);
+    type_map.register_type_with_metadata(unfinished_type, metadata_stub);
+
+    UnfinishedMetadata {
+        unfinished_type,
+        unique_type_id,
+        metadata_stub,
+        member_description_factory,
+    }
+}
+
+impl<'tcx> RecursiveTypeDescription<'tcx> {
+    // Finishes up the description of the type in question (mostly by providing
+    // descriptions of the fields of the given type) and returns the final type
+    // metadata.
+    fn finalize<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> MetadataCreationResult {
+        match *self {
+            FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false),
+            UnfinishedMetadata {
+                unfinished_type,
+                unique_type_id,
+                metadata_stub,
+                ref member_description_factory,
+            } => {
+                // Make sure that we have a forward declaration of the type in
+                // the TypeMap so that recursive references are possible. This
+                // will always be the case if the RecursiveTypeDescription has
+                // been properly created through the
+                // create_and_register_recursive_type_forward_declaration()
+                // function.
+                {
+                    let type_map = debug_context(cx).type_map.borrow();
+                    if type_map.find_metadata_for_unique_id(unique_type_id).is_none() ||
+                       type_map.find_metadata_for_type(unfinished_type).is_none() {
+                        bug!("Forward declaration of potentially recursive type \
+                              '{:?}' was not found in TypeMap!",
+                             unfinished_type);
+                    }
+                }
+
+                // ... then create the member descriptions ...
+                let member_descriptions =
+                    member_description_factory.create_member_descriptions(cx);
+
+                // ... and attach them to the stub to complete it.
+                set_members_of_composite_type(cx,
+                                              metadata_stub,
+                                              &member_descriptions[..]);
+                return MetadataCreationResult::new(metadata_stub, true);
+            }
+        }
+    }
+}
+
+// Returns from the enclosing function if the type metadata with the given
+// unique id can be found in the type map
+macro_rules! return_if_metadata_created_in_meantime {
+    ($cx: expr, $unique_type_id: expr) => (
+        match debug_context($cx).type_map
+                                .borrow()
+                                .find_metadata_for_unique_id($unique_type_id) {
+            Some(metadata) => return MetadataCreationResult::new(metadata, true),
+            None => { /* proceed normally */ }
+        }
+    )
+}
+
+fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                unique_type_id: UniqueTypeId,
+                                array_or_slice_type: Ty<'tcx>,
+                                element_type: Ty<'tcx>,
+                                span: Span)
+                                -> MetadataCreationResult {
+    let element_type_metadata = type_metadata(cx, element_type, span);
+
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+    let (size, align) = cx.size_and_align_of(array_or_slice_type);
+
+    let upper_bound = match array_or_slice_type.sty {
+        ty::TyArray(_, len) => {
+            len.unwrap_usize(cx.tcx) as c_longlong
+        }
+        _ => -1
+    };
+
+    let subrange = unsafe {
+        llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)
+    };
+
+    let subscripts = create_DIArray(DIB(cx), &[subrange]);
+    let metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateArrayType(
+            DIB(cx),
+            size.bits(),
+            align.abi_bits() as u32,
+            element_type_metadata,
+            subscripts)
+    };
+
+    return MetadataCreationResult::new(metadata, false);
+}
+
+fn vec_slice_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                slice_ptr_type: Ty<'tcx>,
+                                element_type: Ty<'tcx>,
+                                unique_type_id: UniqueTypeId,
+                                span: Span)
+                                -> MetadataCreationResult {
+    let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
+
+    let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
+
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+    let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true);
+
+    let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
+    let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
+
+    let member_descriptions = [
+        MemberDescription {
+            name: "data_ptr".to_string(),
+            type_metadata: data_ptr_metadata,
+            offset: Size::from_bytes(0),
+            size: pointer_size,
+            align: pointer_align,
+            flags: DIFlags::FlagZero,
+        },
+        MemberDescription {
+            name: "length".to_string(),
+            type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
+            offset: pointer_size,
+            size: usize_size,
+            align: usize_align,
+            flags: DIFlags::FlagZero,
+        },
+    ];
+
+    let file_metadata = unknown_file_metadata(cx);
+
+    let metadata = composite_type_metadata(cx,
+                                           slice_ptr_type,
+                                           &slice_type_name[..],
+                                           unique_type_id,
+                                           &member_descriptions,
+                                           NO_SCOPE_METADATA,
+                                           file_metadata,
+                                           span);
+    MetadataCreationResult::new(metadata, false)
+}
+
+fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                      unique_type_id: UniqueTypeId,
+                                      signature: ty::PolyFnSig<'tcx>,
+                                      span: Span)
+                                      -> MetadataCreationResult
+{
+    let signature = cx.tcx.normalize_erasing_late_bound_regions(
+        ty::ParamEnv::reveal_all(),
+        &signature,
+    );
+
+    let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
+
+    // return type
+    signature_metadata.push(match signature.output().sty {
+        ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+        _ => type_metadata(cx, signature.output(), span)
+    });
+
+    // regular arguments
+    for &argument_type in signature.inputs() {
+        signature_metadata.push(type_metadata(cx, argument_type, span));
+    }
+
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+    return MetadataCreationResult::new(
+        unsafe {
+            llvm::LLVMRustDIBuilderCreateSubroutineType(
+                DIB(cx),
+                unknown_file_metadata(cx),
+                create_DIArray(DIB(cx), &signature_metadata[..]))
+        },
+        false);
+}
+
+// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill-
+// defined concept. For the case of an actual trait pointer (i.e., Box<Trait>,
+// &Trait), trait_object_type should be the whole thing (e.g, Box<Trait>) and
+// trait_type should be the actual trait (e.g., Trait). Where the trait is part
+// of a DST struct, there is no trait_object_type and the results of this
+// function will be a little bit weird.
+fn trait_pointer_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                    trait_type: Ty<'tcx>,
+                                    trait_object_type: Option<Ty<'tcx>>,
+                                    unique_type_id: UniqueTypeId)
+                                    -> DIType {
+    // The implementation provided here is a stub. It makes sure that the trait
+    // type is assigned the correct name, size, namespace, and source location.
+    // But it does not describe the trait's methods.
+
+    let containing_scope = match trait_type.sty {
+        ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() {
+            let def_id = principal.def_id();
+            get_namespace_for_item(cx, def_id)
+        } else {
+            NO_SCOPE_METADATA
+        },
+        _ => {
+            bug!("debuginfo: Unexpected trait-object type in \
+                  trait_pointer_metadata(): {:?}",
+                 trait_type);
+        }
+    };
+
+    let trait_object_type = trait_object_type.unwrap_or(trait_type);
+    let trait_type_name =
+        compute_debuginfo_type_name(cx, trait_object_type, false);
+
+    let file_metadata = unknown_file_metadata(cx);
+
+    let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
+
+    assert_eq!(abi::FAT_PTR_ADDR, 0);
+    assert_eq!(abi::FAT_PTR_EXTRA, 1);
+
+    let data_ptr_field = layout.field(cx, 0);
+    let vtable_field = layout.field(cx, 1);
+    let member_descriptions = [
+        MemberDescription {
+            name: "pointer".to_string(),
+            type_metadata: type_metadata(cx,
+                cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
+                syntax_pos::DUMMY_SP),
+            offset: layout.fields.offset(0),
+            size: data_ptr_field.size,
+            align: data_ptr_field.align,
+            flags: DIFlags::FlagArtificial,
+        },
+        MemberDescription {
+            name: "vtable".to_string(),
+            type_metadata: type_metadata(cx, vtable_field.ty, syntax_pos::DUMMY_SP),
+            offset: layout.fields.offset(1),
+            size: vtable_field.size,
+            align: vtable_field.align,
+            flags: DIFlags::FlagArtificial,
+        },
+    ];
+
+    composite_type_metadata(cx,
+                            trait_object_type,
+                            &trait_type_name[..],
+                            unique_type_id,
+                            &member_descriptions,
+                            containing_scope,
+                            file_metadata,
+                            syntax_pos::DUMMY_SP)
+}
+
+pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                               t: Ty<'tcx>,
+                               usage_site_span: Span)
+                               -> DIType {
+    // Get the unique type id of this type.
+    let unique_type_id = {
+        let mut type_map = debug_context(cx).type_map.borrow_mut();
+        // First, try to find the type in TypeMap. If we have seen it before, we
+        // can exit early here.
+        match type_map.find_metadata_for_type(t) {
+            Some(metadata) => {
+                return metadata;
+            },
+            None => {
+                // The Ty is not in the TypeMap but maybe we have already seen
+                // an equivalent type (e.g. only differing in region arguments).
+                // In order to find out, generate the unique type id and look
+                // that up.
+                let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
+                match type_map.find_metadata_for_unique_id(unique_type_id) {
+                    Some(metadata) => {
+                        // There is already an equivalent type in the TypeMap.
+                        // Register this Ty as an alias in the cache and
+                        // return the cached metadata.
+                        type_map.register_type_with_metadata(t, metadata);
+                        return metadata;
+                    },
+                    None => {
+                        // There really is no type metadata for this type, so
+                        // proceed by creating it.
+                        unique_type_id
+                    }
+                }
+            }
+        }
+    };
+
+    debug!("type_metadata: {:?}", t);
+
+    let ptr_metadata = |ty: Ty<'tcx>| {
+        match ty.sty {
+            ty::TySlice(typ) => {
+                Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span))
+            }
+            ty::TyStr => {
+                Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span))
+            }
+            ty::TyDynamic(..) => {
+                Ok(MetadataCreationResult::new(
+                    trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
+                    false))
+            }
+            _ => {
+                let pointee_metadata = type_metadata(cx, ty, usage_site_span);
+
+                match debug_context(cx).type_map
+                                        .borrow()
+                                        .find_metadata_for_unique_id(unique_type_id) {
+                    Some(metadata) => return Err(metadata),
+                    None => { /* proceed normally */ }
+                };
+
+                Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata),
+                   false))
+            }
+        }
+    };
+
+    let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty {
+        ty::TyNever    |
+        ty::TyBool     |
+        ty::TyChar     |
+        ty::TyInt(_)   |
+        ty::TyUint(_)  |
+        ty::TyFloat(_) => {
+            MetadataCreationResult::new(basic_type_metadata(cx, t), false)
+        }
+        ty::TyTuple(ref elements) if elements.is_empty() => {
+            MetadataCreationResult::new(basic_type_metadata(cx, t), false)
+        }
+        ty::TyArray(typ, _) |
+        ty::TySlice(typ) => {
+            fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
+        }
+        ty::TyStr => {
+            fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span)
+        }
+        ty::TyDynamic(..) => {
+            MetadataCreationResult::new(
+                        trait_pointer_metadata(cx, t, None, unique_type_id),
+            false)
+        }
+        ty::TyForeign(..) => {
+            MetadataCreationResult::new(
+                        foreign_type_metadata(cx, t, unique_type_id),
+            false)
+        }
+        ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
+        ty::TyRef(_, ty, _) => {
+            match ptr_metadata(ty) {
+                Ok(res) => res,
+                Err(metadata) => return metadata,
+            }
+        }
+        ty::TyAdt(def, _) if def.is_box() => {
+            match ptr_metadata(t.boxed_ty()) {
+                Ok(res) => res,
+                Err(metadata) => return metadata,
+            }
+        }
+        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+            let fn_metadata = subroutine_type_metadata(cx,
+                                                       unique_type_id,
+                                                       t.fn_sig(cx.tcx),
+                                                       usage_site_span).metadata;
+            match debug_context(cx).type_map
+                                   .borrow()
+                                   .find_metadata_for_unique_id(unique_type_id) {
+                Some(metadata) => return metadata,
+                None => { /* proceed normally */ }
+            };
+
+            // This is actually a function pointer, so wrap it in pointer DI
+            MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
+
+        }
+        ty::TyClosure(def_id, substs) => {
+            let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx).collect();
+            prepare_tuple_metadata(cx,
+                                   t,
+                                   &upvar_tys,
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
+        }
+        ty::TyGenerator(def_id, substs,  _) => {
+            let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| {
+                cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
+            }).collect();
+            prepare_tuple_metadata(cx,
+                                   t,
+                                   &upvar_tys,
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
+        }
+        ty::TyAdt(def, ..) => match def.adt_kind() {
+            AdtKind::Struct => {
+                prepare_struct_metadata(cx,
+                                        t,
+                                        unique_type_id,
+                                        usage_site_span).finalize(cx)
+            }
+            AdtKind::Union => {
+                prepare_union_metadata(cx,
+                                    t,
+                                    unique_type_id,
+                                    usage_site_span).finalize(cx)
+            }
+            AdtKind::Enum => {
+                prepare_enum_metadata(cx,
+                                    t,
+                                    def.did,
+                                    unique_type_id,
+                                    usage_site_span).finalize(cx)
+            }
+        },
+        ty::TyTuple(ref elements) => {
+            prepare_tuple_metadata(cx,
+                                   t,
+                                   &elements[..],
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
+        }
+        _ => {
+            bug!("debuginfo: unexpected type in type_metadata: {:?}", t)
+        }
+    };
+
+    {
+        let mut type_map = debug_context(cx).type_map.borrow_mut();
+
+        if already_stored_in_typemap {
+            // Also make sure that we already have a TypeMap entry for the unique type id.
+            let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
+                Some(metadata) => metadata,
+                None => {
+                    span_bug!(usage_site_span,
+                              "Expected type metadata for unique \
+                               type id '{}' to already be in \
+                               the debuginfo::TypeMap but it \
+                               was not. (Ty = {})",
+                              type_map.get_unique_type_id_as_string(unique_type_id),
+                              t);
+                }
+            };
+
+            match type_map.find_metadata_for_type(t) {
+                Some(metadata) => {
+                    if metadata != metadata_for_uid {
+                        span_bug!(usage_site_span,
+                                  "Mismatch between Ty and \
+                                   UniqueTypeId maps in \
+                                   debuginfo::TypeMap. \
+                                   UniqueTypeId={}, Ty={}",
+                                  type_map.get_unique_type_id_as_string(unique_type_id),
+                                  t);
+                    }
+                }
+                None => {
+                    type_map.register_type_with_metadata(t, metadata);
+                }
+            }
+        } else {
+            type_map.register_type_with_metadata(t, metadata);
+            type_map.register_unique_id_with_metadata(unique_type_id, metadata);
+        }
+    }
+
+    metadata
+}
+
+pub fn file_metadata(cx: &CodegenCx,
+                     file_name: &FileName,
+                     defining_crate: CrateNum) -> DIFile {
+    debug!("file_metadata: file_name: {}, defining_crate: {}",
+           file_name,
+           defining_crate);
+
+    let directory = if defining_crate == LOCAL_CRATE {
+        &cx.sess().working_dir.0
+    } else {
+        // If the path comes from an upstream crate we assume it has been made
+        // independent of the compiler's working directory one way or another.
+        Path::new("")
+    };
+
+    file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy())
+}
+
+pub fn unknown_file_metadata(cx: &CodegenCx) -> DIFile {
+    file_metadata_raw(cx, "<unknown>", "")
+}
+
+fn file_metadata_raw(cx: &CodegenCx,
+                     file_name: &str,
+                     directory: &str)
+                     -> DIFile {
+    let key = (Symbol::intern(file_name), Symbol::intern(directory));
+
+    if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) {
+        return *file_metadata;
+    }
+
+    debug!("file_metadata: file_name: {}, directory: {}", file_name, directory);
+
+    let file_name = CString::new(file_name).unwrap();
+    let directory = CString::new(directory).unwrap();
+
+    let file_metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateFile(DIB(cx),
+                                          file_name.as_ptr(),
+                                          directory.as_ptr())
+    };
+
+    let mut created_files = debug_context(cx).created_files.borrow_mut();
+    created_files.insert(key, file_metadata);
+    file_metadata
+}
+
+fn basic_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                 t: Ty<'tcx>) -> DIType {
+
+    debug!("basic_type_metadata: {:?}", t);
+
+    let (name, encoding) = match t.sty {
+        ty::TyNever => ("!", DW_ATE_unsigned),
+        ty::TyTuple(ref elements) if elements.is_empty() =>
+            ("()", DW_ATE_unsigned),
+        ty::TyBool => ("bool", DW_ATE_boolean),
+        ty::TyChar => ("char", DW_ATE_unsigned_char),
+        ty::TyInt(int_ty) => {
+            (int_ty.ty_to_string(), DW_ATE_signed)
+        },
+        ty::TyUint(uint_ty) => {
+            (uint_ty.ty_to_string(), DW_ATE_unsigned)
+        },
+        ty::TyFloat(float_ty) => {
+            (float_ty.ty_to_string(), DW_ATE_float)
+        },
+        _ => bug!("debuginfo::basic_type_metadata - t is invalid type")
+    };
+
+    let (size, align) = cx.size_and_align_of(t);
+    let name = CString::new(name).unwrap();
+    let ty_metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateBasicType(
+            DIB(cx),
+            name.as_ptr(),
+            size.bits(),
+            align.abi_bits() as u32,
+            encoding)
+    };
+
+    return ty_metadata;
+}
+
+fn foreign_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                   t: Ty<'tcx>,
+                                   unique_type_id: UniqueTypeId) -> DIType {
+    debug!("foreign_type_metadata: {:?}", t);
+
+    let name = compute_debuginfo_type_name(cx, t, false);
+    create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
+}
+
+fn pointer_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                   pointer_type: Ty<'tcx>,
+                                   pointee_type_metadata: DIType)
+                                   -> DIType {
+    let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
+    let name = compute_debuginfo_type_name(cx, pointer_type, false);
+    let name = CString::new(name).unwrap();
+    unsafe {
+        llvm::LLVMRustDIBuilderCreatePointerType(
+            DIB(cx),
+            pointee_type_metadata,
+            pointer_size.bits(),
+            pointer_align.abi_bits() as u32,
+            name.as_ptr())
+    }
+}
+
+pub fn compile_unit_metadata(tcx: TyCtxt,
+                             codegen_unit_name: &str,
+                             debug_context: &CrateDebugContext)
+                             -> DIDescriptor {
+    let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
+        Some(ref path) => path.clone(),
+        None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()),
+    };
+
+    // The OSX linker has an idiosyncrasy where it will ignore some debuginfo
+    // if multiple object files with the same DW_AT_name are linked together.
+    // As a workaround we generate unique names for each object file. Those do
+    // not correspond to an actual source file but that should be harmless.
+    if tcx.sess.target.target.options.is_like_osx {
+        name_in_debuginfo.push("@");
+        name_in_debuginfo.push(codegen_unit_name);
+    }
+
+    debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
+    // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
+    let producer = format!("clang LLVM (rustc version {})",
+                           (option_env!("CFG_VERSION")).expect("CFG_VERSION"));
+
+    let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned();
+    let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap();
+    let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap();
+    let producer = CString::new(producer).unwrap();
+    let flags = "\0";
+    let split_name = "\0";
+
+    unsafe {
+        let file_metadata = llvm::LLVMRustDIBuilderCreateFile(
+            debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr());
+
+        let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
+            debug_context.builder,
+            DW_LANG_RUST,
+            file_metadata,
+            producer.as_ptr(),
+            tcx.sess.opts.optimize != config::OptLevel::No,
+            flags.as_ptr() as *const _,
+            0,
+            split_name.as_ptr() as *const _);
+
+        if tcx.sess.opts.debugging_opts.profile {
+            let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext,
+                                                                 unit_metadata);
+
+            let gcov_cu_info = [
+                path_to_mdstring(debug_context.llcontext,
+                                 &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno")),
+                path_to_mdstring(debug_context.llcontext,
+                                 &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda")),
+                cu_desc_metadata,
+            ];
+            let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext,
+                                                          gcov_cu_info.as_ptr(),
+                                                          gcov_cu_info.len() as c_uint);
+
+            let llvm_gcov_ident = CString::new("llvm.gcov").unwrap();
+            llvm::LLVMAddNamedMetadataOperand(debug_context.llmod,
+                                              llvm_gcov_ident.as_ptr(),
+                                              gcov_metadata);
+        }
+
+        return unit_metadata;
+    };
+
+    fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef {
+        let path_str = path2cstr(path);
+        unsafe {
+            llvm::LLVMMDStringInContext(llcx,
+                                        path_str.as_ptr(),
+                                        path_str.as_bytes().len() as c_uint)
+        }
+    }
+}
+
+struct MetadataCreationResult {
+    metadata: DIType,
+    already_stored_in_typemap: bool
+}
+
+impl MetadataCreationResult {
+    fn new(metadata: DIType, already_stored_in_typemap: bool) -> MetadataCreationResult {
+        MetadataCreationResult {
+            metadata,
+            already_stored_in_typemap,
+        }
+    }
+}
+
+// Description of a type member, which can either be a regular field (as in
+// structs or tuples) or an enum variant.
+#[derive(Debug)]
+struct MemberDescription {
+    name: String,
+    type_metadata: DIType,
+    offset: Size,
+    size: Size,
+    align: Align,
+    flags: DIFlags,
+}
+
+// A factory for MemberDescriptions. It produces a list of member descriptions
+// for some record-like type. MemberDescriptionFactories are used to defer the
+// creation of type member descriptions in order to break cycles arising from
+// recursive type definitions.
+enum MemberDescriptionFactory<'tcx> {
+    StructMDF(StructMemberDescriptionFactory<'tcx>),
+    TupleMDF(TupleMemberDescriptionFactory<'tcx>),
+    EnumMDF(EnumMemberDescriptionFactory<'tcx>),
+    UnionMDF(UnionMemberDescriptionFactory<'tcx>),
+    VariantMDF(VariantMemberDescriptionFactory<'tcx>)
+}
+
+impl<'tcx> MemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        match *self {
+            StructMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
+            TupleMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
+            EnumMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
+            UnionMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
+            VariantMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
+        }
+    }
+}
+
+//=-----------------------------------------------------------------------------
+// Structs
+//=-----------------------------------------------------------------------------
+
+// Creates MemberDescriptions for the fields of a struct
+struct StructMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
+    variant: &'tcx ty::VariantDef,
+    span: Span,
+}
+
+impl<'tcx> StructMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        let layout = cx.layout_of(self.ty);
+        self.variant.fields.iter().enumerate().map(|(i, f)| {
+            let name = if self.variant.ctor_kind == CtorKind::Fn {
+                format!("__{}", i)
+            } else {
+                f.name.to_string()
+            };
+            let field = layout.field(cx, i);
+            let (size, align) = field.size_and_align();
+            MemberDescription {
+                name,
+                type_metadata: type_metadata(cx, field.ty, self.span),
+                offset: layout.fields.offset(i),
+                size,
+                align,
+                flags: DIFlags::FlagZero,
+            }
+        }).collect()
+    }
+}
+
+
+fn prepare_struct_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                     struct_type: Ty<'tcx>,
+                                     unique_type_id: UniqueTypeId,
+                                     span: Span)
+                                     -> RecursiveTypeDescription<'tcx> {
+    let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
+
+    let (struct_def_id, variant) = match struct_type.sty {
+        ty::TyAdt(def, _) => (def.did, def.non_enum_variant()),
+        _ => bug!("prepare_struct_metadata on a non-ADT")
+    };
+
+    let containing_scope = get_namespace_for_item(cx, struct_def_id);
+
+    let struct_metadata_stub = create_struct_stub(cx,
+                                                  struct_type,
+                                                  &struct_name,
+                                                  unique_type_id,
+                                                  containing_scope);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        struct_type,
+        unique_type_id,
+        struct_metadata_stub,
+        StructMDF(StructMemberDescriptionFactory {
+            ty: struct_type,
+            variant,
+            span,
+        })
+    )
+}
+
+//=-----------------------------------------------------------------------------
+// Tuples
+//=-----------------------------------------------------------------------------
+
+// Creates MemberDescriptions for the fields of a tuple
+struct TupleMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
+    component_types: Vec<Ty<'tcx>>,
+    span: Span,
+}
+
+impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        let layout = cx.layout_of(self.ty);
+        self.component_types.iter().enumerate().map(|(i, &component_type)| {
+            let (size, align) = cx.size_and_align_of(component_type);
+            MemberDescription {
+                name: format!("__{}", i),
+                type_metadata: type_metadata(cx, component_type, self.span),
+                offset: layout.fields.offset(i),
+                size,
+                align,
+                flags: DIFlags::FlagZero,
+            }
+        }).collect()
+    }
+}
+
+fn prepare_tuple_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                    tuple_type: Ty<'tcx>,
+                                    component_types: &[Ty<'tcx>],
+                                    unique_type_id: UniqueTypeId,
+                                    span: Span)
+                                    -> RecursiveTypeDescription<'tcx> {
+    let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        tuple_type,
+        unique_type_id,
+        create_struct_stub(cx,
+                           tuple_type,
+                           &tuple_name[..],
+                           unique_type_id,
+                           NO_SCOPE_METADATA),
+        TupleMDF(TupleMemberDescriptionFactory {
+            ty: tuple_type,
+            component_types: component_types.to_vec(),
+            span,
+        })
+    )
+}
+
+//=-----------------------------------------------------------------------------
+// Unions
+//=-----------------------------------------------------------------------------
+
+struct UnionMemberDescriptionFactory<'tcx> {
+    layout: TyLayout<'tcx>,
+    variant: &'tcx ty::VariantDef,
+    span: Span,
+}
+
+impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        self.variant.fields.iter().enumerate().map(|(i, f)| {
+            let field = self.layout.field(cx, i);
+            let (size, align) = field.size_and_align();
+            MemberDescription {
+                name: f.name.to_string(),
+                type_metadata: type_metadata(cx, field.ty, self.span),
+                offset: Size::from_bytes(0),
+                size,
+                align,
+                flags: DIFlags::FlagZero,
+            }
+        }).collect()
+    }
+}
+
+fn prepare_union_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                    union_type: Ty<'tcx>,
+                                    unique_type_id: UniqueTypeId,
+                                    span: Span)
+                                    -> RecursiveTypeDescription<'tcx> {
+    let union_name = compute_debuginfo_type_name(cx, union_type, false);
+
+    let (union_def_id, variant) = match union_type.sty {
+        ty::TyAdt(def, _) => (def.did, def.non_enum_variant()),
+        _ => bug!("prepare_union_metadata on a non-ADT")
+    };
+
+    let containing_scope = get_namespace_for_item(cx, union_def_id);
+
+    let union_metadata_stub = create_union_stub(cx,
+                                                union_type,
+                                                &union_name,
+                                                unique_type_id,
+                                                containing_scope);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        union_type,
+        unique_type_id,
+        union_metadata_stub,
+        UnionMDF(UnionMemberDescriptionFactory {
+            layout: cx.layout_of(union_type),
+            variant,
+            span,
+        })
+    )
+}
+
+//=-----------------------------------------------------------------------------
+// Enums
+//=-----------------------------------------------------------------------------
+
+// Describes the members of an enum value: An enum is described as a union of
+// structs in DWARF. This MemberDescriptionFactory provides the description for
+// the members of this union; so for every variant of the given enum, this
+// factory will produce one MemberDescription (all with no name and a fixed
+// offset of zero bytes).
+struct EnumMemberDescriptionFactory<'tcx> {
+    enum_type: Ty<'tcx>,
+    layout: TyLayout<'tcx>,
+    discriminant_type_metadata: Option<DIType>,
+    containing_scope: DIScope,
+    span: Span,
+}
+
+impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        let adt = &self.enum_type.ty_adt_def().unwrap();
+        match self.layout.variants {
+            layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
+            layout::Variants::Single { index } => {
+                let (variant_type_metadata, member_description_factory) =
+                    describe_enum_variant(cx,
+                                          self.layout,
+                                          &adt.variants[index],
+                                          NoDiscriminant,
+                                          self.containing_scope,
+                                          self.span);
+
+                let member_descriptions =
+                    member_description_factory.create_member_descriptions(cx);
+
+                set_members_of_composite_type(cx,
+                                              variant_type_metadata,
+                                              &member_descriptions[..]);
+                vec![
+                    MemberDescription {
+                        name: "".to_string(),
+                        type_metadata: variant_type_metadata,
+                        offset: Size::from_bytes(0),
+                        size: self.layout.size,
+                        align: self.layout.align,
+                        flags: DIFlags::FlagZero
+                    }
+                ]
+            }
+            layout::Variants::Tagged { ref variants, .. } => {
+                let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
+                    .expect(""));
+                (0..variants.len()).map(|i| {
+                    let variant = self.layout.for_variant(cx, i);
+                    let (variant_type_metadata, member_desc_factory) =
+                        describe_enum_variant(cx,
+                                              variant,
+                                              &adt.variants[i],
+                                              discriminant_info,
+                                              self.containing_scope,
+                                              self.span);
+
+                    let member_descriptions = member_desc_factory
+                        .create_member_descriptions(cx);
+
+                    set_members_of_composite_type(cx,
+                                                  variant_type_metadata,
+                                                  &member_descriptions);
+                    MemberDescription {
+                        name: "".to_string(),
+                        type_metadata: variant_type_metadata,
+                        offset: Size::from_bytes(0),
+                        size: variant.size,
+                        align: variant.align,
+                        flags: DIFlags::FlagZero
+                    }
+                }).collect()
+            }
+            layout::Variants::NicheFilling { dataful_variant, ref niche_variants, .. } => {
+                let variant = self.layout.for_variant(cx, dataful_variant);
+                // Create a description of the non-null variant
+                let (variant_type_metadata, member_description_factory) =
+                    describe_enum_variant(cx,
+                                          variant,
+                                          &adt.variants[dataful_variant],
+                                          OptimizedDiscriminant,
+                                          self.containing_scope,
+                                          self.span);
+
+                let variant_member_descriptions =
+                    member_description_factory.create_member_descriptions(cx);
+
+                set_members_of_composite_type(cx,
+                                              variant_type_metadata,
+                                              &variant_member_descriptions[..]);
+
+                // Encode the information about the null variant in the union
+                // member's name.
+                let mut name = String::from("RUST$ENCODED$ENUM$");
+                // HACK(eddyb) the debuggers should just handle offset+size
+                // of discriminant instead of us having to recover its path.
+                // Right now it's not even going to work for `niche_start > 0`,
+                // and for multiple niche variants it only supports the first.
+                fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                                name: &mut String,
+                                                layout: TyLayout<'tcx>,
+                                                offset: Size,
+                                                size: Size) {
+                    for i in 0..layout.fields.count() {
+                        let field_offset = layout.fields.offset(i);
+                        if field_offset > offset {
+                            continue;
+                        }
+                        let inner_offset = offset - field_offset;
+                        let field = layout.field(cx, i);
+                        if inner_offset + size <= field.size {
+                            write!(name, "{}$", i).unwrap();
+                            compute_field_path(cx, name, field, inner_offset, size);
+                        }
+                    }
+                }
+                compute_field_path(cx, &mut name,
+                                   self.layout,
+                                   self.layout.fields.offset(0),
+                                   self.layout.field(cx, 0).size);
+                name.push_str(&adt.variants[*niche_variants.start()].name.as_str());
+
+                // Create the (singleton) list of descriptions of union members.
+                vec![
+                    MemberDescription {
+                        name,
+                        type_metadata: variant_type_metadata,
+                        offset: Size::from_bytes(0),
+                        size: variant.size,
+                        align: variant.align,
+                        flags: DIFlags::FlagZero
+                    }
+                ]
+            }
+        }
+    }
+}
+
+// Creates MemberDescriptions for the fields of a single enum variant.
+struct VariantMemberDescriptionFactory<'tcx> {
+    // Cloned from the layout::Struct describing the variant.
+    offsets: Vec<layout::Size>,
+    args: Vec<(String, Ty<'tcx>)>,
+    discriminant_type_metadata: Option<DIType>,
+    span: Span,
+}
+
+impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        self.args.iter().enumerate().map(|(i, &(ref name, ty))| {
+            let (size, align) = cx.size_and_align_of(ty);
+            MemberDescription {
+                name: name.to_string(),
+                type_metadata: match self.discriminant_type_metadata {
+                    Some(metadata) if i == 0 => metadata,
+                    _ => type_metadata(cx, ty, self.span)
+                },
+                offset: self.offsets[i],
+                size,
+                align,
+                flags: DIFlags::FlagZero
+            }
+        }).collect()
+    }
+}
+
+#[derive(Copy, Clone)]
+enum EnumDiscriminantInfo {
+    RegularDiscriminant(DIType),
+    OptimizedDiscriminant,
+    NoDiscriminant
+}
+
+// Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type
+// of the variant, and (3) a MemberDescriptionFactory for producing the
+// descriptions of the fields of the variant. This is a rudimentary version of a
+// full RecursiveTypeDescription.
+fn describe_enum_variant<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                   layout: layout::TyLayout<'tcx>,
+                                   variant: &'tcx ty::VariantDef,
+                                   discriminant_info: EnumDiscriminantInfo,
+                                   containing_scope: DIScope,
+                                   span: Span)
+                                   -> (DICompositeType, MemberDescriptionFactory<'tcx>) {
+    let variant_name = variant.name.as_str();
+    let unique_type_id = debug_context(cx).type_map
+                                          .borrow_mut()
+                                          .get_unique_type_id_of_enum_variant(
+                                              cx,
+                                              layout.ty,
+                                              &variant_name);
+
+    let metadata_stub = create_struct_stub(cx,
+                                           layout.ty,
+                                           &variant_name,
+                                           unique_type_id,
+                                           containing_scope);
+
+    // If this is not a univariant enum, there is also the discriminant field.
+    let (discr_offset, discr_arg) = match discriminant_info {
+        RegularDiscriminant(_) => {
+            let enum_layout = cx.layout_of(layout.ty);
+            (Some(enum_layout.fields.offset(0)),
+             Some(("RUST$ENUM$DISR".to_string(), enum_layout.field(cx, 0).ty)))
+        }
+        _ => (None, None),
+    };
+    let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
+        layout.fields.offset(i)
+    })).collect();
+
+    // Build an array of (field name, field type) pairs to be captured in the factory closure.
+    let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
+        let name = if variant.ctor_kind == CtorKind::Fn {
+            format!("__{}", i)
+        } else {
+            variant.fields[i].name.to_string()
+        };
+        (name, layout.field(cx, i).ty)
+    })).collect();
+
+    let member_description_factory =
+        VariantMDF(VariantMemberDescriptionFactory {
+            offsets,
+            args,
+            discriminant_type_metadata: match discriminant_info {
+                RegularDiscriminant(discriminant_type_metadata) => {
+                    Some(discriminant_type_metadata)
+                }
+                _ => None
+            },
+            span,
+        });
+
+    (metadata_stub, member_description_factory)
+}
+
+fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                   enum_type: Ty<'tcx>,
+                                   enum_def_id: DefId,
+                                   unique_type_id: UniqueTypeId,
+                                   span: Span)
+                                   -> RecursiveTypeDescription<'tcx> {
+    let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
+
+    let containing_scope = get_namespace_for_item(cx, enum_def_id);
+    // FIXME: This should emit actual file metadata for the enum, but we
+    // currently can't get the necessary information when it comes to types
+    // imported from other crates. Formerly we violated the ODR when performing
+    // LTO because we emitted debuginfo for the same type with varying file
+    // metadata, so as a workaround we pretend that the type comes from
+    // <unknown>
+    let file_metadata = unknown_file_metadata(cx);
+
+    let def = enum_type.ty_adt_def().unwrap();
+    let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx)
+        .zip(&def.variants)
+        .map(|(discr, v)| {
+            let token = v.name.as_str();
+            let name = CString::new(token.as_bytes()).unwrap();
+            unsafe {
+                llvm::LLVMRustDIBuilderCreateEnumerator(
+                    DIB(cx),
+                    name.as_ptr(),
+                    // FIXME: what if enumeration has i128 discriminant?
+                    discr.val as u64)
+            }
+        })
+        .collect();
+
+    let discriminant_type_metadata = |discr: layout::Primitive| {
+        let disr_type_key = (enum_def_id, discr);
+        let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
+                                                                 .borrow()
+                                                                 .get(&disr_type_key).cloned();
+        match cached_discriminant_type_metadata {
+            Some(discriminant_type_metadata) => discriminant_type_metadata,
+            None => {
+                let (discriminant_size, discriminant_align) =
+                    (discr.size(cx), discr.align(cx));
+                let discriminant_base_type_metadata =
+                    type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP);
+                let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str();
+
+                let name = CString::new(discriminant_name.as_bytes()).unwrap();
+                let discriminant_type_metadata = unsafe {
+                    llvm::LLVMRustDIBuilderCreateEnumerationType(
+                        DIB(cx),
+                        containing_scope,
+                        name.as_ptr(),
+                        file_metadata,
+                        UNKNOWN_LINE_NUMBER,
+                        discriminant_size.bits(),
+                        discriminant_align.abi_bits() as u32,
+                        create_DIArray(DIB(cx), &enumerators_metadata),
+                        discriminant_base_type_metadata)
+                };
+
+                debug_context(cx).created_enum_disr_types
+                                 .borrow_mut()
+                                 .insert(disr_type_key, discriminant_type_metadata);
+
+                discriminant_type_metadata
+            }
+        }
+    };
+
+    let layout = cx.layout_of(enum_type);
+
+    let discriminant_type_metadata = match layout.variants {
+        layout::Variants::Single { .. } |
+        layout::Variants::NicheFilling { .. } => None,
+        layout::Variants::Tagged { ref tag, .. } => {
+            Some(discriminant_type_metadata(tag.value))
+        }
+    };
+
+    match (&layout.abi, discriminant_type_metadata) {
+        (&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
+        _ => {}
+    }
+
+    let (enum_type_size, enum_type_align) = layout.size_and_align();
+
+    let enum_name = CString::new(enum_name).unwrap();
+    let unique_type_id_str = CString::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
+    ).unwrap();
+    let enum_metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateUnionType(
+        DIB(cx),
+        containing_scope,
+        enum_name.as_ptr(),
+        file_metadata,
+        UNKNOWN_LINE_NUMBER,
+        enum_type_size.bits(),
+        enum_type_align.abi_bits() as u32,
+        DIFlags::FlagZero,
+        ptr::null_mut(),
+        0, // RuntimeLang
+        unique_type_id_str.as_ptr())
+    };
+
+    return create_and_register_recursive_type_forward_declaration(
+        cx,
+        enum_type,
+        unique_type_id,
+        enum_metadata,
+        EnumMDF(EnumMemberDescriptionFactory {
+            enum_type,
+            layout,
+            discriminant_type_metadata,
+            containing_scope,
+            span,
+        }),
+    );
+
+    fn get_enum_discriminant_name(cx: &CodegenCx,
+                                  def_id: DefId)
+                                  -> InternedString {
+        cx.tcx.item_name(def_id)
+    }
+}
+
+/// Creates debug information for a composite type, that is, anything that
+/// results in a LLVM struct.
+///
+/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
+fn composite_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                     composite_type: Ty<'tcx>,
+                                     composite_type_name: &str,
+                                     composite_type_unique_id: UniqueTypeId,
+                                     member_descriptions: &[MemberDescription],
+                                     containing_scope: DIScope,
+
+                                     // Ignore source location information as long as it
+                                     // can't be reconstructed for non-local crates.
+                                     _file_metadata: DIFile,
+                                     _definition_span: Span)
+                                     -> DICompositeType {
+    // Create the (empty) struct metadata node ...
+    let composite_type_metadata = create_struct_stub(cx,
+                                                     composite_type,
+                                                     composite_type_name,
+                                                     composite_type_unique_id,
+                                                     containing_scope);
+    // ... and immediately create and add the member descriptions.
+    set_members_of_composite_type(cx,
+                                  composite_type_metadata,
+                                  member_descriptions);
+
+    return composite_type_metadata;
+}
+
+fn set_members_of_composite_type(cx: &CodegenCx,
+                                 composite_type_metadata: DICompositeType,
+                                 member_descriptions: &[MemberDescription]) {
+    // In some rare cases LLVM metadata uniquing would lead to an existing type
+    // description being used instead of a new one created in
+    // create_struct_stub. This would cause a hard to trace assertion in
+    // DICompositeType::SetTypeArray(). The following check makes sure that we
+    // get a better error message if this should happen again due to some
+    // regression.
+    {
+        let mut composite_types_completed =
+            debug_context(cx).composite_types_completed.borrow_mut();
+        if composite_types_completed.contains(&composite_type_metadata) {
+            bug!("debuginfo::set_members_of_composite_type() - \
+                  Already completed forward declaration re-encountered.");
+        } else {
+            composite_types_completed.insert(composite_type_metadata);
+        }
+    }
+
+    let member_metadata: Vec<DIDescriptor> = member_descriptions
+        .iter()
+        .map(|member_description| {
+            let member_name = member_description.name.as_bytes();
+            let member_name = CString::new(member_name).unwrap();
+            unsafe {
+                llvm::LLVMRustDIBuilderCreateMemberType(
+                    DIB(cx),
+                    composite_type_metadata,
+                    member_name.as_ptr(),
+                    unknown_file_metadata(cx),
+                    UNKNOWN_LINE_NUMBER,
+                    member_description.size.bits(),
+                    member_description.align.abi_bits() as u32,
+                    member_description.offset.bits(),
+                    member_description.flags,
+                    member_description.type_metadata)
+            }
+        })
+        .collect();
+
+    unsafe {
+        let type_array = create_DIArray(DIB(cx), &member_metadata[..]);
+        llvm::LLVMRustDICompositeTypeSetTypeArray(
+            DIB(cx), composite_type_metadata, type_array);
+    }
+}
+
+// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do
+// any caching, does not add any fields to the struct. This can be done later
+// with set_members_of_composite_type().
+fn create_struct_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                struct_type: Ty<'tcx>,
+                                struct_type_name: &str,
+                                unique_type_id: UniqueTypeId,
+                                containing_scope: DIScope)
+                                -> DICompositeType {
+    let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
+
+    let name = CString::new(struct_type_name).unwrap();
+    let unique_type_id = CString::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
+    ).unwrap();
+    let metadata_stub = unsafe {
+        // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        llvm::LLVMRustDIBuilderCreateStructType(
+            DIB(cx),
+            containing_scope,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            struct_size.bits(),
+            struct_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            ptr::null_mut(),
+            empty_array,
+            0,
+            ptr::null_mut(),
+            unique_type_id.as_ptr())
+    };
+
+    return metadata_stub;
+}
+
+fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                               union_type: Ty<'tcx>,
+                               union_type_name: &str,
+                               unique_type_id: UniqueTypeId,
+                               containing_scope: DIScope)
+                               -> DICompositeType {
+    let (union_size, union_align) = cx.size_and_align_of(union_type);
+
+    let name = CString::new(union_type_name).unwrap();
+    let unique_type_id = CString::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
+    ).unwrap();
+    let metadata_stub = unsafe {
+        // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        llvm::LLVMRustDIBuilderCreateUnionType(
+            DIB(cx),
+            containing_scope,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            union_size.bits(),
+            union_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            empty_array,
+            0, // RuntimeLang
+            unique_type_id.as_ptr())
+    };
+
+    return metadata_stub;
+}
+
+/// Creates debug information for the given global variable.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_global_var_metadata(cx: &CodegenCx,
+                                  def_id: DefId,
+                                  global: ValueRef) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
+    let tcx = cx.tcx;
+    let attrs = tcx.codegen_fn_attrs(def_id);
+
+    if attrs.flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
+        return;
+    }
+
+    let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
+    // We may want to remove the namespace scope if we're in an extern block, see:
+    // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952
+    let var_scope = get_namespace_for_item(cx, def_id);
+    let span = tcx.def_span(def_id);
+
+    let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP {
+        let loc = span_start(cx, span);
+        (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint)
+    } else {
+        (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
+    };
+
+    let is_local_to_unit = is_node_local_to_unit(cx, def_id);
+    let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx);
+    let type_metadata = type_metadata(cx, variable_type, span);
+    let var_name = tcx.item_name(def_id).to_string();
+    let var_name = CString::new(var_name).unwrap();
+    let linkage_name = if no_mangle {
+        None
+    } else {
+        let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id));
+        Some(CString::new(linkage_name.to_string()).unwrap())
+    };
+
+    let global_align = cx.align_of(variable_type);
+
+    unsafe {
+        llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
+                                                    var_scope,
+                                                    var_name.as_ptr(),
+                                                    // If null, linkage_name field is omitted,
+                                                    // which is what we want for no_mangle statics
+                                                    linkage_name.as_ref()
+                                                     .map_or(ptr::null(), |name| name.as_ptr()),
+                                                    file_metadata,
+                                                    line_number,
+                                                    type_metadata,
+                                                    is_local_to_unit,
+                                                    global,
+                                                    ptr::null_mut(),
+                                                    global_align.abi() as u32,
+        );
+    }
+}
+
+// Creates an "extension" of an existing DIScope into another file.
+pub fn extend_scope_to_file(cx: &CodegenCx,
+                            scope_metadata: DIScope,
+                            file: &syntax_pos::FileMap,
+                            defining_crate: CrateNum)
+                            -> DILexicalBlock {
+    let file_metadata = file_metadata(cx, &file.name, defining_crate);
+    unsafe {
+        llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
+            DIB(cx),
+            scope_metadata,
+            file_metadata)
+    }
+}
+
+/// Creates debug information for the given vtable, which is for the
+/// given type.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_vtable_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                        ty: ty::Ty<'tcx>,
+                                        vtable: ValueRef) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
+    let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP);
+
+    unsafe {
+        // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        let name = CString::new("vtable").unwrap();
+
+        // Create a new one each time.  We don't want metadata caching
+        // here, because each vtable will refer to a unique containing
+        // type.
+        let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
+            DIB(cx),
+            NO_SCOPE_METADATA,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            Size::from_bytes(0).bits(),
+            cx.tcx.data_layout.pointer_align.abi_bits() as u32,
+            DIFlags::FlagArtificial,
+            ptr::null_mut(),
+            empty_array,
+            0,
+            type_metadata,
+            name.as_ptr()
+        );
+
+        llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
+                                                    NO_SCOPE_METADATA,
+                                                    name.as_ptr(),
+                                                    // LLVM 3.9
+                                                    // doesn't accept
+                                                    // null here, so
+                                                    // pass the name
+                                                    // as the linkage
+                                                    // name.
+                                                    name.as_ptr(),
+                                                    unknown_file_metadata(cx),
+                                                    UNKNOWN_LINE_NUMBER,
+                                                    vtable_type,
+                                                    true,
+                                                    vtable,
+                                                    ptr::null_mut(),
+                                                    0);
+    }
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
new file mode 100644
index 00000000000..294d8cbbd93
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -0,0 +1,542 @@
+// Copyright 2012-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.
+
+// See doc.rs for documentation.
+mod doc;
+
+use self::VariableAccess::*;
+use self::VariableKind::*;
+
+use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
+use self::namespace::mangled_name_of_instance;
+use self::type_names::compute_debuginfo_type_name;
+use self::metadata::{type_metadata, file_metadata, TypeMap};
+use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
+
+use llvm;
+use llvm::{ModuleRef, ContextRef, ValueRef};
+use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
+use rustc::hir::CodegenFnAttrFlags;
+use rustc::hir::def_id::{DefId, CrateNum};
+use rustc::ty::subst::{Substs, UnpackedKind};
+
+use abi::Abi;
+use common::CodegenCx;
+use builder::Builder;
+use monomorphize::Instance;
+use rustc::ty::{self, ParamEnv, Ty, InstanceDef};
+use rustc::mir;
+use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
+use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
+
+use libc::c_uint;
+use std::cell::{Cell, RefCell};
+use std::ffi::CString;
+use std::ptr;
+
+use syntax_pos::{self, Span, Pos};
+use syntax::ast;
+use syntax::symbol::{Symbol, InternedString};
+use rustc::ty::layout::{self, LayoutOf};
+
+pub mod gdb;
+mod utils;
+mod namespace;
+mod type_names;
+pub mod metadata;
+mod create_scope_map;
+mod source_loc;
+
+pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
+pub use self::source_loc::start_emitting_source_locations;
+pub use self::metadata::create_global_var_metadata;
+pub use self::metadata::create_vtable_metadata;
+pub use self::metadata::extend_scope_to_file;
+pub use self::source_loc::set_source_location;
+
+#[allow(non_upper_case_globals)]
+const DW_TAG_auto_variable: c_uint = 0x100;
+#[allow(non_upper_case_globals)]
+const DW_TAG_arg_variable: c_uint = 0x101;
+
+/// A context object for maintaining all state needed by the debuginfo module.
+pub struct CrateDebugContext<'tcx> {
+    llcontext: ContextRef,
+    llmod: ModuleRef,
+    builder: DIBuilderRef,
+    created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>,
+    created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Primitive), DIType>>,
+
+    type_map: RefCell<TypeMap<'tcx>>,
+    namespace_map: RefCell<DefIdMap<DIScope>>,
+
+    // This collection is used to assert that composite types (structs, enums,
+    // ...) have their members only set once:
+    composite_types_completed: RefCell<FxHashSet<DIType>>,
+}
+
+impl<'tcx> CrateDebugContext<'tcx> {
+    pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> {
+        debug!("CrateDebugContext::new");
+        let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
+        // DIBuilder inherits context from the module, so we'd better use the same one
+        let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
+        CrateDebugContext {
+            llcontext,
+            llmod,
+            builder,
+            created_files: RefCell::new(FxHashMap()),
+            created_enum_disr_types: RefCell::new(FxHashMap()),
+            type_map: RefCell::new(TypeMap::new()),
+            namespace_map: RefCell::new(DefIdMap()),
+            composite_types_completed: RefCell::new(FxHashSet()),
+        }
+    }
+}
+
+pub enum FunctionDebugContext {
+    RegularContext(FunctionDebugContextData),
+    DebugInfoDisabled,
+    FunctionWithoutDebugInfo,
+}
+
+impl FunctionDebugContext {
+    pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData {
+        match *self {
+            FunctionDebugContext::RegularContext(ref data) => data,
+            FunctionDebugContext::DebugInfoDisabled => {
+                span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message());
+            }
+            FunctionDebugContext::FunctionWithoutDebugInfo => {
+                span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message());
+            }
+        }
+    }
+
+    fn debuginfo_disabled_message() -> &'static str {
+        "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
+    }
+
+    fn should_be_ignored_message() -> &'static str {
+        "debuginfo: Error trying to access FunctionDebugContext for function that should be \
+         ignored by debug info!"
+    }
+}
+
+pub struct FunctionDebugContextData {
+    fn_metadata: DISubprogram,
+    source_locations_enabled: Cell<bool>,
+    pub defining_crate: CrateNum,
+}
+
+pub enum VariableAccess<'a> {
+    // The llptr given is an alloca containing the variable's value
+    DirectVariable { alloca: ValueRef },
+    // The llptr given is an alloca containing the start of some pointer chain
+    // leading to the variable's content.
+    IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
+}
+
+pub enum VariableKind {
+    ArgumentVariable(usize /*index*/),
+    LocalVariable,
+    CapturedVariable,
+}
+
+/// Create any deferred debug metadata nodes
+pub fn finalize(cx: &CodegenCx) {
+    if cx.dbg_cx.is_none() {
+        return;
+    }
+
+    debug!("finalize");
+
+    if gdb::needs_gdb_debug_scripts_section(cx) {
+        // Add a .debug_gdb_scripts section to this compile-unit. This will
+        // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
+        // which activates the Rust pretty printers for binary this section is
+        // contained in.
+        gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
+    }
+
+    unsafe {
+        llvm::LLVMRustDIBuilderFinalize(DIB(cx));
+        llvm::LLVMRustDIBuilderDispose(DIB(cx));
+        // Debuginfo generation in LLVM by default uses a higher
+        // version of dwarf than macOS currently understands. We can
+        // instruct LLVM to emit an older version of dwarf, however,
+        // for macOS to understand. For more info see #11352
+        // This can be overridden using --llvm-opts -dwarf-version,N.
+        // Android has the same issue (#22398)
+        if cx.sess().target.target.options.is_like_osx ||
+           cx.sess().target.target.options.is_like_android {
+            llvm::LLVMRustAddModuleFlag(cx.llmod,
+                                        "Dwarf Version\0".as_ptr() as *const _,
+                                        2)
+        }
+
+        // Indicate that we want CodeView debug information on MSVC
+        if cx.sess().target.target.options.is_like_msvc {
+            llvm::LLVMRustAddModuleFlag(cx.llmod,
+                                        "CodeView\0".as_ptr() as *const _,
+                                        1)
+        }
+
+        // Prevent bitcode readers from deleting the debug info.
+        let ptr = "Debug Info Version\0".as_ptr();
+        llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _,
+                                    llvm::LLVMRustDebugMetadataVersion());
+    };
+}
+
+/// Creates the function-specific debug context.
+///
+/// Returns the FunctionDebugContext for the function which holds state needed
+/// for debug info creation. The function may also return another variant of the
+/// FunctionDebugContext enum which indicates why no debuginfo should be created
+/// for the function.
+pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                               instance: Instance<'tcx>,
+                                               sig: ty::FnSig<'tcx>,
+                                               llfn: ValueRef,
+                                               mir: &mir::Mir) -> FunctionDebugContext {
+    if cx.sess().opts.debuginfo == NoDebugInfo {
+        return FunctionDebugContext::DebugInfoDisabled;
+    }
+
+    if let InstanceDef::Item(def_id) = instance.def {
+        if cx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
+            return FunctionDebugContext::FunctionWithoutDebugInfo;
+        }
+    }
+
+    let span = mir.span;
+
+    // This can be the case for functions inlined from another crate
+    if span == syntax_pos::DUMMY_SP {
+        // FIXME(simulacrum): Probably can't happen; remove.
+        return FunctionDebugContext::FunctionWithoutDebugInfo;
+    }
+
+    let def_id = instance.def_id();
+    let containing_scope = get_containing_scope(cx, instance);
+    let loc = span_start(cx, span);
+    let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate);
+
+    let function_type_metadata = unsafe {
+        let fn_signature = get_function_signature(cx, sig);
+        llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
+    };
+
+    // Find the enclosing function, in case this is a closure.
+    let def_key = cx.tcx.def_key(def_id);
+    let mut name = def_key.disambiguated_data.data.to_string();
+
+    let enclosing_fn_def_id = cx.tcx.closure_base_def_id(def_id);
+
+    // Get_template_parameters() will append a `<...>` clause to the function
+    // name if necessary.
+    let generics = cx.tcx.generics_of(enclosing_fn_def_id);
+    let substs = instance.substs.truncate_to(cx.tcx, generics);
+    let template_parameters = get_template_parameters(cx,
+                                                      &generics,
+                                                      substs,
+                                                      file_metadata,
+                                                      &mut name);
+
+    // Get the linkage_name, which is just the symbol name
+    let linkage_name = mangled_name_of_instance(cx, instance);
+
+    let scope_line = span_start(cx, span).line;
+    let is_local_to_unit = is_node_local_to_unit(cx, def_id);
+
+    let function_name = CString::new(name).unwrap();
+    let linkage_name = CString::new(linkage_name.to_string()).unwrap();
+
+    let mut flags = DIFlags::FlagPrototyped;
+
+    let local_id = cx.tcx.hir.as_local_node_id(def_id);
+    match *cx.sess().entry_fn.borrow() {
+        Some((id, _, _)) => {
+            if local_id == Some(id) {
+                flags = flags | DIFlags::FlagMainSubprogram;
+            }
+        }
+        None => {}
+    };
+    if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited {
+        flags = flags | DIFlags::FlagNoReturn;
+    }
+
+    let fn_metadata = unsafe {
+        llvm::LLVMRustDIBuilderCreateFunction(
+            DIB(cx),
+            containing_scope,
+            function_name.as_ptr(),
+            linkage_name.as_ptr(),
+            file_metadata,
+            loc.line as c_uint,
+            function_type_metadata,
+            is_local_to_unit,
+            true,
+            scope_line as c_uint,
+            flags,
+            cx.sess().opts.optimize != config::OptLevel::No,
+            llfn,
+            template_parameters,
+            ptr::null_mut())
+    };
+
+    // Initialize fn debug context (including scope map and namespace map)
+    let fn_debug_context = FunctionDebugContextData {
+        fn_metadata,
+        source_locations_enabled: Cell::new(false),
+        defining_crate: def_id.krate,
+    };
+
+    return FunctionDebugContext::RegularContext(fn_debug_context);
+
+    fn get_function_signature<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                        sig: ty::FnSig<'tcx>) -> DIArray {
+        if cx.sess().opts.debuginfo == LimitedDebugInfo {
+            return create_DIArray(DIB(cx), &[]);
+        }
+
+        let mut signature = Vec::with_capacity(sig.inputs().len() + 1);
+
+        // Return type -- llvm::DIBuilder wants this at index 0
+        signature.push(match sig.output().sty {
+            ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+            _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
+        });
+
+        let inputs = if sig.abi == Abi::RustCall {
+            &sig.inputs()[..sig.inputs().len() - 1]
+        } else {
+            sig.inputs()
+        };
+
+        // Arguments types
+        if cx.sess().target.target.options.is_like_msvc {
+            // FIXME(#42800):
+            // There is a bug in MSDIA that leads to a crash when it encounters
+            // a fixed-size array of `u8` or something zero-sized in a
+            // function-type (see #40477).
+            // As a workaround, we replace those fixed-size arrays with a
+            // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
+            // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
+            // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
+            // This transformed type is wrong, but these function types are
+            // already inaccurate due to ABI adjustments (see #42800).
+            signature.extend(inputs.iter().map(|&t| {
+                let t = match t.sty {
+                    ty::TyArray(ct, _)
+                        if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => {
+                        cx.tcx.mk_imm_ptr(ct)
+                    }
+                    _ => t
+                };
+                type_metadata(cx, t, syntax_pos::DUMMY_SP)
+            }));
+        } else {
+            signature.extend(inputs.iter().map(|t| {
+                type_metadata(cx, t, syntax_pos::DUMMY_SP)
+            }));
+        }
+
+        if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
+            if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
+                for &argument_type in args {
+                    signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
+                }
+            }
+        }
+
+        return create_DIArray(DIB(cx), &signature[..]);
+    }
+
+    fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                         generics: &ty::Generics,
+                                         substs: &Substs<'tcx>,
+                                         file_metadata: DIFile,
+                                         name_to_append_suffix_to: &mut String)
+                                         -> DIArray
+    {
+        if substs.types().next().is_none() {
+            return create_DIArray(DIB(cx), &[]);
+        }
+
+        name_to_append_suffix_to.push('<');
+        for (i, actual_type) in substs.types().enumerate() {
+            if i != 0 {
+                name_to_append_suffix_to.push_str(",");
+            }
+
+            let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
+            // Add actual type name to <...> clause of function name
+            let actual_type_name = compute_debuginfo_type_name(cx,
+                                                               actual_type,
+                                                               true);
+            name_to_append_suffix_to.push_str(&actual_type_name[..]);
+        }
+        name_to_append_suffix_to.push('>');
+
+        // Again, only create type information if full debuginfo is enabled
+        let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
+            let names = get_parameter_names(cx, generics);
+            substs.iter().zip(names).filter_map(|(kind, name)| {
+                if let UnpackedKind::Type(ty) = kind.unpack() {
+                    let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+                    let actual_type_metadata =
+                        type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
+                    let name = CString::new(name.as_str().as_bytes()).unwrap();
+                    Some(unsafe {
+                        llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+                            DIB(cx),
+                            ptr::null_mut(),
+                            name.as_ptr(),
+                            actual_type_metadata,
+                            file_metadata,
+                            0,
+                            0)
+                    })
+                } else {
+                    None
+                }
+            }).collect()
+        } else {
+            vec![]
+        };
+
+        return create_DIArray(DIB(cx), &template_params[..]);
+    }
+
+    fn get_parameter_names(cx: &CodegenCx,
+                           generics: &ty::Generics)
+                           -> Vec<InternedString> {
+        let mut names = generics.parent.map_or(vec![], |def_id| {
+            get_parameter_names(cx, cx.tcx.generics_of(def_id))
+        });
+        names.extend(generics.params.iter().map(|param| param.name));
+        names
+    }
+
+    fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
+                                        instance: Instance<'tcx>)
+                                        -> DIScope {
+        // First, let's see if this is a method within an inherent impl. Because
+        // if yes, we want to make the result subroutine DIE a child of the
+        // subroutine's self-type.
+        let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
+            // If the method does *not* belong to a trait, proceed
+            if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
+                let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
+                    instance.substs,
+                    ty::ParamEnv::reveal_all(),
+                    &cx.tcx.type_of(impl_def_id),
+                );
+
+                // Only "class" methods are generally understood by LLVM,
+                // so avoid methods on other types (e.g. `<*mut T>::null`).
+                match impl_self_ty.sty {
+                    ty::TyAdt(def, ..) if !def.is_box() => {
+                        Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
+                    }
+                    _ => None
+                }
+            } else {
+                // For trait method impls we still use the "parallel namespace"
+                // strategy
+                None
+            }
+        });
+
+        self_type.unwrap_or_else(|| {
+            namespace::item_namespace(cx, DefId {
+                krate: instance.def_id().krate,
+                index: cx.tcx
+                         .def_key(instance.def_id())
+                         .parent
+                         .expect("get_containing_scope: missing parent?")
+            })
+        })
+    }
+}
+
+pub fn declare_local<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
+                               dbg_context: &FunctionDebugContext,
+                               variable_name: ast::Name,
+                               variable_type: Ty<'tcx>,
+                               scope_metadata: DIScope,
+                               variable_access: VariableAccess,
+                               variable_kind: VariableKind,
+                               span: Span) {
+    let cx = bx.cx;
+
+    let file = span_start(cx, span).file;
+    let file_metadata = file_metadata(cx,
+                                      &file.name,
+                                      dbg_context.get_ref(span).defining_crate);
+
+    let loc = span_start(cx, span);
+    let type_metadata = type_metadata(cx, variable_type, span);
+
+    let (argument_index, dwarf_tag) = match variable_kind {
+        ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
+        LocalVariable    |
+        CapturedVariable => (0, DW_TAG_auto_variable)
+    };
+    let align = cx.align_of(variable_type);
+
+    let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
+    match (variable_access, &[][..]) {
+        (DirectVariable { alloca }, address_operations) |
+        (IndirectVariable {alloca, address_operations}, _) => {
+            let metadata = unsafe {
+                llvm::LLVMRustDIBuilderCreateVariable(
+                    DIB(cx),
+                    dwarf_tag,
+                    scope_metadata,
+                    name.as_ptr(),
+                    file_metadata,
+                    loc.line as c_uint,
+                    type_metadata,
+                    cx.sess().opts.optimize != config::OptLevel::No,
+                    DIFlags::FlagZero,
+                    argument_index,
+                    align.abi() as u32,
+                )
+            };
+            source_loc::set_debug_location(bx,
+                InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
+            unsafe {
+                let debug_loc = llvm::LLVMGetCurrentDebugLocation(bx.llbuilder);
+                let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
+                    DIB(cx),
+                    alloca,
+                    metadata,
+                    address_operations.as_ptr(),
+                    address_operations.len() as c_uint,
+                    debug_loc,
+                    bx.llbb());
+
+                llvm::LLVMSetInstDebugLocation(bx.llbuilder, instr);
+            }
+        }
+    }
+
+    match variable_kind {
+        ArgumentVariable(_) | CapturedVariable => {
+            assert!(!dbg_context.get_ref(span).source_locations_enabled.get());
+            source_loc::set_debug_location(bx, UnknownLocation);
+        }
+        _ => { /* nothing to do */ }
+    }
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs
new file mode 100644
index 00000000000..51c45de9dc2
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs
@@ -0,0 +1,66 @@
+// 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.
+
+// Namespace Handling.
+
+use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER};
+use super::utils::{DIB, debug_context};
+use monomorphize::Instance;
+use rustc::ty;
+
+use llvm;
+use llvm::debuginfo::DIScope;
+use rustc::hir::def_id::DefId;
+use rustc::hir::map::DefPathData;
+use common::CodegenCx;
+
+use std::ffi::CString;
+use std::ptr;
+
+pub fn mangled_name_of_instance<'a, 'tcx>(
+    cx: &CodegenCx<'a, 'tcx>,
+    instance: Instance<'tcx>,
+) -> ty::SymbolName {
+     let tcx = cx.tcx;
+     tcx.symbol_name(instance)
+}
+
+pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope {
+    if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
+        return scope;
+    }
+
+    let def_key = cx.tcx.def_key(def_id);
+    let parent_scope = def_key.parent.map_or(ptr::null_mut(), |parent| {
+        item_namespace(cx, DefId {
+            krate: def_id.krate,
+            index: parent
+        })
+    });
+
+    let namespace_name = match def_key.disambiguated_data.data {
+        DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(),
+        data => data.as_interned_str().as_str()
+    };
+
+    let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
+
+    let scope = unsafe {
+        llvm::LLVMRustDIBuilderCreateNameSpace(
+            DIB(cx),
+            parent_scope,
+            namespace_name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER)
+    };
+
+    debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope);
+    scope
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
new file mode 100644
index 00000000000..eb37e7f931c
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
@@ -0,0 +1,107 @@
+// 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.
+
+use self::InternalDebugLocation::*;
+
+use super::utils::{debug_context, span_start};
+use super::metadata::UNKNOWN_COLUMN_NUMBER;
+use super::FunctionDebugContext;
+
+use llvm;
+use llvm::debuginfo::DIScope;
+use builder::Builder;
+
+use libc::c_uint;
+use std::ptr;
+use syntax_pos::{Span, Pos};
+
+/// Sets the current debug location at the beginning of the span.
+///
+/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...).
+pub fn set_source_location(
+    debug_context: &FunctionDebugContext, bx: &Builder, scope: DIScope, span: Span
+) {
+    let function_debug_context = match *debug_context {
+        FunctionDebugContext::DebugInfoDisabled => return,
+        FunctionDebugContext::FunctionWithoutDebugInfo => {
+            set_debug_location(bx, UnknownLocation);
+            return;
+        }
+        FunctionDebugContext::RegularContext(ref data) => data
+    };
+
+    let dbg_loc = if function_debug_context.source_locations_enabled.get() {
+        debug!("set_source_location: {}", bx.sess().codemap().span_to_string(span));
+        let loc = span_start(bx.cx, span);
+        InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
+    } else {
+        UnknownLocation
+    };
+    set_debug_location(bx, dbg_loc);
+}
+
+/// Enables emitting source locations for the given functions.
+///
+/// Since we don't want source locations to be emitted for the function prelude,
+/// they are disabled when beginning to codegen a new function. This functions
+/// switches source location emitting on and must therefore be called before the
+/// first real statement/expression of the function is codegened.
+pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) {
+    match *dbg_context {
+        FunctionDebugContext::RegularContext(ref data) => {
+            data.source_locations_enabled.set(true)
+        },
+        _ => { /* safe to ignore */ }
+    }
+}
+
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum InternalDebugLocation {
+    KnownLocation { scope: DIScope, line: usize, col: usize },
+    UnknownLocation
+}
+
+impl InternalDebugLocation {
+    pub fn new(scope: DIScope, line: usize, col: usize) -> InternalDebugLocation {
+        KnownLocation {
+            scope,
+            line,
+            col,
+        }
+    }
+}
+
+pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) {
+    let metadata_node = match debug_location {
+        KnownLocation { scope, line, .. } => {
+            // Always set the column to zero like Clang and GCC
+            let col = UNKNOWN_COLUMN_NUMBER;
+            debug!("setting debug location to {} {}", line, col);
+
+            unsafe {
+                llvm::LLVMRustDIBuilderCreateDebugLocation(
+                    debug_context(bx.cx).llcontext,
+                    line as c_uint,
+                    col as c_uint,
+                    scope,
+                    ptr::null_mut())
+            }
+        }
+        UnknownLocation => {
+            debug!("clearing debug location ");
+            ptr::null_mut()
+        }
+    };
+
+    unsafe {
+        llvm::LLVMSetCurrentDebugLocation(bx.llbuilder, metadata_node);
+    }
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
new file mode 100644
index 00000000000..05a74db3a6c
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs
@@ -0,0 +1,224 @@
+// 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.
+
+// Type Names for Debug Info.
+
+use common::CodegenCx;
+use rustc::hir::def_id::DefId;
+use rustc::ty::subst::Substs;
+use rustc::ty::{self, Ty};
+
+use rustc::hir;
+
+// Compute the name of the type as it should be stored in debuginfo. Does not do
+// any caching, i.e. calling the function twice with the same type will also do
+// the work twice. The `qualified` parameter only affects the first level of the
+// type name, further levels (i.e. type parameters) are always fully qualified.
+pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                             t: Ty<'tcx>,
+                                             qualified: bool)
+                                             -> String {
+    let mut result = String::with_capacity(64);
+    push_debuginfo_type_name(cx, t, qualified, &mut result);
+    result
+}
+
+// Pushes the name of the type as it should be stored in debuginfo on the
+// `output` String. See also compute_debuginfo_type_name().
+pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                          t: Ty<'tcx>,
+                                          qualified: bool,
+                                          output: &mut String) {
+    // When targeting MSVC, emit C++ style type names for compatibility with
+    // .natvis visualizers (and perhaps other existing native debuggers?)
+    let cpp_like_names = cx.sess().target.target.options.is_like_msvc;
+
+    match t.sty {
+        ty::TyBool => output.push_str("bool"),
+        ty::TyChar => output.push_str("char"),
+        ty::TyStr => output.push_str("str"),
+        ty::TyNever => output.push_str("!"),
+        ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()),
+        ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
+        ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()),
+        ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output),
+        ty::TyAdt(def, substs) => {
+            push_item_name(cx, def.did, qualified, output);
+            push_type_params(cx, substs, output);
+        },
+        ty::TyTuple(component_types) => {
+            output.push('(');
+            for &component_type in component_types {
+                push_debuginfo_type_name(cx, component_type, true, output);
+                output.push_str(", ");
+            }
+            if !component_types.is_empty() {
+                output.pop();
+                output.pop();
+            }
+            output.push(')');
+        },
+        ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
+            if !cpp_like_names {
+                output.push('*');
+            }
+            match mutbl {
+                hir::MutImmutable => output.push_str("const "),
+                hir::MutMutable => output.push_str("mut "),
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+
+            if cpp_like_names {
+                output.push('*');
+            }
+        },
+        ty::TyRef(_, inner_type, mutbl) => {
+            if !cpp_like_names {
+                output.push('&');
+            }
+            if mutbl == hir::MutMutable {
+                output.push_str("mut ");
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+
+            if cpp_like_names {
+                output.push('*');
+            }
+        },
+        ty::TyArray(inner_type, len) => {
+            output.push('[');
+            push_debuginfo_type_name(cx, inner_type, true, output);
+            output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
+            output.push(']');
+        },
+        ty::TySlice(inner_type) => {
+            if cpp_like_names {
+                output.push_str("slice<");
+            } else {
+                output.push('[');
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+
+            if cpp_like_names {
+                output.push('>');
+            } else {
+                output.push(']');
+            }
+        },
+        ty::TyDynamic(ref trait_data, ..) => {
+            if let Some(principal) = trait_data.principal() {
+                let principal = cx.tcx.normalize_erasing_late_bound_regions(
+                    ty::ParamEnv::reveal_all(),
+                    &principal,
+                );
+                push_item_name(cx, principal.def_id, false, output);
+                push_type_params(cx, principal.substs, output);
+            }
+        },
+        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+            let sig = t.fn_sig(cx.tcx);
+            if sig.unsafety() == hir::Unsafety::Unsafe {
+                output.push_str("unsafe ");
+            }
+
+            let abi = sig.abi();
+            if abi != ::abi::Abi::Rust {
+                output.push_str("extern \"");
+                output.push_str(abi.name());
+                output.push_str("\" ");
+            }
+
+            output.push_str("fn(");
+
+            let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+            if !sig.inputs().is_empty() {
+                for &parameter_type in sig.inputs() {
+                    push_debuginfo_type_name(cx, parameter_type, true, output);
+                    output.push_str(", ");
+                }
+                output.pop();
+                output.pop();
+            }
+
+            if sig.variadic {
+                if !sig.inputs().is_empty() {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push(')');
+
+            if !sig.output().is_nil() {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output(), true, output);
+            }
+        },
+        ty::TyClosure(..) => {
+            output.push_str("closure");
+        }
+        ty::TyGenerator(..) => {
+            output.push_str("generator");
+        }
+        ty::TyError |
+        ty::TyInfer(_) |
+        ty::TyProjection(..) |
+        ty::TyAnon(..) |
+        ty::TyGeneratorWitness(..) |
+        ty::TyParam(_) => {
+            bug!("debuginfo: Trying to create type name for \
+                unexpected type: {:?}", t);
+        }
+    }
+
+    fn push_item_name(cx: &CodegenCx,
+                      def_id: DefId,
+                      qualified: bool,
+                      output: &mut String) {
+        if qualified {
+            output.push_str(&cx.tcx.crate_name(def_id.krate).as_str());
+            for path_element in cx.tcx.def_path(def_id).data {
+                output.push_str("::");
+                output.push_str(&path_element.data.as_interned_str().as_str());
+            }
+        } else {
+            output.push_str(&cx.tcx.item_name(def_id).as_str());
+        }
+    }
+
+    // Pushes the type parameters in the given `Substs` to the output string.
+    // This ignores region parameters, since they can't reliably be
+    // reconstructed for items from non-local crates. For local crates, this
+    // would be possible but with inlining and LTO we have to use the least
+    // common denominator - otherwise we would run into conflicts.
+    fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                  substs: &Substs<'tcx>,
+                                  output: &mut String) {
+        if substs.types().next().is_none() {
+            return;
+        }
+
+        output.push('<');
+
+        for type_parameter in substs.types() {
+            push_debuginfo_type_name(cx, type_parameter, true, output);
+            output.push_str(", ");
+        }
+
+        output.pop();
+        output.pop();
+
+        output.push('>');
+    }
+}
diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs
new file mode 100644
index 00000000000..9d37f99cb2a
--- /dev/null
+++ b/src/librustc_codegen_llvm/debuginfo/utils.rs
@@ -0,0 +1,65 @@
+// 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::{CrateDebugContext};
+use super::namespace::item_namespace;
+
+use rustc::hir::def_id::DefId;
+use rustc::ty::DefIdTree;
+
+use llvm;
+use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
+use common::{CodegenCx};
+
+use syntax_pos::{self, Span};
+
+pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool
+{
+    // The is_local_to_unit flag indicates whether a function is local to the
+    // current compilation unit (i.e. if it is *static* in the C-sense). The
+    // *reachable* set should provide a good approximation of this, as it
+    // contains everything that might leak out of the current crate (by being
+    // externally visible or by being inlined into something externally
+    // visible). It might better to use the `exported_items` set from
+    // `driver::CrateAnalysis` in the future, but (atm) this set is not
+    // available in the codegen pass.
+    !cx.tcx.is_reachable_non_generic(def_id)
+}
+
+#[allow(non_snake_case)]
+pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
+    return unsafe {
+        llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32)
+    };
+}
+
+/// Return syntax_pos::Loc corresponding to the beginning of the span
+pub fn span_start(cx: &CodegenCx, span: Span) -> syntax_pos::Loc {
+    cx.sess().codemap().lookup_char_pos(span.lo())
+}
+
+#[inline]
+pub fn debug_context<'a, 'tcx>(cx: &'a CodegenCx<'a, 'tcx>)
+                           -> &'a CrateDebugContext<'tcx> {
+    cx.dbg_cx.as_ref().unwrap()
+}
+
+#[inline]
+#[allow(non_snake_case)]
+pub fn DIB(cx: &CodegenCx) -> DIBuilderRef {
+    cx.dbg_cx.as_ref().unwrap().builder
+}
+
+pub fn get_namespace_for_item(cx: &CodegenCx, def_id: DefId) -> DIScope {
+    item_namespace(cx, cx.tcx.parent(def_id)
+        .expect("get_namespace_for_item: missing parent?"))
+}