about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@gmail>2013-09-11 16:37:43 +0200
committerMichael Woerister <michaelwoerister@gmail>2013-09-15 12:28:25 +0200
commitf85da506a88265f7e541ef548c644527f7510945 (patch)
treecd59766b28a7400689e2f92a3ea8711a52bc68a7 /src
parent206cc59f46f6e7b4f91ebe8fdfe4dae83a1fa703 (diff)
downloadrust-f85da506a88265f7e541ef548c644527f7510945.tar.gz
rust-f85da506a88265f7e541ef548c644527f7510945.zip
debuginfo: Support for recursive types.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/lib/llvm.rs4
-rw-r--r--src/librustc/middle/trans/debuginfo.rs556
-rw-r--r--src/rustllvm/RustWrapper.cpp30
3 files changed, 416 insertions, 174 deletions
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 75dabc8478f..9a9015179f6 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -2118,6 +2118,10 @@ pub mod llvm {
                                             -> ValueRef;
 
         #[fast_ffi]
+        pub fn LLVMDICompositeTypeSetTypeArray(CompositeType: ValueRef, TypeArray: ValueRef);
+
+
+        #[fast_ffi]
         pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
 
         #[fast_ffi]
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 5f4b169a482..f26d8365092 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -84,9 +84,6 @@ static DW_ATE_signed_char: c_uint = 0x06;
 static DW_ATE_unsigned: c_uint = 0x07;
 static DW_ATE_unsigned_char: c_uint = 0x08;
 
-
-
-
 //=-------------------------------------------------------------------------------------------------
 //  Public Interface of debuginfo module
 //=-------------------------------------------------------------------------------------------------
@@ -1058,80 +1055,176 @@ fn pointer_type_metadata(cx: &mut CrateContext,
     return ptr_metadata;
 }
 
-fn struct_metadata(cx: &mut CrateContext,
-                   struct_type: ty::t,
-                   def_id: ast::DefId,
-                   substs: &ty::substs,
-                   span: Span)
-                -> DICompositeType {
+fn prepare_struct_metadata(cx: &mut CrateContext,
+                           struct_type: ty::t,
+                           def_id: ast::DefId,
+                           substs: &ty::substs,
+                           span: Span)
+                        -> RecursiveTypeDescription {
     let struct_name = ppaux::ty_to_str(cx.tcx, struct_type);
-    debug!("struct_metadata: %s", struct_name);
+    println(fmt!("struct_metadata: %s", struct_name));
 
     let struct_llvm_type = type_of::type_of(cx, struct_type);
+    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id, span);
+
+    let file_name = span_start(cx, definition_span).file.name;
+    let file_metadata = file_metadata(cx, file_name);
+
+    let loc = span_start(cx, definition_span);
+
+    let (composite_size, composite_align) = size_and_align_of(cx, struct_llvm_type);
+
+    let struct_metadata_stub = create_struct_stub(cx,
+                                                  struct_llvm_type,
+                                                  struct_name,
+                                                  containing_scope,
+                                                  file_metadata,
+                                                  definition_span);
+
     let fields = ty::struct_fields(cx.tcx, def_id, substs);
-    let field_descriptions = do fields.map |field| {
-        let name = if field.ident.name == special_idents::unnamed_field.name {
-            @""
-        } else {
-            token::ident_to_str(&field.ident)
-        };
 
-        MemberDescription {
-            name: name,
-            llvm_type: type_of::type_of(cx, field.mt.ty),
-            type_metadata: type_metadata(cx, field.mt.ty, span),
+    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: |cx| {
+            do fields.map |field| {
+                let name = if field.ident.name == special_idents::unnamed_field.name {
+                    @""
+                } else {
+                    token::ident_to_str(&field.ident)
+                };
+
+                MemberDescription {
+                    name: name,
+                    llvm_type: type_of::type_of(cx, field.mt.ty),
+                    type_metadata: type_metadata(cx, field.mt.ty, span),
+                    offset: ComputedMemberOffset,
+                }
+            }
         }
-    };
+    }
+}
 
-    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id, span);
+enum RecursiveTypeDescription {
+    UnfinishedMetadata {
+        cache_id: uint,
+        metadata_stub: DICompositeType,
+        llvm_type: Type,
+        file_metadata: DIFile,
+        member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription],
+    },
+    FinalMetadata(DICompositeType)
+}
 
-    let file_name = span_start(cx, definition_span).file.name;
-    let file_metadata = file_metadata(cx, file_name);
+impl RecursiveTypeDescription {
 
-    return composite_type_metadata(
-        cx,
-        struct_llvm_type,
-        struct_name,
-        field_descriptions,
-        containing_scope,
-        file_metadata,
-        definition_span);
+    fn metadata(&self) -> DICompositeType {
+        match *self {
+            UnfinishedMetadata { metadata_stub, _ } => metadata_stub,
+            FinalMetadata(metadata) => metadata
+        }
+    }
+
+    fn finalize(&self, cx: &mut CrateContext) -> DICompositeType {
+        match *self {
+            FinalMetadata(metadata) => metadata,
+            UnfinishedMetadata {
+                cache_id,
+                metadata_stub,
+                llvm_type,
+                file_metadata,
+                member_description_factory
+            } => {
+                // Insert the stub into the cache in order to allow recursive references ...
+                debug_context(cx).created_types.insert(cache_id, metadata_stub);
+
+                // ... then create the member descriptions
+                let member_descriptions = member_description_factory(cx);
+                let member_metadata: ~[DIDescriptor] = member_descriptions
+                    .iter()
+                    .enumerate()
+                    .map(|(i, member_description)| {
+                        let (member_size,
+                             member_align) = size_and_align_of(cx, member_description.llvm_type);
+                        let member_offset = match member_description.offset {
+                            FixedMemberOffset { bytes } => bytes,
+                            ComputedMemberOffset => {
+                                machine::llelement_offset(cx, llvm_type, i)
+                            }
+                        };
+
+                        do member_description.name.with_c_str |member_name| {
+                            unsafe {
+                                llvm::LLVMDIBuilderCreateMemberType(
+                                    DIB(cx),
+                                    metadata_stub,
+                                    member_name,
+                                    file_metadata,
+                                    0 as c_uint,
+                                    bytes_to_bits(member_size),
+                                    bytes_to_bits(member_align),
+                                    bytes_to_bits(member_offset),
+                                    0,
+                                    member_description.type_metadata)
+                            }
+                        }
+                    })
+                    .collect();
+
+                unsafe {
+                    let type_array = create_DIArray(DIB(cx), member_metadata);
+                    llvm::LLVMDICompositeTypeSetTypeArray(metadata_stub, type_array);
+                }
+
+                metadata_stub
+            }
+        }
+    }
 }
 
-fn tuple_metadata(cx: &mut CrateContext,
-                  tuple_type: ty::t,
-                  component_types: &[ty::t],
-                  span: Span)
-               -> DICompositeType {
+fn prepare_tuple_metadata(cx: &mut CrateContext,
+                          tuple_type: ty::t,
+                          component_types: &[ty::t],
+                          span: Span)
+                       -> RecursiveTypeDescription {
     let tuple_name = ppaux::ty_to_str(cx.tcx, tuple_type);
     let tuple_llvm_type = type_of::type_of(cx, tuple_type);
 
-    let component_descriptions = do component_types.map |&component_type| {
-        MemberDescription {
-            name: @"",
-            llvm_type: type_of::type_of(cx, component_type),
-            type_metadata: type_metadata(cx, component_type, span),
-        }
-    };
-
     let loc = span_start(cx, span);
     let file_metadata = file_metadata(cx, loc.file.name);
-
-    return composite_type_metadata(
-        cx,
-        tuple_llvm_type,
-        tuple_name,
-        component_descriptions,
-        file_metadata,
-        file_metadata,
-        span);
+    // Needs to be copied for closure below :(
+    let component_types = component_types.to_owned();
+
+    UnfinishedMetadata {
+        cache_id: cache_id_for_type(tuple_type),
+        metadata_stub: create_struct_stub(cx,
+                                          tuple_llvm_type,
+                                          tuple_name,
+                                          file_metadata,
+                                          file_metadata,
+                                          span),
+        llvm_type: tuple_llvm_type,
+        file_metadata: file_metadata,
+        member_description_factory: |cx| {
+            do component_types.map |&component_type| {
+                MemberDescription {
+                    name: @"",
+                    llvm_type: type_of::type_of(cx, component_type),
+                    type_metadata: type_metadata(cx, component_type, span),
+                    offset: ComputedMemberOffset,
+                }
+            }
+        }
+    }
 }
 
-fn enum_metadata(cx: &mut CrateContext,
-                 enum_type: ty::t,
-                 enum_def_id: ast::DefId,
-                 span: Span)
-              -> DIType {
+fn prepare_enum_metadata(cx: &mut CrateContext,
+                         enum_type: ty::t,
+                         enum_def_id: ast::DefId,
+                         span: Span)
+                      -> RecursiveTypeDescription {
     let enum_name = ppaux::ty_to_str(cx.tcx, enum_type);
 
     let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx,
@@ -1143,16 +1236,18 @@ fn enum_metadata(cx: &mut CrateContext,
     // For empty enums there is an early exit. Just describe it as an empty struct with the
     // appropriate type name
     if ty::type_is_empty(cx.tcx, enum_type) {
-        return composite_type_metadata(cx,
-                                       Type::nil(),
-                                       enum_name,
-                                       [],
-                                       file_metadata,
-                                       file_metadata,
-                                       definition_span);
+        let empty_type_metadata = composite_type_metadata(cx,
+                                                          Type::nil(),
+                                                          enum_name,
+                                                          [],
+                                                          containing_scope,
+                                                          file_metadata,
+                                                          definition_span);
+
+        return FinalMetadata(empty_type_metadata);
     }
 
-    // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
+    // Prepare some data (llvm type, size, align, etc) about the discriminant. This data will be
     // needed in all of the following cases.
     let discriminant_llvm_type = Type::enum_discrim(cx);
     let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
@@ -1160,7 +1255,7 @@ fn enum_metadata(cx: &mut CrateContext,
     assert!(Type::enum_discrim(cx) == cx.int_type);
     let discriminant_base_type_metadata = type_metadata(cx, ty::mk_int(), codemap::dummy_sp());
 
-    let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
+    let variants = ty::enum_variants(cx.tcx, enum_def_id);
 
     let enumerators_metadata: ~[DIDescriptor] = variants
         .iter()
@@ -1196,55 +1291,34 @@ fn enum_metadata(cx: &mut CrateContext,
 
     let type_rep = adt::represent_type(cx, enum_type);
 
-    match *type_rep {
+    return match *type_rep {
         adt::CEnum(*) => {
-            return discriminant_type_metadata;
+            FinalMetadata(discriminant_type_metadata)
         }
         adt::Univariant(ref struct_def, _) => {
             assert!(variants.len() == 1);
-            return adt_struct_metadata(cx,
-                                       struct_def,
-                                       variants[0],
-                                       None,
-                                       containing_scope,
-                                       file_metadata,
-                                       span);
+            let (metadata_stub,
+                 variant_llvm_type,
+                 member_description_factory) = describe_variant(cx,
+                                                                struct_def,
+                                                                variants[0],
+                                                                None,
+                                                                containing_scope,
+                                                                file_metadata,
+                                                                span);
+            UnfinishedMetadata {
+                cache_id: cache_id_for_type(enum_type),
+                metadata_stub: metadata_stub,
+                llvm_type: variant_llvm_type,
+                file_metadata: file_metadata,
+                member_description_factory: member_description_factory
+            }
         }
-        adt::General(ref struct_defs) => {
-            let variants_member_metadata: ~[DIDescriptor] = do struct_defs
-                .iter()
-                .enumerate()
-                .map |(i, struct_def)| {
-                    let variant_type_metadata = adt_struct_metadata(
-                        cx,
-                        struct_def,
-                        variants[i],
-                        Some(discriminant_type_metadata),
-                        containing_scope,
-                        file_metadata,
-                        span);
-
-                    do "".with_c_str |name| {
-                        unsafe {
-                            llvm::LLVMDIBuilderCreateMemberType(
-                                DIB(cx),
-                                containing_scope,
-                                name,
-                                file_metadata,
-                                loc.line as c_uint,
-                                bytes_to_bits(struct_def.size as uint),
-                                bytes_to_bits(struct_def.align as uint),
-                                bytes_to_bits(0),
-                                0,
-                                variant_type_metadata)
-                        }
-                    }
-            }.collect();
-
+        adt::General(_) => {
             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);
 
-            return do enum_name.with_c_str |enum_name| {
+            let enum_metadata = do enum_name.with_c_str |enum_name| {
                 unsafe {
                     llvm::LLVMDIBuilderCreateUnionType(
                     DIB(cx),
@@ -1255,55 +1329,85 @@ fn enum_metadata(cx: &mut CrateContext,
                     bytes_to_bits(enum_type_size),
                     bytes_to_bits(enum_type_align),
                     0, // Flags
-                    create_DIArray(DIB(cx), variants_member_metadata),
+                    ptr::null(),
                     0) // RuntimeLang
             }};
+
+            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: |cx| {
+                    // Capture type_rep, so we don't have to copy the struct_defs array
+                    let struct_defs = match *type_rep {
+                        adt::General(ref struct_defs) => struct_defs,
+                        _ => cx.sess.bug("unreachable")
+                    };
+
+                    do struct_defs
+                        .iter()
+                        .enumerate()
+                        .map |(i, struct_def)| {
+                            let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
+                                describe_variant(cx,
+                                                 struct_def,
+                                                 variants[i],
+                                                 Some(discriminant_type_metadata),
+                                                 containing_scope,
+                                                 file_metadata,
+                                                 span);
+
+                            let member_descriptions = member_desc_factory(cx);
+
+                            set_members_of_composite_type(cx,
+                                                          variant_type_metadata,
+                                                          variant_llvm_type,
+                                                          member_descriptions,
+                                                          file_metadata,
+                                                          codemap::dummy_sp());
+                            MemberDescription {
+                                name: @"",
+                                llvm_type: variant_llvm_type,
+                                type_metadata: variant_type_metadata,
+                                offset: FixedMemberOffset { bytes: 0 },
+                            }
+                    }.collect()
+                }
+            }
         }
         adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
-            return adt_struct_metadata(cx,
-                                       struct_def,
-                                       variants[nndiscr],
-                                       None,
-                                       containing_scope,
-                                       file_metadata,
-                                       span);
-        }
-    }
-
-    fn adt_struct_metadata(cx: &mut CrateContext,
-                                  struct_def: &adt::Struct,
-                                  variant_info: &ty::VariantInfo,
-                                  discriminant_type_metadata: Option<DIType>,
-                                  containing_scope: DIScope,
-                                  file_metadata: DIFile,
-                                  span: Span)
-                               -> DICompositeType {
-        // Get the argument names from the enum variant info
-        let mut arg_names = match variant_info.arg_names {
-            Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
-            None => do variant_info.args.map |_| { @"" }
-        };
-
-        // If this is not a univariant enum, there is also the (unnamed) discriminant field
-        if discriminant_type_metadata.is_some() {
-            arg_names.insert(0, @"");
+            let (metadata_stub,
+                 variant_llvm_type,
+                 member_description_factory) = describe_variant(cx,
+                                                                struct_def,
+                                                                variants[nndiscr],
+                                                                None,
+                                                                containing_scope,
+                                                                file_metadata,
+                                                                span);
+            UnfinishedMetadata {
+                cache_id: cache_id_for_type(enum_type),
+                metadata_stub: metadata_stub,
+                llvm_type: variant_llvm_type,
+                file_metadata: file_metadata,
+                member_description_factory: member_description_factory
+            }
         }
+    };
 
-        let arg_descriptions : ~[MemberDescription] =
-            do struct_def.fields.iter().enumerate().map |(i, &ty)| {
-                MemberDescription {
-                    name: arg_names[i].clone(),
-                    llvm_type: type_of::type_of(cx, ty),
-                    type_metadata: match discriminant_type_metadata {
-                        Some(metadata) if i == 0 => metadata,
-                        _                        => type_metadata(cx, ty, span)
-                    }
-                }
-            }.collect();
-
+    fn describe_variant(cx: &mut CrateContext,
+                        struct_def: &adt::Struct,
+                        variant_info: &ty::VariantInfo,
+                        discriminant_type_metadata: Option<DIType>,
+                        containing_scope: DIScope,
+                        file_metadata: DIFile,
+                        span: Span)
+                     -> (DICompositeType, Type, @fn(&mut CrateContext) -> ~[MemberDescription]) {
         let variant_name = token::ident_to_str(&variant_info.name);
-        let variant_llvm_type = Type::struct_(arg_descriptions.map(|d| d.llvm_type),
+        let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
                                               struct_def.packed);
+        // Could some consistency checks here: size, align, field count, discr type
 
         // Find the source code location of the variant's definition
         let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
@@ -1321,21 +1425,58 @@ fn enum_metadata(cx: &mut CrateContext,
             codemap::dummy_sp()
         };
 
-        return composite_type_metadata(
-            cx,
-            variant_llvm_type,
-            variant_name,
-            arg_descriptions,
-            containing_scope,
-            file_metadata,
-            variant_definition_span);
+        let metadata_stub = create_struct_stub(cx,
+                                               variant_llvm_type,
+                                               variant_name,
+                                               containing_scope,
+                                               file_metadata,
+                                               variant_definition_span);
+
+        // Get the argument names from the enum variant info
+        let mut arg_names = match variant_info.arg_names {
+            Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
+            None => do variant_info.args.map |_| { @"" }
+        };
+
+        // If this is not a univariant enum, there is also the (unnamed) discriminant field
+        if discriminant_type_metadata.is_some() {
+            arg_names.insert(0, @"");
+        }
+
+        // Build an array of (field name, field type) pairs to be captured in the factory closure.
+        let args: ~[(@str, ty::t)] = arg_names.iter()
+            .zip(struct_def.fields.iter())
+            .map(|(&s, &t)| (s, t))
+            .collect();
+
+        let member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription] = |cx| {
+            do args.iter().enumerate().map |(i, &(name, ty))| {
+                MemberDescription {
+                    name: name,
+                    llvm_type: type_of::type_of(cx, ty),
+                    type_metadata: match discriminant_type_metadata {
+                        Some(metadata) if i == 0 => metadata,
+                        _ => type_metadata(cx, ty, span)
+                    },
+                    offset: ComputedMemberOffset,
+                }
+            }.collect()
+        };
+
+        (metadata_stub, variant_llvm_type, member_description_factory)
     }
 }
 
+enum MemberOffset {
+    FixedMemberOffset{ bytes: uint },
+    ComputedMemberOffset
+}
+
 struct MemberDescription {
     name: @str,
     llvm_type: Type,
     type_metadata: DIType,
+    offset: MemberOffset,
 }
 
 /// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
@@ -1350,21 +1491,58 @@ fn composite_type_metadata(cx: &mut CrateContext,
                            definition_span: Span)
                         -> DICompositeType {
     let loc = span_start(cx, definition_span);
-
     let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type);
 
+    let composite_type_metadata = do composite_type_name.with_c_str |name| {
+        unsafe {
+            llvm::LLVMDIBuilderCreateStructType(
+                DIB(cx),
+                containing_scope,
+                name,
+                file_metadata,
+                loc.line as c_uint,
+                bytes_to_bits(composite_size),
+                bytes_to_bits(composite_align),
+                0,
+                ptr::null(),
+                ptr::null(),
+                0,
+                ptr::null())
+    }};
+
+    set_members_of_composite_type(cx,
+                                  composite_type_metadata,
+                                  composite_llvm_type,
+                                  member_descriptions,
+                                  file_metadata,
+                                  definition_span);
+
+    return composite_type_metadata;
+}
+
+fn set_members_of_composite_type(cx: &mut CrateContext,
+                                 composite_type_metadata: DICompositeType,
+                                 composite_llvm_type: Type,
+                                 member_descriptions: &[MemberDescription],
+                                 file_metadata: DIFile,
+                                 definition_span: Span) {
+    let loc = span_start(cx, definition_span);
+
     let member_metadata: ~[DIDescriptor] = member_descriptions
         .iter()
         .enumerate()
         .map(|(i, member_description)| {
             let (member_size, member_align) = size_and_align_of(cx, member_description.llvm_type);
-            let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
+            let member_offset = match member_description.offset {
+                FixedMemberOffset { bytes } => bytes,
+                ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
+            };
 
             do member_description.name.with_c_str |member_name| {
                 unsafe {
                     llvm::LLVMDIBuilderCreateMemberType(
                         DIB(cx),
-                        file_metadata,
+                        composite_type_metadata,
                         member_name,
                         file_metadata,
                         loc.line as c_uint,
@@ -1378,7 +1556,25 @@ fn composite_type_metadata(cx: &mut CrateContext,
         })
         .collect();
 
-    return do composite_type_name.with_c_str |name| {
+    unsafe {
+        let type_array = create_DIArray(DIB(cx), member_metadata);
+        llvm::LLVMDICompositeTypeSetTypeArray(composite_type_metadata, type_array);
+    }
+}
+
+// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any caching, does not
+// add any fields to the struct. This can be done later with LLVMDICompositeTypeSetTypeArray().
+fn create_struct_stub(cx: &mut CrateContext,
+                      struct_llvm_type: Type,
+                      struct_type_name: &str,
+                      containing_scope: DIScope,
+                      file_metadata: DIFile,
+                      definition_span: Span)
+                   -> DICompositeType {
+    let loc = span_start(cx, definition_span);
+    let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
+
+    return do struct_type_name.with_c_str |name| {
         unsafe {
             llvm::LLVMDIBuilderCreateStructType(
                 DIB(cx),
@@ -1386,11 +1582,11 @@ fn composite_type_metadata(cx: &mut CrateContext,
                 name,
                 file_metadata,
                 loc.line as c_uint,
-                bytes_to_bits(composite_size),
-                bytes_to_bits(composite_align),
+                bytes_to_bits(struct_size),
+                bytes_to_bits(struct_align),
                 0,
                 ptr::null(),
-                create_DIArray(DIB(cx), member_metadata),
+                ptr::null(),
                 0,
                 ptr::null())
     }};
@@ -1420,26 +1616,31 @@ fn boxed_type_metadata(cx: &mut CrateContext,
             name: @"refcnt",
             llvm_type: member_llvm_types[0],
             type_metadata: type_metadata(cx, int_type, codemap::dummy_sp()),
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"tydesc",
             llvm_type: member_llvm_types[1],
             type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"prev",
             llvm_type: member_llvm_types[2],
             type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"next",
             llvm_type: member_llvm_types[3],
             type_metadata: nil_pointer_type_metadata,
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"val",
             llvm_type: member_llvm_types[4],
-            type_metadata: content_type_metadata
+            type_metadata: content_type_metadata,
+            offset: ComputedMemberOffset,
         }
     ];
 
@@ -1526,16 +1727,19 @@ fn vec_metadata(cx: &mut CrateContext,
             name: @"fill",
             llvm_type: member_llvm_types[0],
             type_metadata: int_type_metadata,
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"alloc",
             llvm_type: member_llvm_types[1],
             type_metadata: int_type_metadata,
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"elements",
             llvm_type: member_llvm_types[2],
             type_metadata: array_type_metadata,
+            offset: ComputedMemberOffset,
         }
     ];
 
@@ -1558,7 +1762,6 @@ fn boxed_vec_metadata(cx: &mut CrateContext,
                       element_type: ty::t,
                       span: Span)
                    -> DICompositeType {
-
     let element_llvm_type = type_of::type_of(cx, element_type);
     let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
     let vec_type_name: &str = fmt!("[%s]", ppaux::ty_to_str(cx.tcx, element_type));
@@ -1593,11 +1796,13 @@ fn vec_slice_metadata(cx: &mut CrateContext,
             name: @"data_ptr",
             llvm_type: member_llvm_types[0],
             type_metadata: type_metadata(cx, data_ptr_type, span),
+            offset: ComputedMemberOffset,
         },
         MemberDescription {
             name: @"size_in_bytes",
             llvm_type: member_llvm_types[1],
             type_metadata: type_metadata(cx, ty::mk_uint(), span),
+            offset: ComputedMemberOffset,
         },
     ];
 
@@ -1708,12 +1913,16 @@ fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
     return metadata;
 }
 
+fn cache_id_for_type(t: ty::t) -> uint {
+    ty::type_id(t)
+}
+
 fn type_metadata(cx: &mut CrateContext,
                  t: ty::t,
                  usage_site_span: Span)
               -> DIType {
-    let type_id = ty::type_id(t);
-    match debug_context(cx).created_types.find(&type_id) {
+    let cache_id = cache_id_for_type(t);
+    match debug_context(cx).created_types.find(&cache_id) {
         Some(type_metadata) => return *type_metadata,
         None => ()
     }
@@ -1722,7 +1931,6 @@ fn type_metadata(cx: &mut CrateContext,
                                       pointer_type: ty::t,
                                       type_in_box: ty::t)
                                    -> DIType {
-
         let content_type_name: &str = ppaux::ty_to_str(cx.tcx, type_in_box);
         let content_llvm_type = type_of::type_of(cx, type_in_box);
         let content_type_metadata = type_metadata(
@@ -1773,7 +1981,7 @@ fn type_metadata(cx: &mut CrateContext,
             }
         },
         ty::ty_enum(def_id, _) => {
-            enum_metadata(cx, t, def_id, usage_site_span)
+            prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
         },
         ty::ty_box(ref mt) => {
             create_pointer_to_box_metadata(cx, t, mt.ty)
@@ -1819,10 +2027,10 @@ fn type_metadata(cx: &mut CrateContext,
             trait_metadata(cx, def_id, t, substs, trait_store, mutability, bounds, usage_site_span)
         },
         ty::ty_struct(def_id, ref substs) => {
-            struct_metadata(cx, t, def_id, substs, usage_site_span)
+            prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
         },
         ty::ty_tup(ref elements) => {
-            tuple_metadata(cx, t, *elements, usage_site_span)
+            prepare_tuple_metadata(cx, t, *elements, usage_site_span).finalize(cx)
         },
         ty::ty_opaque_box => {
             create_pointer_to_box_metadata(cx, t, ty::mk_nil())
@@ -1830,7 +2038,7 @@ fn type_metadata(cx: &mut CrateContext,
         _ => cx.sess.bug(fmt!("debuginfo: unexpected type in type_metadata: %?", sty))
     };
 
-    debug_context(cx).created_types.insert(type_id, type_metadata);
+    debug_context(cx).created_types.insert(cache_id, type_metadata);
     return type_metadata;
 }
 
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 22288a27624..9aca0705911 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -789,3 +789,33 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateNameSpace(
         unwrapDI<DIFile>(File),
         LineNo));
 }
+
+// extern "C" LLVMValueRef LLVMDIBuilderCreateForwardDecl(
+//     DIBuilderRef Builder,
+//     unsigned Tag,
+//     const char* Name,
+//     LLVMValueRef Scope,
+//     LLVMValueRef File,
+//     unsigned Line,
+//     unsigned RuntimeLang,
+//     uint64_t SizeInBits,
+//     uint64_t AlignInBits)
+// {
+//     return wrap(Builder->createForwardDecl(
+//         Tag,
+//         Name,
+//         unwrapDI<DIDescriptor>(Scope),
+//         unwrapDI<DIFile>(File),
+//         Line,
+//         RuntimeLang,
+//         SizeInBits,
+//         AlignInBits
+//     ));
+// }
+
+extern "C" void LLVMDICompositeTypeSetTypeArray(
+    LLVMValueRef CompositeType,
+    LLVMValueRef TypeArray)
+{
+    unwrapDI<DICompositeType>(CompositeType).setTypeArray(unwrapDI<DIArray>(TypeArray));
+}