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 = 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 = 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 (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id); + 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 file_name = span_start(cx, definition_span).file.name.clone(); - let file_metadata = file_metadata(cx, file_name.as_slice()); + let trait_pointer_type_name = + compute_debuginfo_type_name(cx, trait_pointer_type, false); - let trait_llvm_type = type_of::type_of(cx, trait_type); + let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); + + 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()]; @@ -3700,6 +3667,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 ¶meter_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 ¶meter_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 { 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 or the MIT license +// , 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 + +// gdb-command:whatis generic_struct2 +// gdb-check:type = struct GenericStruct 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 + +// gdb-command:whatis generic_enum_2 +// gdb-check:type = union Enum3 + + +// TUPLES +// gdb-command:whatis tuple1 +// gdb-check:type = struct (u32, type-names::Struct1, type-names::Mod1::Mod2::Enum3) + +// 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, i32) + +// gdb-command:whatis box2 +// gdb-check:type = struct (Box>, 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, 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, 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, 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, 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 + +// 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> + +// gdb-command:whatis generic_ref_trait +// gdb-check:type = struct &Trait2 + +// gdb-command:whatis generic_mut_ref_trait +// gdb-check:type = struct &mut Trait2> + + +// BARE FUNCTIONS +// gdb-command:whatis rust_fn +// gdb-check:type = struct (fn(core::option::Option, 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), 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) -> type-names::Mod1::Struct2, uint) + +// gdb-command:whatis extern_stdcall_fn_with_return_value +// gdb-check:type = struct (extern "stdcall" fn(Box) -> 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; + +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 { + Variant3_1, + Variant3_2(T), + } + } +} + +trait Trait1 { } +trait Trait2 { } + +impl Trait1 for int {} +impl Trait2 for int {} + +fn rust_fn(_: Option, _: Option<&Mod1::Struct2>) {} +extern "C" fn extern_c_fn(_: int) {} +unsafe fn unsafe_fn(_: Result) {} +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) -> Mod1::Struct2 { Mod1::Struct2 } +extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box) -> uint { 0 } + +fn generic_function(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, 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 = GenericStruct; + let generic_struct2: GenericStruct 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::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::, 0i32); + + let mut mut_struct1 = Struct1; + let mut mut_generic_struct = GenericStruct::; + 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, 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, 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; + 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>; + let generic_ref_trait = (&0i) as &Trait2; + + let mut generic_mut_ref_trait_impl = 0i; + let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as + &mut Trait2>; + + // 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::, 0u); + let generic_function_struct3 = (generic_function::, 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() { () }