debuginfo: Make DWARF representation of enums uniform.

So far the DWARF information for enums was different
for regular enums, univariant enums, Option-like enums,
etc. Regular enums were encoded as unions of structs,
while the other variants were encoded as bare structs.

With the changes in this PR all enums are encoded as
unions so that debuggers can reconstruct if something
originally was a struct, a univariant enum, or an
Option-like enum. For the latter case, information
about the Null variant is encoded into the union field
name. This information can then be used by the
debugger to print a None value actually as None
instead of Some(0x0).
This commit is contained in:
Michael Woerister 2014-05-15 15:33:51 +02:00
parent 138089355d
commit eea329b0f7
11 changed files with 221 additions and 145 deletions

View file

@ -1272,7 +1272,7 @@ enum RecursiveTypeDescription {
}
impl RecursiveTypeDescription {
// Finishes up the description of the type in question (mostly by providing description of the
// Finishes up the description of the type in question (mostly by providing descriptions of the
// fields of the given type) and returns the final type metadata.
fn finalize(&self, cx: &CrateContext) -> DICompositeType {
match *self {
@ -1453,7 +1453,7 @@ fn prepare_tuple_metadata(cx: &CrateContext,
struct EnumMemberDescriptionFactory {
type_rep: Rc<adt::Repr>,
variants: Rc<Vec<Rc<ty::VariantInfo>>>,
discriminant_type_metadata: DIType,
discriminant_type_metadata: Option<DIType>,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span,
@ -1461,11 +1461,10 @@ struct EnumMemberDescriptionFactory {
impl EnumMemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription> {
// Capture type_rep, so we don't have to copy the struct_defs array
let struct_defs = match *self.type_rep {
adt::General(_, ref struct_defs) => struct_defs,
_ => cx.sess().bug("unreachable")
};
match *self.type_rep {
adt::General(_, ref struct_defs) => {
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
.expect(""));
struct_defs
.iter()
@ -1475,13 +1474,13 @@ impl EnumMemberDescriptionFactory {
describe_enum_variant(cx,
struct_def,
&**self.variants.get(i),
RegularDiscriminant(self.discriminant_type_metadata),
discriminant_info,
self.containing_scope,
self.file_metadata,
self.span);
let member_descriptions =
member_desc_factory.create_member_descriptions(cx);
let member_descriptions = member_desc_factory
.create_member_descriptions(cx);
set_members_of_composite_type(cx,
variant_type_metadata,
@ -1496,6 +1495,136 @@ impl EnumMemberDescriptionFactory {
offset: FixedMemberOffset { bytes: 0 },
}
}).collect()
},
adt::Univariant(ref struct_def, _) => {
assert!(self.variants.len() <= 1);
if self.variants.len() == 0 {
vec![]
} else {
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
struct_def,
&**self.variants.get(0),
NoDiscriminant,
self.containing_scope,
self.file_metadata,
self.span);
let member_descriptions =
member_description_factory.create_member_descriptions(cx);
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
member_descriptions.as_slice(),
self.file_metadata,
codemap::DUMMY_SP);
vec![
MemberDescription {
name: "".to_string(),
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
}
]
}
}
adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
// As far as debuginfo is concerned, the pointer this enum represents is still
// wrapped in a struct. This is to make the DWARF representation of enums uniform.
// First create a description of the artifical wrapper struct:
let non_null_variant = self.variants.get(non_null_variant_index as uint);
let non_null_variant_ident = non_null_variant.name;
let non_null_variant_name = token::get_ident(non_null_variant_ident);
// The llvm type and metadata of the pointer
let non_null_llvm_type = type_of::type_of(cx, nnty);
let non_null_type_metadata = type_metadata(cx, nnty, self.span);
// The type of the artificial struct wrapping the pointer
let artificial_struct_llvm_type = Type::struct_(cx, &[non_null_llvm_type], false);
// For the metadata of the wrapper struct, we need to create a MemberDescription
// of the struct's single field.
let sole_struct_member_description = MemberDescription {
name: match non_null_variant.arg_names {
Some(ref names) => token::get_ident(*names.get(0)).get().to_string(),
None => "".to_string()
},
llvm_type: non_null_llvm_type,
type_metadata: non_null_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
};
// Now we can create the metadata of the artificial struct
let artificial_struct_metadata =
composite_type_metadata(cx,
artificial_struct_llvm_type,
non_null_variant_name.get(),
&[sole_struct_member_description],
self.containing_scope,
self.file_metadata,
codemap::DUMMY_SP);
// Encode the information about the null variant in the union member's name
let null_variant_index = (1 - non_null_variant_index) as uint;
let null_variant_ident = self.variants.get(null_variant_index).name;
let null_variant_name = token::get_ident(null_variant_ident);
let union_member_name = format!("RUST$ENCODED$ENUM${}${}", 0, null_variant_name);
// Finally create the (singleton) list of descriptions of union members
vec![
MemberDescription {
name: union_member_name,
llvm_type: artificial_struct_llvm_type,
type_metadata: artificial_struct_metadata,
offset: FixedMemberOffset { bytes: 0 },
}
]
},
adt::StructWrappedNullablePointer { nonnull: ref struct_def, nndiscr, ptrfield, ..} => {
// Create a description of the non-null variant
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
struct_def,
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
self.containing_scope,
self.file_metadata,
self.span);
let variant_member_descriptions =
member_description_factory.create_member_descriptions(cx);
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
variant_member_descriptions.as_slice(),
self.file_metadata,
codemap::DUMMY_SP);
// Encode the information about the null variant in the union member's name
let null_variant_index = (1 - nndiscr) as uint;
let null_variant_ident = self.variants.get(null_variant_index).name;
let null_variant_name = token::get_ident(null_variant_ident);
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
ptrfield,
null_variant_name);
// Create the (singleton) list of descriptions of union members
vec![
MemberDescription {
name: union_member_name,
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
}
]
},
adt::CEnum(..) => cx.sess().span_bug(self.span, "This should be unreachable.")
}
}
}
@ -1546,7 +1675,7 @@ fn describe_enum_variant(cx: &CrateContext,
.collect::<Vec<_>>()
.as_slice(),
struct_def.packed);
// Could some consistency checks here: size, align, field count, discr type
// 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 {
@ -1610,21 +1739,6 @@ fn prepare_enum_metadata(cx: &CrateContext,
let loc = span_start(cx, definition_span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
// For empty enums there is an early exit. Just describe it as an empty struct with the
// appropriate type name
if ty::type_is_empty(cx.tcx(), enum_type) {
let empty_type_metadata = composite_type_metadata(
cx,
Type::nil(cx),
enum_name.as_slice(),
[],
containing_scope,
file_metadata,
definition_span);
return FinalMetadata(empty_type_metadata);
}
let variants = ty::enum_variants(cx.tcx(), enum_def_id);
let enumerators_metadata: Vec<DIDescriptor> = variants
@ -1685,32 +1799,16 @@ fn prepare_enum_metadata(cx: &CrateContext,
let type_rep = adt::represent_type(cx, enum_type);
return match *type_rep {
let discriminant_type_metadata = match *type_rep {
adt::CEnum(inttype, _, _) => {
FinalMetadata(discriminant_type_metadata(inttype))
}
adt::Univariant(ref struct_def, _) => {
assert!(variants.len() == 1);
let (metadata_stub,
variant_llvm_type,
member_description_factory) =
describe_enum_variant(cx,
struct_def,
&**variants.get(0),
NoDiscriminant,
containing_scope,
file_metadata,
span);
UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: metadata_stub,
llvm_type: variant_llvm_type,
file_metadata: file_metadata,
member_description_factory: member_description_factory
}
}
adt::General(inttype, _) => {
let discriminant_type_metadata = discriminant_type_metadata(inttype);
return FinalMetadata(discriminant_type_metadata(inttype))
},
adt::RawNullablePointer { .. } |
adt::StructWrappedNullablePointer { .. } |
adt::Univariant(..) => None,
adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
};
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
let unique_id = generate_unique_type_id("DI_ENUM_");
@ -1734,7 +1832,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
})
});
UnfinishedMetadata {
return UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: enum_metadata,
llvm_type: enum_llvm_type,
@ -1747,30 +1845,6 @@ fn prepare_enum_metadata(cx: &CrateContext,
file_metadata: file_metadata,
span: span,
}),
}
}
adt::RawNullablePointer { nnty, .. } => {
FinalMetadata(type_metadata(cx, nnty, span))
}
adt::StructWrappedNullablePointer { nonnull: ref struct_def, nndiscr, ptrfield, .. } => {
let (metadata_stub,
variant_llvm_type,
member_description_factory) =
describe_enum_variant(cx,
struct_def,
&**variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
containing_scope,
file_metadata,
span);
UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: metadata_stub,
llvm_type: variant_llvm_type,
file_metadata: file_metadata,
member_description_factory: member_description_factory
}
}
};
fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {

View file

@ -22,7 +22,7 @@
// gdb-check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
// gdb-command:print *univariant_ref
// gdb-check:$3 = {4820353753753434}
// gdb-check:$3 = {{4820353753753434}}
#![allow(unused_variable)]
#![feature(struct_variant)]

View file

@ -27,7 +27,7 @@
// gdb-check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}}
// gdb-command:print univariant
// gdb-check:$4 = {a = -1}
// gdb-check:$4 = {{a = -1}}
#![feature(struct_variant)]

View file

@ -27,7 +27,7 @@
// gdb-check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}}
// gdb-command:print univariant
// gdb-check:$4 = {-1}
// gdb-check:$4 = {{-1}}
// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be

View file

@ -22,7 +22,7 @@
// gdb-check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
// gdb-command:print univariant->val
// gdb-check:$3 = {-9747455}
// gdb-check:$3 = {{-9747455}}
#![allow(unused_variable)]
#![feature(struct_variant, managed_boxes)]

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
// ignore-android: FIXME(#10381)
// compile-flags:-g
@ -16,19 +17,19 @@
// gdb-command:finish
// gdb-command:print some
// gdb-check:$1 = (u32 *) 0x12345678
// gdb-check:$1 = {RUST$ENCODED$ENUM$0$None = {0x12345678}}
// gdb-command:print none
// gdb-check:$2 = (u32 *) 0x0
// gdb-check:$2 = {RUST$ENCODED$ENUM$0$None = {0x0}}
// gdb-command:print full
// gdb-check:$3 = {454545, 0x87654321, 9988}
// gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {454545, 0x87654321, 9988}}
// gdb-command:print empty->discr
// gdb-check:$4 = (int *) 0x0
// gdb-command:print droid
// gdb-check:$5 = {id = 675675, range = 10000001, internals = 0x43218765}
// gdb-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}}
// gdb-command:print void_droid->internals
// gdb-check:$6 = (int *) 0x0

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
// ignore-android: FIXME(#10381)
#![feature(managed_boxes)]
@ -20,53 +21,53 @@
// gdb-command:print stack_unique.value
// gdb-check:$1 = 0
// gdb-command:print stack_unique.next->value
// gdb-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value
// gdb-check:$2 = 1
// gdb-command:print unique_unique->value
// gdb-check:$3 = 2
// gdb-command:print unique_unique->next->value
// gdb-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
// gdb-check:$4 = 3
// gdb-command:print box_unique->val.value
// gdb-check:$5 = 4
// gdb-command:print box_unique->val.next->value
// gdb-command:print box_unique->val.next.RUST$ENCODED$ENUM$0$Empty.val->value
// gdb-check:$6 = 5
// gdb-command:print vec_unique[0].value
// gdb-check:$7 = 6.5
// gdb-command:print vec_unique[0].next->value
// gdb-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value
// gdb-check:$8 = 7.5
// gdb-command:print borrowed_unique->value
// gdb-check:$9 = 8.5
// gdb-command:print borrowed_unique->next->value
// gdb-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
// gdb-check:$10 = 9.5
// MANAGED
// gdb-command:print stack_managed.value
// gdb-check:$11 = 10
// gdb-command:print stack_managed.next.val->value
// gdb-command:print stack_managed.next.RUST$ENCODED$ENUM$0$Empty.val->val.value
// gdb-check:$12 = 11
// gdb-command:print unique_managed->value
// gdb-check:$13 = 12
// gdb-command:print unique_managed->next.val->value
// gdb-command:print unique_managed->next.RUST$ENCODED$ENUM$0$Empty.val->val.value
// gdb-check:$14 = 13
// gdb-command:print box_managed.val->value
// gdb-check:$15 = 14
// gdb-command:print box_managed->val->next.val->value
// gdb-command:print box_managed->val->next.RUST$ENCODED$ENUM$0$Empty.val->val.value
// gdb-check:$16 = 15
// gdb-command:print vec_managed[0].value
// gdb-check:$17 = 16.5
// gdb-command:print vec_managed[0].next.val->value
// gdb-command:print vec_managed[0].next.RUST$ENCODED$ENUM$0$Empty.val->val.value
// gdb-check:$18 = 17.5
// gdb-command:print borrowed_managed->value
// gdb-check:$19 = 18.5
// gdb-command:print borrowed_managed->next.val->value
// gdb-command:print borrowed_managed->next.RUST$ENCODED$ENUM$0$Empty.val->val.value
// gdb-check:$20 = 19.5
// LONG CYCLE
@ -97,7 +98,7 @@
// gdb-command:print (*****long_cycle_w_anonymous_types).value
// gdb-check:$31 = 30
// gdb-command:print (*****((*****long_cycle_w_anonymous_types).next)).value
// gdb-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value
// gdb-check:$32 = 31
// gdb-command:continue

View file

@ -24,7 +24,7 @@
// gdb-check:$2 = {{Case2, 0, {x = 286331153, y = 286331153, z = 4369}}, {Case2, 0, 1229782938247303441, 4369}}
// gdb-command:print univariant
// gdb-check:$3 = {{x = 123, y = 456, z = 789}}
// gdb-check:$3 = {{{x = 123, y = 456, z = 789}}}
#![allow(unused_variable)]

View file

@ -27,7 +27,7 @@
// gdb-check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}}
// gdb-command:print univariant
// gdb-check:$4 = {a = -1}
// gdb-check:$4 = {{a = -1}}
#![allow(unused_variable)]
#![feature(struct_variant)]

View file

@ -27,7 +27,7 @@
// gdb-check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}}
// gdb-command:print univariant
// gdb-check:$4 = {-1}
// gdb-check:$4 = {{-1}}
#![allow(unused_variable)]

View file

@ -22,7 +22,7 @@
// gdb-check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
// gdb-command:print *univariant
// gdb-check:$3 = {123234}
// gdb-check:$3 = {{123234}}
#![allow(unused_variable)]
#![feature(struct_variant)]