Fix computation of enum names based off the discrfield in the case of the null pointer optimization. This functionality is needed by pretty printers for gdb and lldb.

This commit is contained in:
Austin Hicks 2016-12-02 19:24:24 -05:00
parent a65cc1ea54
commit 9966bbd1b1
4 changed files with 36 additions and 23 deletions

View file

@ -717,16 +717,18 @@ impl<'a, 'gcx, 'tcx> Struct {
/// Find the path leading to a non-zero leaf field, starting from /// Find the path leading to a non-zero leaf field, starting from
/// the given type and recursing through aggregates. /// the given type and recursing through aggregates.
/// The tuple is `(path, source_path)1,
/// where `path` is in memory order and `source_path` in source order.
// FIXME(eddyb) track value ranges and traverse already optimized enums. // FIXME(eddyb) track value ranges and traverse already optimized enums.
fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>, fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'gcx>) ty: Ty<'gcx>)
-> Result<Option<FieldPath>, LayoutError<'gcx>> { -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx(); let tcx = infcx.tcx.global_tcx();
match (ty.layout(infcx)?, &ty.sty) { match (ty.layout(infcx)?, &ty.sty) {
(&Scalar { non_zero: true, .. }, _) | (&Scalar { non_zero: true, .. }, _) |
(&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])), (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
(&FatPointer { non_zero: true, .. }, _) => { (&FatPointer { non_zero: true, .. }, _) => {
Ok(Some(vec![FAT_PTR_ADDR as u32])) Ok(Some((vec![FAT_PTR_ADDR as u32], vec![FAT_PTR_ADDR as u32])))
} }
// Is this the NonZero lang item wrapping a pointer or integer type? // Is this the NonZero lang item wrapping a pointer or integer type?
@ -737,10 +739,11 @@ impl<'a, 'gcx, 'tcx> Struct {
// FIXME(eddyb) also allow floating-point types here. // FIXME(eddyb) also allow floating-point types here.
Scalar { value: Int(_), non_zero: false } | Scalar { value: Int(_), non_zero: false } |
Scalar { value: Pointer, non_zero: false } => { Scalar { value: Pointer, non_zero: false } => {
Ok(Some(vec![0])) Ok(Some((vec![0], vec![0])))
} }
FatPointer { non_zero: false, .. } => { FatPointer { non_zero: false, .. } => {
Ok(Some(vec![FAT_PTR_ADDR as u32, 0])) let tmp = vec![FAT_PTR_ADDR as u32, 0];
Ok(Some((tmp.clone(), tmp)))
} }
_ => Ok(None) _ => Ok(None)
} }
@ -749,7 +752,7 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the fields of this struct is non-zero // Perhaps one of the fields of this struct is non-zero
// let's recurse and find out // let's recurse and find out
(&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
Struct::non_zero_field_path(infcx, def.struct_variant().fields Struct::non_zero_field_paths(infcx, def.struct_variant().fields
.iter().map(|field| { .iter().map(|field| {
field.ty(tcx, substs) field.ty(tcx, substs)
}), }),
@ -759,19 +762,19 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the upvars of this closure is non-zero // Perhaps one of the upvars of this closure is non-zero
(&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => { (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
let upvar_tys = substs.upvar_tys(def, tcx); let upvar_tys = substs.upvar_tys(def, tcx);
Struct::non_zero_field_path(infcx, upvar_tys, Struct::non_zero_field_paths(infcx, upvar_tys,
Some(&variant.memory_index[..])) Some(&variant.memory_index[..]))
} }
// Can we use one of the fields in this tuple? // Can we use one of the fields in this tuple?
(&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => { (&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
Struct::non_zero_field_path(infcx, tys.iter().cloned(), Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
Some(&variant.memory_index[..])) Some(&variant.memory_index[..]))
} }
// Is this a fixed-size array of something non-zero // Is this a fixed-size array of something non-zero
// with at least one element? // with at least one element?
(_, &ty::TyArray(ety, d)) if d > 0 => { (_, &ty::TyArray(ety, d)) if d > 0 => {
Struct::non_zero_field_path(infcx, Some(ety).into_iter(), None) Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
} }
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
@ -789,20 +792,23 @@ impl<'a, 'gcx, 'tcx> Struct {
/// Find the path leading to a non-zero leaf field, starting from /// Find the path leading to a non-zero leaf field, starting from
/// the given set of fields and recursing through aggregates. /// the given set of fields and recursing through aggregates.
fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // / Returns Some((path, source_path)) on success.
/// `path` is translated to memory order. `source_path` is not.
fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
fields: I, fields: I,
permutation: Option<&[u32]>) permutation: Option<&[u32]>)
-> Result<Option<FieldPath>, LayoutError<'gcx>> -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
where I: Iterator<Item=Ty<'gcx>> { where I: Iterator<Item=Ty<'gcx>> {
for (i, ty) in fields.enumerate() { for (i, ty) in fields.enumerate() {
if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? { if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
source_path.push(i as u32);
let index = if let Some(p) = permutation { let index = if let Some(p) = permutation {
p[i] as usize p[i] as usize
} else { } else {
i i
}; };
path.push(index as u32); path.push(index as u32);
return Ok(Some(path)); return Ok(Some((path, source_path)));
} }
} }
Ok(None) Ok(None)
@ -965,7 +971,9 @@ pub enum Layout {
nndiscr: u64, nndiscr: u64,
nonnull: Struct, nonnull: Struct,
// N.B. There is a 0 at the start, for LLVM GEP through a pointer. // N.B. There is a 0 at the start, for LLVM GEP through a pointer.
discrfield: FieldPath discrfield: FieldPath,
// Like discrfield, but in source order. For debuginfo.
discrfield_source: FieldPath
} }
} }
@ -1242,10 +1250,11 @@ impl<'a, 'gcx, 'tcx> Layout {
if !Struct::would_be_zero_sized(dl, other_fields)? { if !Struct::would_be_zero_sized(dl, other_fields)? {
continue; continue;
} }
let path = Struct::non_zero_field_path(infcx, let paths = Struct::non_zero_field_paths(infcx,
variants[discr].iter().cloned(), variants[discr].iter().cloned(),
None)?; None)?;
let mut path = if let Some(p) = path { p } else { continue }; let (mut path, mut path_source) = if let Some(p) = paths { p }
else { continue };
// FIXME(eddyb) should take advantage of a newtype. // FIXME(eddyb) should take advantage of a newtype.
if path == &[0] && variants[discr].len() == 1 { if path == &[0] && variants[discr].len() == 1 {
@ -1273,11 +1282,14 @@ impl<'a, 'gcx, 'tcx> Layout {
*path.last_mut().unwrap() = i; *path.last_mut().unwrap() = i;
path.push(0); // For GEP through a pointer. path.push(0); // For GEP through a pointer.
path.reverse(); path.reverse();
path_source.push(0);
path_source.reverse();
return success(StructWrappedNullablePointer { return success(StructWrappedNullablePointer {
nndiscr: discr as u64, nndiscr: discr as u64,
nonnull: st, nonnull: st,
discrfield: path discrfield: path,
discrfield_source: path_source
}); });
} }
} }

View file

@ -1870,7 +1870,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
match **layout { match **layout {
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout, Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
nndiscr, nndiscr,
discrfield: _ } => { discrfield: _,
discrfield_source: _ } => {
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}", debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout); ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize]; let variant_def = &adt_def.variants[nndiscr as usize];

View file

@ -1258,7 +1258,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
}, },
layout::StructWrappedNullablePointer { nonnull: ref struct_def, layout::StructWrappedNullablePointer { nonnull: ref struct_def,
nndiscr, nndiscr,
ref discrfield, ..} => { ref discrfield_source, ..} => {
// Create a description of the non-null variant // Create a description of the non-null variant
let (variant_type_metadata, variant_llvm_type, member_description_factory) = let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx, describe_enum_variant(cx,
@ -1281,12 +1281,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
// member's name. // member's name.
let null_variant_index = (1 - nndiscr) as usize; let null_variant_index = (1 - nndiscr) as usize;
let null_variant_name = adt.variants[null_variant_index].name; let null_variant_name = adt.variants[null_variant_index].name;
let discrfield = discrfield.iter() let discrfield_source = discrfield_source.iter()
.skip(1) .skip(1)
.map(|x| x.to_string()) .map(|x| x.to_string())
.collect::<Vec<_>>().join("$"); .collect::<Vec<_>>().join("$");
let union_member_name = format!("RUST$ENCODED$ENUM${}${}", let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
discrfield, discrfield_source,
null_variant_name); null_variant_name);
// Create the (singleton) list of descriptions of union members. // Create the (singleton) list of descriptions of union members.

View file

@ -19,11 +19,11 @@
// gdb-command:run // gdb-command:run
// gdb-command:print case1 // gdb-command:print case1
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}} // gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, [...]}}
// gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868}) // gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868})
// gdb-command:print case2 // gdb-command:print case2
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}} // gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
// gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369) // gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369)
// gdb-command:print univariant // gdb-command:print univariant