]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: Generate cross-crate unique type identifiers for debuginfo types.
authorMichael Woerister <michaelwoerister@posteo>
Fri, 30 May 2014 15:09:16 +0000 (17:09 +0200)
committerMichael Woerister <michaelwoerister@posteo>
Thu, 12 Jun 2014 16:39:01 +0000 (18:39 +0200)
With this change, rustc creates a unique type identifier for types in debuginfo. These type identifiers are used by LLVM to correctly handle link-time-optimization scenarios but also help rustc with dealing with inlining from other crates. For more information, see the documentation block at the top of librustc/middle/trans/debuginfo.rs.

Fixes #13681.

src/librustc/middle/trans/debuginfo.rs
src/test/auxiliary/cross_crate_debuginfo_type_uniquing.rs [new file with mode: 0644]
src/test/debuginfo/cross-crate-type-uniquing.rs [new file with mode: 0644]

index db17000abb32b188c26477794b18e29de05e22d4..33a6068fccad74cd20119168585acd873943737c 100644 (file)
@@ -122,9 +122,37 @@ struct List {
 `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. (int, int) 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::t`
+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::t`
+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).
 */
 
-
 use driver::config;
 use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
 use lib::llvm::llvm;
@@ -152,6 +180,7 @@ struct List {
 use std::ptr;
 use std::rc::{Rc, Weak};
 use std::sync::atomics;
+use syntax::util::interner::Interner;
 use syntax::codemap::{Span, Pos};
 use syntax::{abi, ast, codemap, ast_util, ast_map};
 use syntax::owned_slice::OwnedSlice;
@@ -166,7 +195,6 @@ struct List {
 static DW_ATE_boolean: c_uint = 0x02;
 static DW_ATE_float: c_uint = 0x04;
 static DW_ATE_signed: c_uint = 0x05;
-// static DW_ATE_signed_char: c_uint = 0x06;
 static DW_ATE_unsigned: c_uint = 0x07;
 static DW_ATE_unsigned_char: c_uint = 0x08;
 
@@ -174,15 +202,370 @@ struct List {
 //  Public Interface of debuginfo module
 //=-------------------------------------------------------------------------------------------------
 
+#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)]
+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::t. The
+// TypeMap is responsible for creating UniqueTypeIds.
+struct TypeMap {
+    // The UniqueTypeIds created so far
+    unique_id_interner: Interner<Rc<String>>,
+    // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
+    unique_id_to_metadata: HashMap<UniqueTypeId, DIType>,
+    // A map from ty::type_id() to debuginfo metadata. This is a N:1 mapping.
+    type_to_metadata: HashMap<uint, DIType>,
+    // A map from ty::type_id() to UniqueTypeId. This is a N:1 mapping.
+    type_to_unique_id: HashMap<uint, UniqueTypeId>
+}
+
+impl TypeMap {
+
+    fn new() -> TypeMap {
+        TypeMap {
+            unique_id_interner: Interner::new(),
+            type_to_metadata: HashMap::new(),
+            unique_id_to_metadata: HashMap::new(),
+            type_to_unique_id: HashMap::new(),
+        }
+    }
+
+    // Adds a ty::t to metadata mapping to the TypeMap. The method will fail if the mapping already
+    // exists.
+    fn register_type_with_metadata(&mut self,
+                                   cx: &CrateContext,
+                                   type_: ty::t,
+                                   metadata: DIType) {
+        if !self.type_to_metadata.insert(ty::type_id(type_), metadata) {
+            cx.sess().bug(format!("Type metadata for ty::t '{}' is already in the TypeMap!",
+                                  ppaux::ty_to_str(cx.tcx(), type_)).as_slice());
+        }
+    }
+
+    // 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,
+                                        cx: &CrateContext,
+                                        unique_type_id: UniqueTypeId,
+                                        metadata: DIType) {
+        if !self.unique_id_to_metadata.insert(unique_type_id, metadata) {
+            let unique_type_id_str = self.get_unique_type_id_as_string(unique_type_id);
+            cx.sess().bug(format!("Type metadata for unique id '{}' is already in the TypeMap!",
+                                  unique_type_id_str.as_slice()).as_slice());
+        }
+    }
+
+    fn find_metadata_for_type(&self, type_: ty::t) -> Option<DIType> {
+        self.type_to_metadata.find_copy(&ty::type_id(type_))
+    }
+
+    fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
+        self.unique_id_to_metadata.find_copy(&unique_type_id)
+    }
+
+    // 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) -> Rc<String> {
+        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(&mut self, cx: &CrateContext, type_: ty::t) -> UniqueTypeId {
+
+        // basic type           -> {:name of the type:}
+        // tuple                -> {tuple_(:param-uid:)*}
+        // struct               -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
+        // enum                 -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
+        // enum variant         -> {variant_:variant-name:_:enum-uid:}
+        // reference (&)        -> {& :pointee-uid:}
+        // mut reference (&mut) -> {&mut :pointee-uid:}
+        // ptr (*)              -> {* :pointee-uid:}
+        // mut ptr (*mut)       -> {*mut :pointee-uid:}
+        // unique ptr (~)       -> {~ :pointee-uid:}
+        // @-ptr (@)            -> {@ :pointee-uid:}
+        // sized vec ([T, ..x]) -> {[:size:] :element-uid:}
+        // vec slice (&[T])     -> {&<mut> [] :element-uid:}
+        // trait (~ | &[mut] T) -> {:sigil: trait_:svh: / :node-id:_<(:param-uid:),*> }
+        // closure              -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
+        //                             :return-type-uid: : (:bounds:)*}
+        // function             -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
+        //                             :return-type-uid:}
+
+        match self.type_to_unique_id.find_copy(&ty::type_id(type_)) {
+            Some(unique_type_id) => return unique_type_id,
+            None => { /* generate one */}
+        };
+
+        let mut unique_type_id = String::with_capacity(256);
+        unique_type_id.push_char('{');
+
+        match ty::get(type_).sty {
+            ty::ty_nil                |
+            ty::ty_bot                |
+            ty::ty_bool               |
+            ty::ty_char               |
+            ty::ty_str                |
+            ty::ty_int(_)             |
+            ty::ty_uint(_)            |
+            ty::ty_float(_) => {
+                unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
+            },
+            ty::ty_enum(def_id, ref substs) => {
+                unique_type_id.push_str("enum ");
+                from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
+            },
+            ty::ty_struct(def_id, ref substs) => {
+                unique_type_id.push_str("struct ");
+                from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
+            },
+            ty::ty_tup(ref component_types) => {
+                unique_type_id.push_str("tuple ");
+                for &component_type in component_types.iter() {
+                    let component_type_id = self.get_unique_type_id_of_type(cx, component_type);
+                    let component_type_id = self.get_unique_type_id_as_string(component_type_id);
+                    unique_type_id.push_str(component_type_id.as_slice());
+                }
+            },
+            ty::ty_box(inner_type) => {
+                unique_type_id.push_char('@');
+                let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+                let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+                unique_type_id.push_str(inner_type_id.as_slice());
+            },
+            ty::ty_uniq(inner_type) => {
+                unique_type_id.push_char('~');
+                let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+                let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+                unique_type_id.push_str(inner_type_id.as_slice());
+            },
+            ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+                unique_type_id.push_char('*');
+                if mutbl == ast::MutMutable {
+                    unique_type_id.push_str("mut");
+                }
+
+                let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+                let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+                unique_type_id.push_str(inner_type_id.as_slice());
+            },
+            ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+                unique_type_id.push_char('&');
+                if mutbl == ast::MutMutable {
+                    unique_type_id.push_str("mut");
+                }
+
+                let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+                let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+                unique_type_id.push_str(inner_type_id.as_slice());
+            },
+            ty::ty_vec(ty::mt { ty: inner_type, mutbl }, optional_length) => {
+                match optional_length {
+                    Some(len) => {
+                        unique_type_id.push_str(format!("[{}]", len).as_slice());
+                    }
+                    None => {
+                        unique_type_id.push_char('&');
+
+                        if mutbl == ast::MutMutable {
+                           unique_type_id.push_str("mut");
+                        }
+
+                        unique_type_id.push_str("[]");
+                    }
+                };
+
+                let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+                let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+                unique_type_id.push_str(inner_type_id.as_slice());
+            },
+            ty::ty_trait(ref trait_data) => {
+                match trait_data.store {
+                    ty::UniqTraitStore => unique_type_id.push_char('~'),
+                    ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut"),
+                    ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_char('&'),
+                };
+
+                unique_type_id.push_str("trait ");
+
+                from_def_id_and_substs(self,
+                                       cx,
+                                       trait_data.def_id,
+                                       &trait_data.substs,
+                                       &mut unique_type_id);
+            },
+            ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
+                if fn_style == ast::UnsafeFn {
+                    unique_type_id.push_str("unsafe ");
+                }
+
+                unique_type_id.push_str(abi.name());
+
+                unique_type_id.push_str(" fn(");
+
+                for &parameter_type in sig.inputs.iter() {
+                    let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
+                    let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
+                    unique_type_id.push_str(parameter_type_id.as_slice());
+                    unique_type_id.push_char(',');
+                }
+
+                if sig.variadic {
+                    unique_type_id.push_str("...");
+                }
+
+                unique_type_id.push_str(")->");
+                let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
+                let return_type_id = self.get_unique_type_id_as_string(return_type_id);
+                unique_type_id.push_str(return_type_id.as_slice());
+            },
+            ty::ty_closure(box ty::ClosureTy { fn_style,
+                                               onceness,
+                                               store,
+                                               ref bounds,
+                                               ref sig }) => {
+                if fn_style == ast::UnsafeFn {
+                    unique_type_id.push_str("unsafe ");
+                }
+
+                if onceness == ast::Once {
+                    unique_type_id.push_str("once ");
+                }
+
+                match store {
+                    ty::UniqTraitStore => unique_type_id.push_str("~|"),
+                    ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut|"),
+                    ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_str("&|"),
+                };
+
+                for &parameter_type in sig.inputs.iter() {
+                    let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
+                    let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
+                    unique_type_id.push_str(parameter_type_id.as_slice());
+                    unique_type_id.push_char(',');
+                }
+
+                if sig.variadic {
+                    unique_type_id.push_str("...");
+                }
+
+                unique_type_id.push_str("|->");
+
+                let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
+                let return_type_id = self.get_unique_type_id_as_string(return_type_id);
+                unique_type_id.push_str(return_type_id.as_slice());
+
+                unique_type_id.push_char(':');
+
+                for bound in bounds.iter() {
+                    match bound {
+                        ty::BoundStatic => unique_type_id.push_str("'static"),
+                        ty::BoundSend => unique_type_id.push_str("Send"),
+                        ty::BoundSized => unique_type_id.push_str("Sized"),
+                        ty::BoundCopy => unique_type_id.push_str("Copy"),
+                        ty::BoundShare => unique_type_id.push_str("Share"),
+                    };
+                    unique_type_id.push_char('+');
+                }
+            },
+            _ => {
+                cx.sess().bug(format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
+                                      ppaux::ty_to_str(cx.tcx(), type_).as_slice(),
+                                      ty::get(type_).sty).as_slice())
+            }
+        };
+
+        unique_type_id.push_char('}');
+
+        // Trim to size before storing permanently
+        unique_type_id.shrink_to_fit();
+
+        let key = self.unique_id_interner.intern(Rc::new(unique_type_id));
+        self.type_to_unique_id.insert(ty::type_id(type_), UniqueTypeId(key));
+
+        return UniqueTypeId(key);
+
+        fn from_def_id_and_substs(type_map: &mut TypeMap,
+                                  cx: &CrateContext,
+                                  def_id: ast::DefId,
+                                  substs: &subst::Substs,
+                                  output: &mut String) {
+            use std::num::ToStrRadix;
+
+            // First, find out the 'real' def_id of the type. Items inlined from other crates have
+            // to be mapped back to their source.
+            let source_def_id = if def_id.krate == ast::LOCAL_CRATE {
+                match cx.external_srcs.borrow().find_copy(&def_id.node) {
+                    Some(source_def_id) => {
+                        // The given def_id identifies the inlined copy of a type definition,
+                        // let's take the source of the copy
+                        source_def_id
+                    }
+                    None => def_id
+                }
+            } else {
+                def_id
+            };
+
+            // Get the crate hash as first part of the identifier
+            let crate_hash = if source_def_id.krate == ast::LOCAL_CRATE {
+                cx.link_meta.crate_hash.clone()
+            } else {
+                cx.sess().cstore.get_crate_hash(source_def_id.krate)
+            };
+
+            output.push_str(crate_hash.as_str());
+            output.push_str("/");
+            output.push_str(def_id.node.to_str_radix(16).as_slice());
+
+            // Maybe check that there is no self type here
+
+            if substs.tps.len() > 0 {
+                output.push_char('<');
+
+                for &type_parameter in substs.tps.iter() {
+                    let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter);
+                    let param_type_id = type_map.get_unique_type_id_as_string(param_type_id);
+                    output.push_str(param_type_id.as_slice());
+                    output.push_char(',');
+                }
+
+                output.push_char('>');
+            }
+        }
+    }
+
+    // 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(&mut self,
+                                          cx: &CrateContext,
+                                          enum_type: ty::t,
+                                          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)
+                                               .as_slice(),
+                                           variant_name);
+        let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
+        UniqueTypeId(interner_key)
+    }
+}
+
+
 /// A context object for maintaining all state needed by the debuginfo module.
 pub struct CrateDebugContext {
     llcontext: ContextRef,
     builder: DIBuilderRef,
     current_debug_location: Cell<DebugLocation>,
     created_files: RefCell<HashMap<String, DIFile>>,
-    created_types: RefCell<HashMap<uint, DIType>>,
     created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
+
+    type_map: RefCell<TypeMap>,
     namespace_map: RefCell<HashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
+
     // This collection is used to assert that composite types (structs, enums, ...) have their
     // members only set once:
     composite_types_completed: RefCell<HashSet<DIType>>,
@@ -199,8 +582,8 @@ pub fn new(llmod: ModuleRef) -> CrateDebugContext {
             builder: builder,
             current_debug_location: Cell::new(UnknownLocation),
             created_files: RefCell::new(HashMap::new()),
-            created_types: RefCell::new(HashMap::new()),
             created_enum_disr_types: RefCell::new(HashMap::new()),
+            type_map: RefCell::new(TypeMap::new()),
             namespace_map: RefCell::new(HashMap::new()),
             composite_types_completed: RefCell::new(HashSet::new()),
         };
@@ -1255,7 +1638,8 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
 // more information.
 enum RecursiveTypeDescription {
     UnfinishedMetadata {
-        cache_id: uint,
+        unfinished_type: ty::t,
+        unique_type_id: UniqueTypeId,
         metadata_stub: DICompositeType,
         llvm_type: Type,
         file_metadata: DIFile,
@@ -1264,6 +1648,31 @@ enum RecursiveTypeDescription {
     FinalMetadata(DICompositeType)
 }
 
+fn create_and_register_recursive_type_forward_declaration(
+    cx: &CrateContext,
+    unfinished_type: ty::t,
+    unique_type_id: UniqueTypeId,
+    metadata_stub: DICompositeType,
+    llvm_type: Type,
+    file_metadata: DIFile,
+    member_description_factory: MemberDescriptionFactory)
+ -> RecursiveTypeDescription {
+
+    // 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(cx, unique_type_id, metadata_stub);
+    type_map.register_type_with_metadata(cx, unfinished_type, metadata_stub);
+
+    UnfinishedMetadata {
+        unfinished_type: unfinished_type,
+        unique_type_id: unique_type_id,
+        metadata_stub: metadata_stub,
+        llvm_type: llvm_type,
+        file_metadata: file_metadata,
+        member_description_factory: member_description_factory,
+    }
+}
+
 impl RecursiveTypeDescription {
     // 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.
@@ -1271,15 +1680,27 @@ fn finalize(&self, cx: &CrateContext) -> DICompositeType {
         match *self {
             FinalMetadata(metadata) => metadata,
             UnfinishedMetadata {
-                cache_id,
+                unfinished_type,
+                unique_type_id,
                 metadata_stub,
                 llvm_type,
                 file_metadata,
                 ref member_description_factory
             } => {
-                // Insert the stub into the cache in order to allow recursive references ...
-                debug_context(cx).created_types.borrow_mut()
-                                 .insert(cache_id, metadata_stub);
+                // 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() {
+                        cx.sess().bug(format!("Forward declaration of potentially recursive type \
+                                              '{}' was not found in TypeMap!",
+                                              ppaux::ty_to_str(cx.tcx(), unfinished_type))
+                                      .as_slice());
+                    }
+                }
 
                 // ... then create the member descriptions ...
                 let member_descriptions = member_description_factory.create_member_descriptions(cx);
@@ -1349,6 +1770,7 @@ fn prepare_struct_metadata(cx: &CrateContext,
                            struct_type: ty::t,
                            def_id: ast::DefId,
                            substs: &subst::Substs,
+                           unique_type_id: UniqueTypeId,
                            span: Span)
                         -> RecursiveTypeDescription {
     let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
@@ -1362,23 +1784,26 @@ fn prepare_struct_metadata(cx: &CrateContext,
     let struct_metadata_stub = create_struct_stub(cx,
                                                   struct_llvm_type,
                                                   struct_name.as_slice(),
+                                                  unique_type_id,
                                                   containing_scope,
                                                   file_metadata,
                                                   definition_span);
 
     let fields = ty::struct_fields(cx.tcx(), def_id, substs);
 
-    UnfinishedMetadata {
-        cache_id: cache_id_for_type(struct_type),
-        metadata_stub: struct_metadata_stub,
-        llvm_type: struct_llvm_type,
-        file_metadata: file_metadata,
-        member_description_factory: StructMDF(StructMemberDescriptionFactory {
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        struct_type,
+        unique_type_id,
+        struct_metadata_stub,
+        struct_llvm_type,
+        file_metadata,
+        StructMDF(StructMemberDescriptionFactory {
             fields: fields,
             is_simd: ty::type_is_simd(cx.tcx(), struct_type),
             span: span,
-        }),
-    }
+        })
+    )
 }
 
 
@@ -1409,6 +1834,7 @@ fn create_member_descriptions(&self, cx: &CrateContext)
 fn prepare_tuple_metadata(cx: &CrateContext,
                           tuple_type: ty::t,
                           component_types: &[ty::t],
+                          unique_type_id: UniqueTypeId,
                           span: Span)
                        -> RecursiveTypeDescription {
     let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
@@ -1417,21 +1843,24 @@ fn prepare_tuple_metadata(cx: &CrateContext,
     let loc = span_start(cx, span);
     let file_metadata = file_metadata(cx, loc.file.name.as_slice());
 
-    UnfinishedMetadata {
-        cache_id: cache_id_for_type(tuple_type),
-        metadata_stub: create_struct_stub(cx,
-                                          tuple_llvm_type,
-                                          tuple_name.as_slice(),
-                                          file_metadata,
-                                          file_metadata,
-                                          span),
-        llvm_type: tuple_llvm_type,
-        file_metadata: file_metadata,
-        member_description_factory: TupleMDF(TupleMemberDescriptionFactory {
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        tuple_type,
+        unique_type_id,
+        create_struct_stub(cx,
+                           tuple_llvm_type,
+                           tuple_name.as_slice(),
+                           unique_type_id,
+                           file_metadata,
+                           file_metadata,
+                           span),
+        tuple_llvm_type,
+        file_metadata,
+        TupleMDF(TupleMemberDescriptionFactory {
             component_types: Vec::from_slice(component_types),
             span: span,
         })
-    }
+    )
 }
 
 
@@ -1444,6 +1873,7 @@ fn prepare_tuple_metadata(cx: &CrateContext,
 // variant of the given enum, this factory will produce one MemberDescription (all with no name and
 // a fixed offset of zero bytes).
 struct EnumMemberDescriptionFactory {
+    enum_type: ty::t,
     type_rep: Rc<adt::Repr>,
     variants: Rc<Vec<Rc<ty::VariantInfo>>>,
     discriminant_type_metadata: Option<DIType>,
@@ -1465,6 +1895,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                     .map(|(i, struct_def)| {
                         let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
                             describe_enum_variant(cx,
+                                                  self.enum_type,
                                                   struct_def,
                                                   &**self.variants.get(i),
                                                   discriminant_info,
@@ -1497,6 +1928,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                 } else {
                     let (variant_type_metadata, variant_llvm_type, member_description_factory) =
                         describe_enum_variant(cx,
+                                              self.enum_type,
                                               struct_def,
                                               &**self.variants.get(0),
                                               NoDiscriminant,
@@ -1551,11 +1983,19 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                     offset: FixedMemberOffset { bytes: 0 },
                 };
 
+                let unique_type_id = debug_context(cx).type_map
+                                                      .borrow_mut()
+                                                      .get_unique_type_id_of_enum_variant(
+                                                          cx,
+                                                          self.enum_type,
+                                                          non_null_variant_name.get());
+
                 // Now we can create the metadata of the artificial struct
                 let artificial_struct_metadata =
                     composite_type_metadata(cx,
                                             artificial_struct_llvm_type,
                                             non_null_variant_name.get(),
+                                            unique_type_id,
                                             &[sole_struct_member_description],
                                             self.containing_scope,
                                             self.file_metadata,
@@ -1581,6 +2021,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                 // Create a description of the non-null variant
                 let (variant_type_metadata, variant_llvm_type, member_description_factory) =
                     describe_enum_variant(cx,
+                                          self.enum_type,
                                           struct_def,
                                           &**self.variants.get(nndiscr as uint),
                                           OptimizedDiscriminant(ptrfield),
@@ -1654,6 +2095,7 @@ enum EnumDiscriminantInfo {
 // (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(cx: &CrateContext,
+                         enum_type: ty::t,
                          struct_def: &adt::Struct,
                          variant_info: &ty::VariantInfo,
                          discriminant_info: EnumDiscriminantInfo,
@@ -1678,9 +2120,19 @@ fn describe_enum_variant(cx: &CrateContext,
         codemap::DUMMY_SP
     };
 
+    let variant_name = token::get_ident(variant_info.name);
+    let variant_name = variant_name.get();
+    let unique_type_id = debug_context(cx).type_map
+                                          .borrow_mut()
+                                          .get_unique_type_id_of_enum_variant(
+                                              cx,
+                                              enum_type,
+                                              variant_name);
+
     let metadata_stub = create_struct_stub(cx,
                                            variant_llvm_type,
-                                           token::get_ident(variant_info.name).get(),
+                                           variant_name,
+                                           unique_type_id,
                                            containing_scope,
                                            file_metadata,
                                            variant_definition_span);
@@ -1724,6 +2176,7 @@ fn describe_enum_variant(cx: &CrateContext,
 fn prepare_enum_metadata(cx: &CrateContext,
                          enum_type: ty::t,
                          enum_def_id: ast::DefId,
+                         unique_type_id: UniqueTypeId,
                          span: Span)
                       -> RecursiveTypeDescription {
     let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
@@ -1804,10 +2257,14 @@ fn prepare_enum_metadata(cx: &CrateContext,
 
     let enum_llvm_type = type_of::type_of(cx, enum_type);
     let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
-    let unique_id = generate_unique_type_id("DI_ENUM_");
+
+    let unique_type_id_str = debug_context(cx)
+                             .type_map
+                             .borrow()
+                             .get_unique_type_id_as_string(unique_type_id);
 
     let enum_metadata = enum_name.as_slice().with_c_str(|enum_name| {
-        unique_id.as_slice().with_c_str(|unique_id| {
+        unique_type_id_str.as_slice().with_c_str(|unique_type_id_str| {
             unsafe {
                 llvm::LLVMDIBuilderCreateUnionType(
                 DIB(cx),
@@ -1820,17 +2277,20 @@ fn prepare_enum_metadata(cx: &CrateContext,
                 0, // Flags
                 ptr::null(),
                 0, // RuntimeLang
-                unique_id)
+                unique_type_id_str)
             }
         })
     });
 
-    return UnfinishedMetadata {
-        cache_id: cache_id_for_type(enum_type),
-        metadata_stub: enum_metadata,
-        llvm_type: enum_llvm_type,
-        file_metadata: file_metadata,
-        member_description_factory: EnumMDF(EnumMemberDescriptionFactory {
+    return create_and_register_recursive_type_forward_declaration(
+        cx,
+        enum_type,
+        unique_type_id,
+        enum_metadata,
+        enum_llvm_type,
+        file_metadata,
+        EnumMDF(EnumMemberDescriptionFactory {
+            enum_type: enum_type,
             type_rep: type_rep.clone(),
             variants: variants,
             discriminant_type_metadata: discriminant_type_metadata,
@@ -1838,7 +2298,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
             file_metadata: file_metadata,
             span: span,
         }),
-    };
+    );
 
     fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
         let name = if def_id.krate == ast::LOCAL_CRATE {
@@ -1857,6 +2317,7 @@ fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::I
 fn composite_type_metadata(cx: &CrateContext,
                            composite_llvm_type: Type,
                            composite_type_name: &str,
+                           composite_type_unique_id: UniqueTypeId,
                            member_descriptions: &[MemberDescription],
                            containing_scope: DIScope,
                            file_metadata: DIFile,
@@ -1866,10 +2327,10 @@ fn composite_type_metadata(cx: &CrateContext,
     let composite_type_metadata = create_struct_stub(cx,
                                                      composite_llvm_type,
                                                      composite_type_name,
+                                                     composite_type_unique_id,
                                                      containing_scope,
                                                      file_metadata,
                                                      definition_span);
-
     // ... and immediately create and add the member descriptions.
     set_members_of_composite_type(cx,
                                   composite_type_metadata,
@@ -1944,6 +2405,7 @@ fn set_members_of_composite_type(cx: &CrateContext,
 fn create_struct_stub(cx: &CrateContext,
                       struct_llvm_type: Type,
                       struct_type_name: &str,
+                      unique_type_id: UniqueTypeId,
                       containing_scope: DIScope,
                       file_metadata: DIFile,
                       definition_span: Span)
@@ -1951,13 +2413,12 @@ fn create_struct_stub(cx: &CrateContext,
     let loc = span_start(cx, definition_span);
     let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
 
-    // We assign unique IDs to the type stubs so LLVM metadata uniquing does not reuse instances
-    // where we don't want it.
-    let unique_id = generate_unique_type_id("DI_STRUCT_");
-
-    return unsafe {
+    let unique_type_id_str = debug_context(cx).type_map
+                                              .borrow()
+                                              .get_unique_type_id_as_string(unique_type_id);
+    let metadata_stub = unsafe {
         struct_type_name.with_c_str(|name| {
-            unique_id.as_slice().with_c_str(|unique_id| {
+            unique_type_id_str.as_slice().with_c_str(|unique_type_id| {
                 // LLVMDIBuilderCreateStructType() 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), []);
@@ -1975,23 +2436,23 @@ fn create_struct_stub(cx: &CrateContext,
                     empty_array,
                     0,
                     ptr::null(),
-                    unique_id)
+                    unique_type_id)
             })
         })
     };
+
+    return metadata_stub;
 }
 
-fn boxed_type_metadata(cx: &CrateContext,
-                       content_type_name: Option<&str>,
-                       content_llvm_type: Type,
-                       content_type_metadata: DIType,
-                       span: Span)
-                    -> DICompositeType {
-    let box_type_name = match content_type_name {
-        Some(content_type_name) => format!("Boxed<{}>", content_type_name),
-        None                    => "BoxedType".to_string()
-    };
+fn at_box_metadata(cx: &CrateContext,
+                   content_type: ty::t,
+                   unique_type_id: UniqueTypeId) -> DIType {
+    let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
+    let content_type_name = content_type_name.as_slice();
+    let content_llvm_type = type_of::type_of(cx, content_type);
+    let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
 
+    let box_type_name = format!("Boxed<{}>", content_type_name);
     let box_llvm_type = Type::at_box(cx, content_llvm_type);
     let member_llvm_types = box_llvm_type.field_types();
     assert!(box_layout_is_correct(cx,
@@ -2035,17 +2496,18 @@ fn boxed_type_metadata(cx: &CrateContext,
         }
     ];
 
-    let loc = span_start(cx, span);
+    let loc = span_start(cx, codemap::DUMMY_SP);
     let file_metadata = file_metadata(cx, loc.file.name.as_slice());
 
     return composite_type_metadata(
         cx,
         box_llvm_type,
         box_type_name.as_slice(),
+        unique_type_id,
         member_descriptions,
         file_metadata,
         file_metadata,
-        span);
+        codemap::DUMMY_SP);
 
     // Unfortunately, we cannot assert anything but the correct types here---and not whether the
     // 'next' and 'prev' pointers are in the correct order.
@@ -2062,6 +2524,7 @@ fn box_layout_is_correct(cx: &CrateContext,
     }
 }
 
+
 fn fixed_vec_metadata(cx: &CrateContext,
                       element_type: ty::t,
                       len: uint,
@@ -2089,18 +2552,19 @@ fn fixed_vec_metadata(cx: &CrateContext,
     };
 }
 
-fn vec_metadata(cx: &CrateContext,
-                element_type: ty::t,
-                span: Span)
-             -> DICompositeType {
+fn heap_vec_metadata(cx: &CrateContext,
+                     vec_type: ty::t,
+                     element_type: ty::t,
+                     unique_type_id: UniqueTypeId,
+                     span: Span)
+                  -> DICompositeType {
 
     let element_type_metadata = type_metadata(cx, element_type, span);
     let element_llvm_type = type_of::type_of(cx, element_type);
     let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
 
     let vec_llvm_type = Type::vec(cx, &element_llvm_type);
-    let vec_type_name = format!("[{}]",
-                                ppaux::ty_to_str(cx.tcx(), element_type));
+    let vec_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
     let vec_type_name = vec_type_name.as_slice();
 
     let member_llvm_types = vec_llvm_type.field_types();
@@ -2145,6 +2609,7 @@ fn vec_metadata(cx: &CrateContext,
         cx,
         vec_llvm_type,
         vec_type_name,
+        unique_type_id,
         member_descriptions,
         file_metadata,
         file_metadata,
@@ -2154,6 +2619,7 @@ fn vec_metadata(cx: &CrateContext,
 fn vec_slice_metadata(cx: &CrateContext,
                       vec_type: ty::t,
                       element_type: ty::t,
+                      unique_type_id: UniqueTypeId,
                       span: Span)
                    -> DICompositeType {
 
@@ -2196,6 +2662,7 @@ fn vec_slice_metadata(cx: &CrateContext,
         cx,
         slice_llvm_type,
         slice_type_name.as_slice(),
+        unique_type_id,
         member_descriptions,
         file_metadata,
         file_metadata,
@@ -2218,8 +2685,7 @@ fn subroutine_type_metadata(cx: &CrateContext,
     let loc = span_start(cx, span);
     let file_metadata = file_metadata(cx, loc.file.name.as_slice());
 
-    let mut signature_metadata: Vec<DIType> =
-        Vec::with_capacity(signature.inputs.len() + 1);
+    let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
 
     // return type
     signature_metadata.push(match ty::get(signature.output).sty {
@@ -2245,7 +2711,8 @@ fn trait_metadata(cx: &CrateContext,
                   trait_type: ty::t,
                   substs: &subst::Substs,
                   trait_store: ty::TraitStore,
-                  _: &ty::BuiltinBounds)
+                  _: &ty::BuiltinBounds,
+                  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
@@ -2272,49 +2739,55 @@ fn trait_metadata(cx: &CrateContext,
     composite_type_metadata(cx,
                             trait_llvm_type,
                             name.as_slice(),
+                            unique_type_id,
                             [],
                             containing_scope,
                             file_metadata,
                             definition_span)
 }
 
+
 fn type_metadata(cx: &CrateContext,
                  t: ty::t,
                  usage_site_span: Span)
               -> DIType {
-    let cache_id = cache_id_for_type(t);
-
-    match debug_context(cx).created_types.borrow().find(&cache_id) {
-        Some(type_metadata) => return *type_metadata,
-        None => ()
-    }
-
-    fn create_pointer_to_box_metadata(cx: &CrateContext,
-                                      pointer_type: ty::t,
-                                      type_in_box: ty::t)
-                                   -> DIType {
-        let content_type_name = ppaux::ty_to_str(cx.tcx(), type_in_box);
-        let content_type_name = content_type_name.as_slice();
-        let content_llvm_type = type_of::type_of(cx, type_in_box);
-        let content_type_metadata = type_metadata(
-            cx,
-            type_in_box,
-            codemap::DUMMY_SP);
-
-        let box_metadata = boxed_type_metadata(
-            cx,
-            Some(content_type_name),
-            content_llvm_type,
-            content_type_metadata,
-            codemap::DUMMY_SP);
-
-        pointer_type_metadata(cx, pointer_type, box_metadata)
-    }
+    // Get the unique type id of this type.
+    let unique_type_id = {
+        let mut type_map = debug_context(cx).type_map.borrow_mut();
+        match type_map.find_metadata_for_type(t) {
+            Some(metadata) => {
+                return metadata;
+            },
+            None => {
+                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) => {
+                        type_map.register_type_with_metadata(cx, 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: {:?}", ty::get(t));
 
+    macro_rules! return_if_created_in_meantime(
+        () => (
+            match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
+                Some(metadata) => return metadata,
+                None => { /* proceed normally */ }
+            };
+        )
+    )
+
     let sty = &ty::get(t).sty;
-    let type_metadata = match *sty {
+    let (type_metadata, should_already_be_stored_in_typemap) = match *sty {
         ty::ty_nil      |
         ty::ty_bot      |
         ty::ty_bool     |
@@ -2322,50 +2795,73 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
         ty::ty_int(_)   |
         ty::ty_uint(_)  |
         ty::ty_float(_) => {
-            basic_type_metadata(cx, t)
+            (basic_type_metadata(cx, t), false)
         }
         ty::ty_enum(def_id, _) => {
-            prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
+            let is_c_style_enum = match *adt::represent_type(cx, t) {
+                adt::CEnum(..) => true,
+                _ => false
+            };
+
+            (prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx),
+             !is_c_style_enum)
         }
-        ty::ty_box(typ) => {
-            create_pointer_to_box_metadata(cx, t, typ)
+        ty::ty_box(pointee_type) => {
+            let box_content_metadata = at_box_metadata(cx, pointee_type, unique_type_id);
+            return_if_created_in_meantime!();
+            (pointer_type_metadata(cx, t, box_content_metadata), false)
         }
-        ty::ty_vec(ref mt, Some(len)) => fixed_vec_metadata(cx, mt.ty, len, usage_site_span),
-        ty::ty_uniq(typ) => {
-            match ty::get(typ).sty {
+        ty::ty_vec(ref mt, Some(len)) => {
+            (fixed_vec_metadata(cx, mt.ty, len, usage_site_span), false)
+        }
+        ty::ty_uniq(pointee_type) => {
+            (match ty::get(pointee_type).sty {
                 ty::ty_vec(ref mt, None) => {
-                    let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
+                    let vec_metadata = heap_vec_metadata(cx,
+                                                         pointee_type,
+                                                         mt.ty,
+                                                         unique_type_id,
+                                                         usage_site_span);
+                    return_if_created_in_meantime!();
                     pointer_type_metadata(cx, t, vec_metadata)
                 }
                 ty::ty_str => {
                     let i8_t = ty::mk_i8();
-                    let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
+                    let vec_metadata = heap_vec_metadata(cx,
+                                                         pointee_type,
+                                                         i8_t,
+                                                         unique_type_id,
+                                                         usage_site_span);
                     pointer_type_metadata(cx, t, vec_metadata)
                 }
                 _ => {
-                    let pointee = type_metadata(cx, typ, usage_site_span);
-                    pointer_type_metadata(cx, t, pointee)
+                    let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
+                    return_if_created_in_meantime!();
+                    pointer_type_metadata(cx, t, pointee_metadata)
                 }
-            }
+            }, false)
         }
         ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
-            match ty::get(mt.ty).sty {
-                ty::ty_vec(ref mt, None) => vec_slice_metadata(cx, t, mt.ty, usage_site_span),
+            (match ty::get(mt.ty).sty {
+                ty::ty_vec(ref mt, None) => {
+                    vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
+                }
                 ty::ty_str => {
                     let i8_t = ty::mk_i8();
-                    vec_slice_metadata(cx, t, i8_t, usage_site_span)
+                    vec_slice_metadata(cx, t, i8_t, unique_type_id, usage_site_span)
                 }
                 _ => {
                     let pointee = type_metadata(cx, mt.ty, usage_site_span);
+                    return_if_created_in_meantime!();
                     pointer_type_metadata(cx, t, pointee)
                 }
-            }
+            }, false)
         }
         ty::ty_bare_fn(ref barefnty) => {
-            subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
+            (subroutine_type_metadata(cx, &barefnty.sig, usage_site_span), false)
         }
         ty::ty_closure(ref closurety) => {
-            subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
+            (subroutine_type_metadata(cx, &closurety.sig, usage_site_span), false)
         }
         ty::ty_trait(box ty::TyTrait {
                 def_id,
@@ -2373,25 +2869,60 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
                 store,
                 ref bounds
             }) => {
-            trait_metadata(cx, def_id, t, substs, store, bounds)
+            (trait_metadata(cx, def_id, t, substs, store, bounds, unique_type_id), false)
         }
         ty::ty_struct(def_id, ref substs) => {
-            prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
+            let struct_metadata = prepare_struct_metadata(cx,
+                                                          t,
+                                                          def_id,
+                                                          substs,
+                                                          unique_type_id,
+                                                          usage_site_span).finalize(cx);
+            (struct_metadata, true)
         }
         ty::ty_tup(ref elements) => {
-            prepare_tuple_metadata(cx,
-                                   t,
-                                   elements.as_slice(),
-                                   usage_site_span).finalize(cx)
+            let tuple_metadata = prepare_tuple_metadata(cx,
+                                                        t,
+                                                        elements.as_slice(),
+                                                        unique_type_id,
+                                                        usage_site_span).finalize(cx);
+            (tuple_metadata, true)
         }
         _ => {
-            cx.sess().bug(format!("debuginfo: unexpected type in \
-                                   type_metadata: {:?}",
+            cx.sess().bug(format!("debuginfo: unexpected type in type_metadata: {:?}",
                                   sty).as_slice())
         }
     };
 
-    debug_context(cx).created_types.borrow_mut().insert(cache_id, type_metadata);
+    {
+        let mut type_map = debug_context(cx).type_map.borrow_mut();
+
+        if should_already_be_stored_in_typemap {
+            // Make sure that we already have a TypeMap entry entry for the ty::t.
+            if type_map.find_metadata_for_type(t).is_none() {
+                let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+                let error_message = format!("Expected type metadata for ty::t '{}' to already be in
+                                            the TypeMap but it was not (unique type id = {})",
+                                            ppaux::ty_to_str(cx.tcx(), t),
+                                            unique_type_id_str.as_slice());
+                cx.sess().span_bug(usage_site_span, error_message.as_slice());
+            }
+
+            // Also make sure that we already have a TypeMap entry entry for the unique type id.
+            if type_map.find_metadata_for_unique_id(unique_type_id).is_none() {
+                let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+                let error_message = format!("Expected type metadata for unique type id '{}' to
+                                            already be in the TypeMap but it was not. (ty::t = {})",
+                                            unique_type_id_str.as_slice(),
+                                            ppaux::ty_to_str(cx.tcx(), t));
+                cx.sess().span_bug(usage_site_span, error_message.as_slice());
+            }
+        } else {
+            type_map.register_type_with_metadata(cx, t, type_metadata);
+            type_map.register_unique_id_with_metadata(cx, unique_type_id, type_metadata);
+        }
+    }
+
     type_metadata
 }
 
@@ -2446,20 +2977,6 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
 //  Utility Functions
 //=-------------------------------------------------------------------------------------------------
 
-fn cache_id_for_type(t: ty::t) -> uint {
-    ty::type_id(t)
-}
-
-// Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and
-// `prepare_enum_metadata()`.
-fn generate_unique_type_id(prefix: &'static str) -> String {
-    unsafe {
-        static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
-        format!("{}{}", prefix,
-                unique_id_counter.fetch_add(1, atomics::SeqCst))
-    }
-}
-
 /// Return codemap::Loc corresponding to the beginning of the span
 fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
     cx.sess().codemap().lookup_char_pos(span.lo)
diff --git a/src/test/auxiliary/cross_crate_debuginfo_type_uniquing.rs b/src/test/auxiliary/cross_crate_debuginfo_type_uniquing.rs
new file mode 100644 (file)
index 0000000..f4bc723
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2013-2014 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.
+
+// no-prefer-dynamic
+#![crate_type = "rlib"]
+// compile-flags:-g
+
+struct S1;
+
+impl S1 {
+    fn f(&mut self) { }
+}
+
+
+struct S2;
+
+impl S2 {
+    fn f(&mut self) { }
+}
diff --git a/src/test/debuginfo/cross-crate-type-uniquing.rs b/src/test/debuginfo/cross-crate-type-uniquing.rs
new file mode 100644 (file)
index 0000000..47de06c
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2013-2014 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.
+
+// ignore-android: FIXME(#10381)
+
+// aux-build:cross_crate_debuginfo_type_uniquing.rs
+extern crate cross_crate_debuginfo_type_uniquing;
+
+// no-prefer-dynamic
+// compile-flags:-g -Zlto
+
+pub struct C;
+pub fn p() -> C {
+    C
+}
+
+fn main() { }
\ No newline at end of file