@@ -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,14 +606,27 @@ 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));
UniqueTypeId(interner_key)
}
}

// 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,28 +1865,24 @@ impl StructMemberDescriptionFactory {
}
}


fn prepare_struct_metadata(cx: &CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
substs: &subst::Substs,
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
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,34 +2409,31 @@ 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;
}

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()];
@@ -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 &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
@@ -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() { () }