about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/debuginfo.rs595
-rw-r--r--src/test/debuginfo/type-names.rs333
2 files changed, 744 insertions, 184 deletions
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 400babb39f8..f4019898003 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -222,6 +222,13 @@ static DW_ATE_signed: c_uint = 0x05;
 static DW_ATE_unsigned: c_uint = 0x07;
 static DW_ATE_unsigned_char: c_uint = 0x08;
 
+static UNKNOWN_LINE_NUMBER: c_uint = 0;
+static UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+
+// ptr::null() doesn't work :(
+static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
+static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
+
 //=-----------------------------------------------------------------------------
 //  Public Interface of debuginfo module
 //=-----------------------------------------------------------------------------
@@ -330,15 +337,15 @@ impl TypeMap {
         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_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());
+                push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
             },
             ty::ty_enum(def_id, ref substs) => {
                 unique_type_id.push_str("enum ");
@@ -587,7 +594,7 @@ impl TypeMap {
                                           element_type: ty::t)
                                        -> UniqueTypeId {
         let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
-        let heap_vec_box_type_id = format!("$$HEAP_VEC_BOX<{}>$$",
+        let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}",
                                            self.get_unique_type_id_as_string(element_type_id)
                                                .as_slice());
         let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id));
@@ -599,7 +606,7 @@ impl TypeMap {
                                     element_type: ty::t)
                                  -> UniqueTypeId {
         let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
-        let gc_box_type_id = format!("$$GC_BOX<{}>$$",
+        let gc_box_type_id = format!("{{GC_BOX<{}>}}",
                                      self.get_unique_type_id_as_string(element_type_id)
                                          .as_slice());
         let interner_key = self.unique_id_interner.intern(Rc::new(gc_box_type_id));
@@ -607,6 +614,19 @@ impl TypeMap {
     }
 }
 
+// Returns from the enclosing function if the type metadata with the given
+// unique id can be found in the type map
+macro_rules! return_if_metadata_created_in_meantime(
+    ($cx: expr, $unique_type_id: expr) => (
+        match debug_context($cx).type_map
+                                .borrow()
+                                .find_metadata_for_unique_id($unique_type_id) {
+            Some(metadata) => return MetadataCreationResult::new(metadata, true),
+            None => { /* proceed normally */ }
+        };
+    )
+)
+
 
 /// A context object for maintaining all state needed by the debuginfo module.
 pub struct CrateDebugContext {
@@ -1304,9 +1324,12 @@ pub fn create_function_debug_context(cx: &CrateContext,
         if has_self_type {
             let actual_self_type = self_type.unwrap();
             // Add self type name to <...> clause of function name
-            let actual_self_type_name = ppaux::ty_to_str(cx.tcx(), actual_self_type);
-            name_to_append_suffix_to.push_str(
-                actual_self_type_name.as_slice());
+            let actual_self_type_name = compute_debuginfo_type_name(
+                cx,
+                actual_self_type,
+                true);
+
+            name_to_append_suffix_to.push_str(actual_self_type_name.as_slice());
 
             if generics.is_type_parameterized() {
                 name_to_append_suffix_to.push_str(",");
@@ -1343,7 +1366,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
         for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() {
             let actual_type = *actual_types.get(index);
             // Add actual type name to <...> clause of function name
-            let actual_type_name = ppaux::ty_to_str(cx.tcx(), actual_type);
+            let actual_type_name = compute_debuginfo_type_name(cx,
+                                                               actual_type,
+                                                               true);
             name_to_append_suffix_to.push_str(actual_type_name.as_slice());
 
             if index != generics.ty_params.len() - 1 {
@@ -1646,7 +1671,7 @@ fn pointer_type_metadata(cx: &CrateContext,
                       -> DIType {
     let pointer_llvm_type = type_of::type_of(cx, pointer_type);
     let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
-    let name = ppaux::ty_to_str(cx.tcx(), pointer_type);
+    let name = compute_debuginfo_type_name(cx, pointer_type, false);
     let ptr_metadata = name.as_slice().with_c_str(|name| {
         unsafe {
             llvm::LLVMDIBuilderCreatePointerType(
@@ -1719,7 +1744,6 @@ enum RecursiveTypeDescription {
         unique_type_id: UniqueTypeId,
         metadata_stub: DICompositeType,
         llvm_type: Type,
-        file_metadata: DIFile,
         member_description_factory: MemberDescriptionFactory,
     },
     FinalMetadata(DICompositeType)
@@ -1731,7 +1755,6 @@ fn create_and_register_recursive_type_forward_declaration(
     unique_type_id: UniqueTypeId,
     metadata_stub: DICompositeType,
     llvm_type: Type,
-    file_metadata: DIFile,
     member_description_factory: MemberDescriptionFactory)
  -> RecursiveTypeDescription {
 
@@ -1745,7 +1768,6 @@ fn create_and_register_recursive_type_forward_declaration(
         unique_type_id: unique_type_id,
         metadata_stub: metadata_stub,
         llvm_type: llvm_type,
-        file_metadata: file_metadata,
         member_description_factory: member_description_factory,
     }
 }
@@ -1761,8 +1783,8 @@ impl RecursiveTypeDescription {
                 unique_type_id,
                 metadata_stub,
                 llvm_type,
-                file_metadata,
-                ref member_description_factory
+                ref member_description_factory,
+                ..
             } => {
                 // Make sure that we have a forward declaration of the type in
                 // the TypeMap so that recursive references are possible. This
@@ -1788,9 +1810,7 @@ impl RecursiveTypeDescription {
                 set_members_of_composite_type(cx,
                                               metadata_stub,
                                               llvm_type,
-                                              member_descriptions.as_slice(),
-                                              file_metadata,
-                                              codemap::DUMMY_SP);
+                                              member_descriptions.as_slice());
                 return MetadataCreationResult::new(metadata_stub, true);
             }
         }
@@ -1845,6 +1865,7 @@ impl StructMemberDescriptionFactory {
     }
 }
 
+
 fn prepare_struct_metadata(cx: &CrateContext,
                            struct_type: ty::t,
                            def_id: ast::DefId,
@@ -1852,21 +1873,16 @@ fn prepare_struct_metadata(cx: &CrateContext,
                            unique_type_id: UniqueTypeId,
                            span: Span)
                         -> RecursiveTypeDescription {
-    let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
+    let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
     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);
-
-    let file_name = span_start(cx, definition_span).file.name.clone();
-    let file_metadata = file_metadata(cx, file_name.as_slice());
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
 
     let struct_metadata_stub = create_struct_stub(cx,
                                                   struct_llvm_type,
                                                   struct_name.as_slice(),
                                                   unique_type_id,
-                                                  containing_scope,
-                                                  file_metadata,
-                                                  definition_span);
+                                                  containing_scope);
 
     let fields = ty::struct_fields(cx.tcx(), def_id, substs);
 
@@ -1876,7 +1892,6 @@ fn prepare_struct_metadata(cx: &CrateContext,
         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),
@@ -1916,12 +1931,9 @@ fn prepare_tuple_metadata(cx: &CrateContext,
                           unique_type_id: UniqueTypeId,
                           span: Span)
                        -> RecursiveTypeDescription {
-    let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
+    let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
     let tuple_llvm_type = type_of::type_of(cx, tuple_type);
 
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
     create_and_register_recursive_type_forward_declaration(
         cx,
         tuple_type,
@@ -1930,11 +1942,8 @@ fn prepare_tuple_metadata(cx: &CrateContext,
                            tuple_llvm_type,
                            tuple_name.as_slice(),
                            unique_type_id,
-                           file_metadata,
-                           file_metadata,
-                           span),
+                           UNKNOWN_SCOPE_METADATA),
         tuple_llvm_type,
-        file_metadata,
         TupleMDF(TupleMemberDescriptionFactory {
             component_types: Vec::from_slice(component_types),
             span: span,
@@ -1982,7 +1991,6 @@ impl EnumMemberDescriptionFactory {
                                                   &**self.variants.get(i),
                                                   discriminant_info,
                                                   self.containing_scope,
-                                                  self.file_metadata,
                                                   self.span);
 
                         let member_descriptions = member_desc_factory
@@ -1991,9 +1999,7 @@ impl EnumMemberDescriptionFactory {
                         set_members_of_composite_type(cx,
                                                       variant_type_metadata,
                                                       variant_llvm_type,
-                                                      member_descriptions.as_slice(),
-                                                      self.file_metadata,
-                                                      codemap::DUMMY_SP);
+                                                      member_descriptions.as_slice());
                         MemberDescription {
                             name: "".to_string(),
                             llvm_type: variant_llvm_type,
@@ -2017,7 +2023,6 @@ impl EnumMemberDescriptionFactory {
                                               &**self.variants.get(0),
                                               NoDiscriminant,
                                               self.containing_scope,
-                                              self.file_metadata,
                                               self.span);
 
                     let member_descriptions =
@@ -2026,9 +2031,7 @@ impl EnumMemberDescriptionFactory {
                     set_members_of_composite_type(cx,
                                                   variant_type_metadata,
                                                   variant_llvm_type,
-                                                  member_descriptions.as_slice(),
-                                                  self.file_metadata,
-                                                  codemap::DUMMY_SP);
+                                                  member_descriptions.as_slice());
                     vec![
                         MemberDescription {
                             name: "".to_string(),
@@ -2119,7 +2122,6 @@ impl EnumMemberDescriptionFactory {
                                           &**self.variants.get(nndiscr as uint),
                                           OptimizedDiscriminant(ptrfield),
                                           self.containing_scope,
-                                          self.file_metadata,
                                           self.span);
 
                 let variant_member_descriptions =
@@ -2128,9 +2130,7 @@ impl EnumMemberDescriptionFactory {
                 set_members_of_composite_type(cx,
                                               variant_type_metadata,
                                               variant_llvm_type,
-                                              variant_member_descriptions.as_slice(),
-                                              self.file_metadata,
-                                              codemap::DUMMY_SP);
+                                              variant_member_descriptions.as_slice());
 
                 // Encode the information about the null variant in the union
                 // member's name.
@@ -2195,7 +2195,6 @@ fn describe_enum_variant(cx: &CrateContext,
                          variant_info: &ty::VariantInfo,
                          discriminant_info: EnumDiscriminantInfo,
                          containing_scope: DIScope,
-                         file_metadata: DIFile,
                          span: Span)
                       -> (DICompositeType, Type, MemberDescriptionFactory) {
     let variant_llvm_type =
@@ -2207,14 +2206,6 @@ fn describe_enum_variant(cx: &CrateContext,
                       struct_def.packed);
     // Could do 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.krate == ast::LOCAL_CRATE {
-        cx.tcx.map.span(variant_info.id.node)
-    } else {
-        // For definitions from other crates we have no location information available.
-        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
@@ -2228,9 +2219,7 @@ fn describe_enum_variant(cx: &CrateContext,
                                            variant_llvm_type,
                                            variant_name,
                                            unique_type_id,
-                                           containing_scope,
-                                           file_metadata,
-                                           variant_definition_span);
+                                           containing_scope);
 
     // Get the argument names from the enum variant info
     let mut arg_names: Vec<_> = match variant_info.arg_names {
@@ -2276,7 +2265,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
                          unique_type_id: UniqueTypeId,
                          span: Span)
                       -> RecursiveTypeDescription {
-    let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
+    let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
 
     let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, enum_def_id);
     let loc = span_start(cx, definition_span);
@@ -2323,8 +2312,8 @@ fn prepare_enum_metadata(cx: &CrateContext,
                             DIB(cx),
                             containing_scope,
                             name,
-                            file_metadata,
-                            loc.line as c_uint,
+                            UNKNOWN_FILE_METADATA,
+                            UNKNOWN_LINE_NUMBER,
                             bytes_to_bits(discriminant_size),
                             bytes_to_bits(discriminant_align),
                             create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
@@ -2368,8 +2357,8 @@ fn prepare_enum_metadata(cx: &CrateContext,
                 DIB(cx),
                 containing_scope,
                 enum_name,
-                file_metadata,
-                loc.line as c_uint,
+                UNKNOWN_FILE_METADATA,
+                UNKNOWN_LINE_NUMBER,
                 bytes_to_bits(enum_type_size),
                 bytes_to_bits(enum_type_align),
                 0, // Flags
@@ -2386,7 +2375,6 @@ fn prepare_enum_metadata(cx: &CrateContext,
         unique_type_id,
         enum_metadata,
         enum_llvm_type,
-        file_metadata,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type: enum_type,
             type_rep: type_rep.clone(),
@@ -2421,24 +2409,23 @@ fn composite_type_metadata(cx: &CrateContext,
                            composite_type_unique_id: UniqueTypeId,
                            member_descriptions: &[MemberDescription],
                            containing_scope: DIScope,
-                           file_metadata: DIFile,
-                           definition_span: Span)
+
+                           // Ignore source location information as long as it
+                           // can't be reconstructed for non-local crates.
+                           _file_metadata: DIFile,
+                           _definition_span: Span)
                         -> DICompositeType {
     // Create the (empty) struct metadata node ...
     let composite_type_metadata = create_struct_stub(cx,
                                                      composite_llvm_type,
                                                      composite_type_name,
                                                      composite_type_unique_id,
-                                                     containing_scope,
-                                                     file_metadata,
-                                                     definition_span);
+                                                     containing_scope);
     // ... and immediately create and add the member descriptions.
     set_members_of_composite_type(cx,
                                   composite_type_metadata,
                                   composite_llvm_type,
-                                  member_descriptions,
-                                  file_metadata,
-                                  definition_span);
+                                  member_descriptions);
 
     return composite_type_metadata;
 }
@@ -2446,9 +2433,7 @@ fn composite_type_metadata(cx: &CrateContext,
 fn set_members_of_composite_type(cx: &CrateContext,
                                  composite_type_metadata: DICompositeType,
                                  composite_llvm_type: Type,
-                                 member_descriptions: &[MemberDescription],
-                                 file_metadata: DIFile,
-                                 definition_span: Span) {
+                                 member_descriptions: &[MemberDescription]) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in create_struct_stub.
     // This would cause a hard to trace assertion in DICompositeType::SetTypeArray().
@@ -2483,8 +2468,6 @@ fn set_members_of_composite_type(cx: &CrateContext,
         }
     }
 
-    let loc = span_start(cx, definition_span);
-
     let member_metadata: Vec<DIDescriptor> = member_descriptions
         .iter()
         .enumerate()
@@ -2501,8 +2484,8 @@ fn set_members_of_composite_type(cx: &CrateContext,
                         DIB(cx),
                         composite_type_metadata,
                         member_name,
-                        file_metadata,
-                        loc.line as c_uint,
+                        UNKNOWN_FILE_METADATA,
+                        UNKNOWN_LINE_NUMBER,
                         bytes_to_bits(member_size),
                         bytes_to_bits(member_align),
                         bytes_to_bits(member_offset),
@@ -2526,11 +2509,8 @@ 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)
+                      containing_scope: DIScope)
                    -> DICompositeType {
-    let loc = span_start(cx, definition_span);
     let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
 
     let unique_type_id_str = debug_context(cx).type_map
@@ -2548,8 +2528,8 @@ fn create_struct_stub(cx: &CrateContext,
                     DIB(cx),
                     containing_scope,
                     name,
-                    file_metadata,
-                    loc.line as c_uint,
+                    UNKNOWN_FILE_METADATA,
+                    UNKNOWN_LINE_NUMBER,
                     bytes_to_bits(struct_size),
                     bytes_to_bits(struct_align),
                     0,
@@ -2572,12 +2552,9 @@ fn at_box_metadata(cx: &CrateContext,
                 -> MetadataCreationResult {
     let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
-    let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
+    let content_type_name = compute_debuginfo_type_name(cx, content_type, true);
     let content_type_name = content_type_name.as_slice();
     let content_llvm_type = type_of::type_of(cx, content_type);
 
@@ -2593,7 +2570,6 @@ fn at_box_metadata(cx: &CrateContext,
     let nil_pointer_type_metadata = type_metadata(cx,
                                                   nil_pointer_type,
                                                   codemap::DUMMY_SP);
-
     let member_descriptions = [
         MemberDescription {
             name: "refcnt".to_string(),
@@ -2627,9 +2603,6 @@ fn at_box_metadata(cx: &CrateContext,
         }
     ];
 
-    let loc = span_start(cx, codemap::DUMMY_SP);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
     let gc_box_unique_id = debug_context(cx).type_map
                                             .borrow_mut()
                                             .get_unique_type_id_of_gc_box(cx, content_type);
@@ -2640,8 +2613,8 @@ fn at_box_metadata(cx: &CrateContext,
         box_type_name.as_slice(),
         gc_box_unique_id,
         member_descriptions,
-        file_metadata,
-        file_metadata,
+        UNKNOWN_SCOPE_METADATA,
+        UNKNOWN_FILE_METADATA,
         codemap::DUMMY_SP);
 
     let gc_pointer_metadata = pointer_type_metadata(cx,
@@ -2674,10 +2647,7 @@ fn fixed_vec_metadata(cx: &CrateContext,
                    -> MetadataCreationResult {
     let element_type_metadata = type_metadata(cx, element_type, span);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let element_llvm_type = type_of::type_of(cx, element_type);
     let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
@@ -2712,13 +2682,12 @@ fn heap_vec_metadata(cx: &CrateContext,
     let element_llvm_type = type_of::type_of(cx, element_type);
     let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
-    let vec_pointer_type_name = ppaux::ty_to_str(cx.tcx(), vec_pointer_type);
+    let vec_pointer_type_name = compute_debuginfo_type_name(cx,
+                                                            vec_pointer_type,
+                                                            true);
     let vec_pointer_type_name = vec_pointer_type_name.as_slice();
 
     let member_llvm_types = vecbox_llvm_type.field_types();
@@ -2769,7 +2738,7 @@ fn heap_vec_metadata(cx: &CrateContext,
                                                   vec_pointer_type_name,
                                                   vec_box_unique_id,
                                                   member_descriptions,
-                                                  file_metadata,
+                                                  UNKNOWN_SCOPE_METADATA,
                                                   file_metadata,
                                                   span);
 
@@ -2791,13 +2760,10 @@ fn vec_slice_metadata(cx: &CrateContext,
 
     let element_type_metadata = type_metadata(cx, data_ptr_type, span);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let slice_llvm_type = type_of::type_of(cx, vec_type);
-    let slice_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
+    let slice_type_name = compute_debuginfo_type_name(cx, vec_type, true);
 
     let member_llvm_types = slice_llvm_type.field_types();
     assert!(slice_layout_is_correct(cx,
@@ -2828,7 +2794,7 @@ fn vec_slice_metadata(cx: &CrateContext,
                                            slice_type_name.as_slice(),
                                            unique_type_id,
                                            member_descriptions,
-                                           file_metadata,
+                                           UNKNOWN_SCOPE_METADATA,
                                            file_metadata,
                                            span);
     return MetadataCreationResult::new(metadata, false);
@@ -2848,8 +2814,6 @@ fn subroutine_type_metadata(cx: &CrateContext,
                             signature: &ty::FnSig,
                             span: Span)
                          -> MetadataCreationResult {
-    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);
 
     // return type
@@ -2863,57 +2827,64 @@ fn subroutine_type_metadata(cx: &CrateContext,
         signature_metadata.push(type_metadata(cx, argument_type, span));
     }
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     return MetadataCreationResult::new(
         unsafe {
             llvm::LLVMDIBuilderCreateSubroutineType(
                 DIB(cx),
-                file_metadata,
+                UNKNOWN_FILE_METADATA,
                 create_DIArray(DIB(cx), signature_metadata.as_slice()))
         },
         false);
 }
 
-fn trait_metadata(cx: &CrateContext,
-                  def_id: ast::DefId,
-                  trait_type: ty::t,
-                  substs: &subst::Substs,
-                  trait_store: ty::TraitStore,
-                  _: &ty::BuiltinBounds,
-                  unique_type_id: UniqueTypeId)
-               -> DIType {
+fn trait_pointer_metadata(cx: &CrateContext,
+                          // trait_pointer_type must be the type of the fat
+                          // pointer to the concrete trait object
+                          trait_pointer_type: ty::t,
+                          unique_type_id: UniqueTypeId)
+                       -> DIType {
     // The implementation provided here is a stub. It makes sure that the trait
     // type is assigned the correct name, size, namespace, and source location.
     // But it does not describe the trait's methods.
-    let last = ty::with_path(cx.tcx(), def_id, |mut path| path.last().unwrap());
-    let ident_string = token::get_name(last.name());
-    let mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store);
-    name.push_str(ident_string.get());
 
-    // Add type and region parameters
-    let trait_def = ty::lookup_trait_def(cx.tcx(), def_id);
-    let name = ppaux::parameterized(cx.tcx(), name.as_slice(),
-                                    substs, &trait_def.generics);
+    let trait_object_type = match ty::get(trait_pointer_type).sty {
+        ty::ty_uniq(pointee_type) => pointee_type,
+        ty::ty_rptr(_, ty::mt { ty, .. }) => ty,
+        _ => {
+            let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_pointer_type);
+            cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \
+                                   trait_pointer_metadata(): {}",
+                                   pp_type_name.as_slice()).as_slice());
+        }
+    };
+
+    let def_id = match ty::get(trait_object_type).sty {
+        ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id,
+        _ => {
+            let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_object_type);
+            cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
+                                   trait_pointer_metadata(): {}",
+                                   pp_type_name.as_slice()).as_slice());
+        }
+    };
 
-    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);
+    let trait_pointer_type_name =
+        compute_debuginfo_type_name(cx, trait_pointer_type, false);
 
-    let file_name = span_start(cx, definition_span).file.name.clone();
-    let file_metadata = file_metadata(cx, file_name.as_slice());
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
 
-    let trait_llvm_type = type_of::type_of(cx, trait_type);
+    let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type);
 
     composite_type_metadata(cx,
-                            trait_llvm_type,
-                            name.as_slice(),
+                            trait_pointer_llvm_type,
+                            trait_pointer_type_name.as_slice(),
                             unique_type_id,
                             [],
                             containing_scope,
-                            file_metadata,
-                            definition_span)
+                            UNKNOWN_FILE_METADATA,
+                            codemap::DUMMY_SP)
 }
 
 fn type_metadata(cx: &CrateContext,
@@ -2955,15 +2926,6 @@ fn type_metadata(cx: &CrateContext,
 
     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 MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
         ty::ty_nil      |
@@ -2993,19 +2955,22 @@ fn type_metadata(cx: &CrateContext,
                     let i8_t = ty::mk_i8();
                     heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
                 }
-                ty::ty_trait(box ty::TyTrait {
-                        def_id,
-                        ref substs,
-                        ref bounds
-                    }) => {
+                ty::ty_trait(..) => {
                     MetadataCreationResult::new(
-                        trait_metadata(cx, def_id, t, substs, ty::UniqTraitStore,
-                                       bounds, unique_type_id),
-                    false)
+                        trait_pointer_metadata(cx, t, unique_type_id),
+                        false)
                 }
                 _ => {
-                    let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
-                    return_if_created_in_meantime!();
+                    let pointee_metadata = type_metadata(cx,
+                                                         pointee_type,
+                                                         usage_site_span);
+                    match debug_context(cx).type_map
+                                           .borrow()
+                                           .find_metadata_for_unique_id(unique_type_id) {
+                        Some(metadata) => return metadata,
+                        None => { /* proceed normally */ }
+                    };
+
                     MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata),
                                                 false)
                 }
@@ -3017,22 +2982,23 @@ fn type_metadata(cx: &CrateContext,
                     vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
                 }
                 ty::ty_str => {
-                    vec_slice_metadata(cx, t, ty::mk_i8(), unique_type_id, usage_site_span)
+                    vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
                 }
-                ty::ty_trait(box ty::TyTrait {
-                        def_id,
-                        ref substs,
-                        ref bounds
-                    }) => {
+                ty::ty_trait(..) => {
                     MetadataCreationResult::new(
-                        trait_metadata(cx, def_id, t, substs,
-                                       ty::RegionTraitStore(ty::ReStatic, mt.mutbl),
-                                       bounds, unique_type_id),
-                    false)
+                        trait_pointer_metadata(cx, t, unique_type_id),
+                        false)
                 }
                 _ => {
                     let pointee = type_metadata(cx, mt.ty, usage_site_span);
-                    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 */ }
+                    };
+
                     MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false)
                 }
             }
@@ -3150,7 +3116,8 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
 
     match debug_location {
         KnownLocation { scope, line, .. } => {
-            let col = 0u; // Always set the column to zero like Clang and GCC
+            // Always set the column to zero like Clang and GCC
+            let col = UNKNOWN_COLUMN_NUMBER;
             debug!("setting debug location to {} {}", line, col);
             let elements = [C_i32(cx, line as i32), C_i32(cx, col as i32),
                             scope, ptr::mut_null()];
@@ -3701,6 +3668,265 @@ fn populate_scope_map(cx: &CrateContext,
 
 
 //=-----------------------------------------------------------------------------
+// Type Names for Debug Info
+//=-----------------------------------------------------------------------------
+
+// Compute the name of the type as it should be stored in debuginfo. Does not do
+// any caching, i.e. calling the function twice with the same type will also do
+// the work twice. The `qualified` parameter only affects the first level of the
+// type name, further levels (i.e. type parameters) are always fully qualified.
+fn compute_debuginfo_type_name(cx: &CrateContext,
+                               t: ty::t,
+                               qualified: bool)
+                            -> String {
+    let mut result = String::with_capacity(64);
+    push_debuginfo_type_name(cx, t, qualified, &mut result);
+    result
+}
+
+// Pushes the name of the type as it should be stored in debuginfo on the
+// `output` String. See also compute_debuginfo_type_name().
+fn push_debuginfo_type_name(cx: &CrateContext,
+                            t: ty::t,
+                            qualified: bool,
+                            output:&mut String) {
+    match ty::get(t).sty {
+        ty::ty_nil               => output.push_str("()"),
+        ty::ty_bot               => output.push_str("!"),
+        ty::ty_bool              => output.push_str("bool"),
+        ty::ty_char              => output.push_str("char"),
+        ty::ty_str               => output.push_str("str"),
+        ty::ty_int(ast::TyI)     => output.push_str("int"),
+        ty::ty_int(ast::TyI8)    => output.push_str("i8"),
+        ty::ty_int(ast::TyI16)   => output.push_str("i16"),
+        ty::ty_int(ast::TyI32)   => output.push_str("i32"),
+        ty::ty_int(ast::TyI64)   => output.push_str("i64"),
+        ty::ty_uint(ast::TyU)    => output.push_str("uint"),
+        ty::ty_uint(ast::TyU8)   => output.push_str("u8"),
+        ty::ty_uint(ast::TyU16)  => output.push_str("u16"),
+        ty::ty_uint(ast::TyU32)  => output.push_str("u32"),
+        ty::ty_uint(ast::TyU64)  => output.push_str("u64"),
+        ty::ty_float(ast::TyF32) => output.push_str("f32"),
+        ty::ty_float(ast::TyF64) => output.push_str("f64"),
+        ty::ty_struct(def_id, ref substs) |
+        ty::ty_enum(def_id, ref substs) => {
+            push_item_name(cx, def_id, qualified, output);
+            push_type_params(cx, substs, output);
+        },
+        ty::ty_tup(ref component_types) => {
+            output.push_char('(');
+            for &component_type in component_types.iter() {
+                push_debuginfo_type_name(cx, component_type, true, output);
+                output.push_str(", ");
+            }
+            output.pop_char();
+            output.pop_char();
+            output.push_char(')');
+        },
+        ty::ty_uniq(inner_type) => {
+            output.push_str("Box<");
+            push_debuginfo_type_name(cx, inner_type, true, output);
+            output.push_char('>');
+        },
+        ty::ty_box(inner_type) => {
+            output.push_char('@');
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+            output.push_char('*');
+            match mutbl {
+                ast::MutImmutable => output.push_str("const "),
+                ast::MutMutable => output.push_str("mut "),
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+            output.push_char('&');
+            if mutbl == ast::MutMutable {
+                output.push_str("mut ");
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
+            output.push_char('[');
+            push_debuginfo_type_name(cx, inner_type, true, output);
+
+            match optional_length {
+                Some(len) => {
+                    output.push_str(format!(", ..{}", len).as_slice());
+                }
+                None => { /* nothing to do */ }
+            };
+
+            output.push_char(']');
+        },
+        ty::ty_trait(ref trait_data) => {
+            push_item_name(cx, trait_data.def_id, false, output);
+            push_type_params(cx, &trait_data.substs, output);
+        },
+        ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
+            if fn_style == ast::UnsafeFn {
+                output.push_str("unsafe ");
+            }
+
+            if abi != ::syntax::abi::Rust {
+                output.push_str("extern \"");
+                output.push_str(abi.name());
+                output.push_str("\" ");
+            }
+
+            output.push_str("fn(");
+
+            if sig.inputs.len() > 0 {
+                for &parameter_type in sig.inputs.iter() {
+                    push_debuginfo_type_name(cx, parameter_type, true, output);
+                    output.push_str(", ");
+                }
+                output.pop_char();
+                output.pop_char();
+            }
+
+            if sig.variadic {
+                if sig.inputs.len() > 0 {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push_char(')');
+
+            if !ty::type_is_nil(sig.output) {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output, true, output);
+            }
+        },
+        ty::ty_closure(box ty::ClosureTy { fn_style,
+                                           onceness,
+                                           store,
+                                           ref sig,
+                                           .. // omitting bounds ...
+                                           }) => {
+            if fn_style == ast::UnsafeFn {
+                output.push_str("unsafe ");
+            }
+
+            if onceness == ast::Once {
+                output.push_str("once ");
+            }
+
+            let param_list_closing_char;
+            match store {
+                ty::UniqTraitStore => {
+                    output.push_str("proc(");
+                    param_list_closing_char = ')';
+                }
+                ty::RegionTraitStore(_, ast::MutMutable) => {
+                    output.push_str("&mut|");
+                    param_list_closing_char = '|';
+                }
+                ty::RegionTraitStore(_, ast::MutImmutable) => {
+                    output.push_str("&|");
+                    param_list_closing_char = '|';
+                }
+            };
+
+            if sig.inputs.len() > 0 {
+                for &parameter_type in sig.inputs.iter() {
+                    push_debuginfo_type_name(cx, parameter_type, true, output);
+                    output.push_str(", ");
+                }
+                output.pop_char();
+                output.pop_char();
+            }
+
+            if sig.variadic {
+                if sig.inputs.len() > 0 {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push_char(param_list_closing_char);
+
+            if !ty::type_is_nil(sig.output) {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output, true, output);
+            }
+        },
+        ty::ty_err      |
+        ty::ty_infer(_) |
+        ty::ty_param(_) => {
+            cx.sess().bug(format!("debuginfo: Trying to create type name for \
+                unexpected type: {}", ppaux::ty_to_str(cx.tcx(), t)).as_slice());
+        }
+    }
+
+    fn push_item_name(cx: &CrateContext,
+                      def_id: ast::DefId,
+                      qualified: bool,
+                      output: &mut String) {
+        ty::with_path(cx.tcx(), def_id, |mut path| {
+            if qualified {
+                if def_id.krate == ast::LOCAL_CRATE {
+                    output.push_str(crate_root_namespace(cx));
+                    output.push_str("::");
+                }
+
+                let mut path_element_count = 0u;
+                for path_element in path {
+                    let name = token::get_name(path_element.name());
+                    output.push_str(name.get());
+                    output.push_str("::");
+                    path_element_count += 1;
+                }
+
+                if path_element_count == 0 {
+                    cx.sess().bug("debuginfo: Encountered empty item path!");
+                }
+
+                output.pop_char();
+                output.pop_char();
+            } else {
+                let name = token::get_name(path.last()
+                                               .expect("debuginfo: Empty item path?")
+                                               .name());
+                output.push_str(name.get());
+            }
+        });
+    }
+
+    // Pushes the type parameters in the given `Substs` to the output string.
+    // This ignores region parameters, since they can't reliably be
+    // reconstructed for items from non-local crates. For local crates, this
+    // would be possible but with inlining and LTO we have to use the least
+    // common denominator - otherwise we would run into conflicts.
+    fn push_type_params(cx: &CrateContext,
+                        substs: &subst::Substs,
+                        output: &mut String) {
+        if substs.types.is_empty() {
+            return;
+        }
+
+        output.push_char('<');
+
+        for &type_parameter in substs.types.iter() {
+            push_debuginfo_type_name(cx, type_parameter, true, output);
+            output.push_str(", ");
+        }
+
+        output.pop_char();
+        output.pop_char();
+
+        output.push_char('>');
+    }
+}
+
+
+//=-----------------------------------------------------------------------------
 // Namespace Handling
 //=-----------------------------------------------------------------------------
 
@@ -3731,14 +3957,15 @@ impl NamespaceTreeNode {
     }
 }
 
+fn crate_root_namespace<'a>(cx: &'a CrateContext) -> &'a str {
+    cx.link_meta.crateid.name.as_slice()
+}
+
 fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTreeNode> {
     ty::with_path(cx.tcx(), def_id, |path| {
         // prepend crate name if not already present
         let krate = if def_id.krate == ast::LOCAL_CRATE {
-            let crate_namespace_ident = token::str_to_ident(cx.link_meta
-                                                              .crateid
-                                                              .name
-                                                              .as_slice());
+            let crate_namespace_ident = token::str_to_ident(crate_root_namespace(cx));
             Some(ast_map::PathMod(crate_namespace_ident.name))
         } else {
             None
diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs
new file mode 100644
index 00000000000..ac5fe830275
--- /dev/null
+++ b/src/test/debuginfo/type-names.rs
@@ -0,0 +1,333 @@
+// 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-tidy-linelength
+// ignore-lldb
+// ignore-android: FIXME(#10381)
+
+// compile-flags:-g
+// gdb-command:rbreak zzz
+// gdb-command:run
+// gdb-command:finish
+
+
+// STRUCTS
+// gdb-command:whatis simple_struct
+// gdb-check:type = struct Struct1
+
+// gdb-command:whatis generic_struct1
+// gdb-check:type = struct GenericStruct<type-names::Mod1::Struct2, type-names::Mod1::Mod2::Struct3>
+
+// gdb-command:whatis generic_struct2
+// gdb-check:type = struct GenericStruct<type-names::Struct1, extern "fastcall" fn(int) -> uint>
+
+// gdb-command:whatis mod_struct
+// gdb-check:type = struct Struct2
+
+
+// ENUMS
+// gdb-command:whatis simple_enum_1
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_2
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_3
+// gdb-check:type = union Enum2
+
+// gdb-command:whatis generic_enum_1
+// gdb-check:type = union Enum3<type-names::Mod1::Struct2>
+
+// gdb-command:whatis generic_enum_2
+// gdb-check:type = union Enum3<type-names::Struct1>
+
+
+// TUPLES
+// gdb-command:whatis tuple1
+// gdb-check:type = struct (u32, type-names::Struct1, type-names::Mod1::Mod2::Enum3<type-names::Mod1::Struct2>)
+
+// gdb-command:whatis tuple2
+// gdb-check:type = struct ((type-names::Struct1, type-names::Mod1::Mod2::Struct3), type-names::Mod1::Enum2, char)
+
+
+// BOX
+// gdb-command:whatis box1
+// gdb-check:type = struct (Box<f32>, i32)
+
+// gdb-command:whatis box2
+// gdb-check:type = struct (Box<type-names::Mod1::Mod2::Enum3<f32>>, i32)
+
+
+// REFERENCES
+// gdb-command:whatis ref1
+// gdb-check:type = struct (&type-names::Struct1, i32)
+
+// gdb-command:whatis ref2
+// gdb-check:type = struct (&type-names::GenericStruct<char, type-names::Struct1>, i32)
+
+// gdb-command:whatis mut_ref1
+// gdb-check:type = struct (&mut type-names::Struct1, i32)
+
+// gdb-command:whatis mut_ref2
+// gdb-check:type = struct (&mut type-names::GenericStruct<type-names::Mod1::Enum2, f64>, i32)
+
+
+// RAW POINTERS
+// gdb-command:whatis mut_ptr1
+// gdb-check:type = struct (*mut type-names::Struct1, int)
+
+// gdb-command:whatis mut_ptr2
+// gdb-check:type = struct (*mut int, int)
+
+// gdb-command:whatis mut_ptr3
+// gdb-check:type = struct (*mut type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+// gdb-command:whatis const_ptr1
+// gdb-check:type = struct (*const type-names::Struct1, int)
+
+// gdb-command:whatis const_ptr2
+// gdb-check:type = struct (*const int, int)
+
+// gdb-command:whatis const_ptr3
+// gdb-check:type = struct (*const type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+
+// VECTORS
+// gdb-command:whatis fixed_size_vec1
+// gdb-check:type = struct ([type-names::Struct1, ..3], i16)
+
+// gdb-command:whatis fixed_size_vec2
+// gdb-check:type = struct ([uint, ..3], i16)
+
+// gdb-command:whatis slice1
+// gdb-check:type = struct &[uint]
+
+// gdb-command:whatis slice2
+// gdb-check:type = struct &[type-names::Mod1::Enum2]
+
+
+// TRAITS
+// gdb-command:whatis box_trait
+// gdb-check:type = struct Box<Trait1>
+
+// gdb-command:whatis ref_trait
+// gdb-check:type = struct &Trait1
+
+// gdb-command:whatis mut_ref_trait
+// gdb-check:type = struct &mut Trait1
+
+// gdb-command:whatis generic_box_trait
+// gdb-check:type = struct Box<Trait2<i32, type-names::Mod1::Struct2>>
+
+// gdb-command:whatis generic_ref_trait
+// gdb-check:type = struct &Trait2<type-names::Struct1, type-names::Struct1>
+
+// gdb-command:whatis generic_mut_ref_trait
+// gdb-check:type = struct &mut Trait2<type-names::Mod1::Mod2::Struct3, type-names::GenericStruct<uint, int>>
+
+
+// BARE FUNCTIONS
+// gdb-command:whatis rust_fn
+// gdb-check:type = struct (fn(core::option::Option<int>, core::option::Option<&type-names::Mod1::Struct2>), uint)
+
+// gdb-command:whatis extern_c_fn
+// gdb-check:type = struct (extern "C" fn(int), uint)
+
+// gdb-command:whatis unsafe_fn
+// gdb-check:type = struct (unsafe fn(core::result::Result<char, f64>), uint)
+
+// gdb-command:whatis extern_stdcall_fn
+// gdb-check:type = struct (extern "stdcall" fn(), uint)
+
+// gdb-command:whatis rust_fn_with_return_value
+// gdb-check:type = struct (fn(f64) -> uint, uint)
+
+// gdb-command:whatis extern_c_fn_with_return_value
+// gdb-check:type = struct (extern "C" fn() -> type-names::Struct1, uint)
+
+// gdb-command:whatis unsafe_fn_with_return_value
+// gdb-check:type = struct (unsafe fn(type-names::GenericStruct<u16, u8>) -> type-names::Mod1::Struct2, uint)
+
+// gdb-command:whatis extern_stdcall_fn_with_return_value
+// gdb-check:type = struct (extern "stdcall" fn(Box<int>) -> uint, uint)
+
+// gdb-command:whatis generic_function_int
+// gdb-check:type = struct (fn(int) -> int, uint)
+
+// gdb-command:whatis generic_function_struct3
+// gdb-check:type = struct (fn(type-names::Mod1::Mod2::Struct3) -> type-names::Mod1::Mod2::Struct3, uint)
+
+// gdb-command:whatis variadic_function
+// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> int, uint)
+
+
+// CLOSURES
+// gdb-command:whatis some_proc
+// gdb-check:type = struct (once proc(int, u8) -> (int, u8), uint)
+
+// gdb-command:whatis stack_closure1
+// gdb-check:type = struct (&mut|int|, uint)
+
+// gdb-command:whatis stack_closure2
+// gdb-check:type = struct (&mut|i8, f32| -> f32, uint)
+
+use std::ptr;
+
+struct Struct1;
+struct GenericStruct<T1, T2>;
+
+enum Enum1 {
+    Variant1_1,
+    Variant1_2(int)
+}
+
+mod Mod1 {
+    pub struct Struct2;
+
+    pub enum Enum2 {
+        Variant2_1,
+        Variant2_2(super::Struct1)
+    }
+
+    pub mod Mod2 {
+        pub struct Struct3;
+
+        pub enum Enum3<T> {
+            Variant3_1,
+            Variant3_2(T),
+        }
+    }
+}
+
+trait Trait1 { }
+trait Trait2<T1, T2> { }
+
+impl Trait1 for int {}
+impl<T1, T2> Trait2<T1, T2> for int {}
+
+fn rust_fn(_: Option<int>, _: Option<&Mod1::Struct2>) {}
+extern "C" fn extern_c_fn(_: int) {}
+unsafe fn unsafe_fn(_: Result<char, f64>) {}
+extern "stdcall" fn extern_stdcall_fn() {}
+
+fn rust_fn_with_return_value(_: f64) -> uint { 4 }
+extern "C" fn extern_c_fn_with_return_value() -> Struct1 { Struct1 }
+unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> Mod1::Struct2 { Mod1::Struct2 }
+extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box<int>) -> uint { 0 }
+
+fn generic_function<T>(x: T) -> T { x }
+
+extern {
+    fn printf(_:*const u8, ...) -> int;
+}
+
+// In many of the cases below, the type that is actually under test is wrapped
+// in a tuple, e.g. Box<T>, references, raw pointers, fixed-size vectors, ...
+// This is because GDB will not print the type name from DWARF debuginfo for
+// some kinds of types (pointers, arrays, functions, ...)
+// Since tuples are structs as far as GDB is concerned, their name will be
+// printed correctly, so the tests below just construct a tuple type that will
+// then *contain* the type name that we want to see.
+fn main() {
+
+    // Structs
+    let simple_struct = Struct1;
+    let generic_struct1: GenericStruct<Mod1::Struct2, Mod1::Mod2::Struct3> = GenericStruct;
+    let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(int) -> uint> = GenericStruct;
+    let mod_struct = Mod1::Struct2;
+
+    // Enums
+    let simple_enum_1 = Variant1_1;
+    let simple_enum_2 = Variant1_2(0);
+    let simple_enum_3 = Mod1::Variant2_2(Struct1);
+
+    let generic_enum_1: Mod1::Mod2::Enum3<Mod1::Struct2> = Mod1::Mod2::Variant3_1;
+    let generic_enum_2 = Mod1::Mod2::Variant3_2(Struct1);
+
+    // Tuples
+    let tuple1 = (8u32, Struct1, Mod1::Mod2::Variant3_2(Mod1::Struct2));
+    let tuple2 = ((Struct1, Mod1::Mod2::Struct3), Mod1::Variant2_1, 'x');
+
+    // Box
+    let box1 = (box 1f32, 0i32);
+    let box2 = (box Mod1::Mod2::Variant3_2(1f32), 0i32);
+
+    // References
+    let ref1 = (&Struct1, 0i32);
+    let ref2 = (&GenericStruct::<char, Struct1>, 0i32);
+
+    let mut mut_struct1 = Struct1;
+    let mut mut_generic_struct = GenericStruct::<Mod1::Enum2, f64>;
+    let mut_ref1 = (&mut mut_struct1, 0i32);
+    let mut_ref2 = (&mut mut_generic_struct, 0i32);
+
+    // Raw Pointers
+    let mut_ptr1: (*mut Struct1, int) = (ptr::mut_null(), 0);
+    let mut_ptr2: (*mut int, int) = (ptr::mut_null(), 0);
+    let mut_ptr3: (*mut Mod1::Mod2::Enum3<Struct1>, int) = (ptr::mut_null(), 0);
+
+    let const_ptr1: (*const Struct1, int) = (ptr::null(), 0);
+    let const_ptr2: (*const int, int) = (ptr::null(), 0);
+    let const_ptr3: (*const Mod1::Mod2::Enum3<Struct1>, int) = (ptr::null(), 0);
+
+    // Vectors
+    let fixed_size_vec1 = ([Struct1, Struct1, Struct1], 0i16);
+    let fixed_size_vec2 = ([0u, 1u, 2u], 0i16);
+
+    let vec1 = vec![0u, 2u, 3u];
+    let slice1 = vec1.as_slice();
+    let vec2 = vec![Mod1::Variant2_2(Struct1)];
+    let slice2 = vec2.as_slice();
+
+    // Trait Objects
+    let box_trait = (box 0i) as Box<Trait1>;
+    let ref_trait = &0i as &Trait1;
+    let mut mut_int1 = 0i;
+    let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
+
+    let generic_box_trait = (box 0i) as Box<Trait2<i32, Mod1::Struct2>>;
+    let generic_ref_trait  = (&0i) as &Trait2<Struct1, Struct1>;
+
+    let mut generic_mut_ref_trait_impl = 0i;
+    let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
+        &mut Trait2<Mod1::Mod2::Struct3, GenericStruct<uint, int>>;
+
+    // Bare Functions
+    let rust_fn = (rust_fn, 0u);
+    let extern_c_fn = (extern_c_fn, 0u);
+    let unsafe_fn = (unsafe_fn, 0u);
+    let extern_stdcall_fn = (extern_stdcall_fn, 0u);
+
+    let rust_fn_with_return_value = (rust_fn_with_return_value, 0u);
+    let extern_c_fn_with_return_value = (extern_c_fn_with_return_value, 0u);
+    let unsafe_fn_with_return_value = (unsafe_fn_with_return_value, 0u);
+    let extern_stdcall_fn_with_return_value = (extern_stdcall_fn_with_return_value, 0u);
+
+    let generic_function_int = (generic_function::<int>, 0u);
+    let generic_function_struct3 = (generic_function::<Mod1::Mod2::Struct3>, 0u);
+
+    let variadic_function = (printf, 0u);
+
+    // Closures
+    // I (mw) am a bit unclear about the current state of closures, their
+    // various forms (boxed, unboxed, proc, capture-by-ref, by-val, once) and
+    // how that maps to rustc's internal representation of these forms.
+    // Once closures have reached their 1.0 form, the tests below should
+    // probably be expanded.
+    let some_proc = (proc(a:int, b:u8) (a, b), 0u);
+
+    let stack_closure1 = (|x:int| {}, 0u);
+    let stack_closure2 = (|x:i8, y: f32| { (x as f32) + y }, 0u);
+
+    zzz();
+}
+
+#[inline(never)]
+fn zzz() { () }