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
//=-----------------------------------------------------------------------------
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 ");
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));
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));
}
}
+// 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 {
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(",");
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 {
-> 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(
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory,
},
FinalMetadata(DICompositeType)
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory)
-> RecursiveTypeDescription {
unique_type_id: unique_type_id,
metadata_stub: metadata_stub,
llvm_type: llvm_type,
- file_metadata: file_metadata,
member_description_factory: member_description_factory,
}
}
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
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);
}
}
}
}
+
fn prepare_struct_metadata(cx: &CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
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);
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),
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,
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,
&**self.variants.get(i),
discriminant_info,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions = member_desc_factory
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,
&**self.variants.get(0),
NoDiscriminant,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions =
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(),
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
self.containing_scope,
- self.file_metadata,
self.span);
let variant_member_descriptions =
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.
variant_info: &ty::VariantInfo,
discriminant_info: EnumDiscriminantInfo,
containing_scope: DIScope,
- file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, MemberDescriptionFactory) {
let variant_llvm_type =
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
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 {
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);
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()),
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
unique_type_id,
enum_metadata,
enum_llvm_type,
- file_metadata,
EnumMDF(EnumMemberDescriptionFactory {
enum_type: enum_type,
type_rep: type_rep.clone(),
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().
}
}
- let loc = span_start(cx, definition_span);
-
let member_metadata: Vec<DIDescriptor> = member_descriptions
.iter()
.enumerate()
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),
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
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,
-> 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);
let nil_pointer_type_metadata = type_metadata(cx,
nil_pointer_type,
codemap::DUMMY_SP);
-
let member_descriptions = [
MemberDescription {
name: "refcnt".to_string(),
}
];
- 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);
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,
-> 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);
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();
vec_pointer_type_name,
vec_box_unique_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
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,
slice_type_name.as_slice(),
unique_type_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
return MetadataCreationResult::new(metadata, false);
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
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,
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 |
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)
}
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)
}
}
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()];
}
+//=-----------------------------------------------------------------------------
+// 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
//=-----------------------------------------------------------------------------
}
}
+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
--- /dev/null
+// 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() { () }