Skip to content

Commit

Permalink
Fix computation of enum names based off the discrfield in the case of…
Browse files Browse the repository at this point in the history
… the null pointer optimization. This functionality is needed by pretty printers for gdb and lldb.
  • Loading branch information
ahicks92 committed Dec 14, 2016
1 parent a65cc1e commit 9966bbd
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 23 deletions.
46 changes: 29 additions & 17 deletions src/librustc/ty/layout.rs
Expand Up @@ -717,16 +717,18 @@ impl<'a, 'gcx, 'tcx> Struct {

/// Find the path leading to a non-zero leaf field, starting from
/// 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.
fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'gcx>)
-> Result<Option<FieldPath>, LayoutError<'gcx>> {
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
match (ty.layout(infcx)?, &ty.sty) {
(&Scalar { non_zero: true, .. }, _) |
(&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])),
(&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
(&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?
Expand All @@ -737,10 +739,11 @@ impl<'a, 'gcx, 'tcx> Struct {
// FIXME(eddyb) also allow floating-point types here.
Scalar { value: Int(_), non_zero: false } |
Scalar { value: Pointer, non_zero: false } => {
Ok(Some(vec![0]))
Ok(Some((vec![0], vec![0])))
}
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)
}
Expand All @@ -749,7 +752,7 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the fields of this struct is non-zero
// let's recurse and find out
(&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| {
field.ty(tcx, substs)
}),
Expand All @@ -759,19 +762,19 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the upvars of this closure is non-zero
(&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
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[..]))
}
// Can we use one of the fields in this tuple?
(&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[..]))
}

// Is this a fixed-size array of something non-zero
// with at least one element?
(_, &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(..)) => {
Expand All @@ -789,20 +792,23 @@ impl<'a, 'gcx, 'tcx> Struct {

/// Find the path leading to a non-zero leaf field, starting from
/// 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,
permutation: Option<&[u32]>)
-> Result<Option<FieldPath>, LayoutError<'gcx>>
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
where I: Iterator<Item=Ty<'gcx>> {
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 {
p[i] as usize
} else {
i
};
path.push(index as u32);
return Ok(Some(path));
return Ok(Some((path, source_path)));
}
}
Ok(None)
Expand Down Expand Up @@ -965,7 +971,9 @@ pub enum Layout {
nndiscr: u64,
nonnull: Struct,
// 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
}
}

Expand Down Expand Up @@ -1242,10 +1250,11 @@ impl<'a, 'gcx, 'tcx> Layout {
if !Struct::would_be_zero_sized(dl, other_fields)? {
continue;
}
let path = Struct::non_zero_field_path(infcx,
let paths = Struct::non_zero_field_paths(infcx,
variants[discr].iter().cloned(),
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.
if path == &[0] && variants[discr].len() == 1 {
Expand Down Expand Up @@ -1273,11 +1282,14 @@ impl<'a, 'gcx, 'tcx> Layout {
*path.last_mut().unwrap() = i;
path.push(0); // For GEP through a pointer.
path.reverse();
path_source.push(0);
path_source.reverse();

return success(StructWrappedNullablePointer {
nndiscr: discr as u64,
nonnull: st,
discrfield: path
discrfield: path,
discrfield_source: path_source
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/base.rs
Expand Up @@ -1870,7 +1870,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
match **layout {
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
nndiscr,
discrfield: _ } => {
discrfield: _,
discrfield_source: _ } => {
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize];
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/debuginfo/metadata.rs
Expand Up @@ -1258,7 +1258,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
},
layout::StructWrappedNullablePointer { nonnull: ref struct_def,
nndiscr,
ref discrfield, ..} => {
ref discrfield_source, ..} => {
// Create a description of the non-null variant
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
Expand All @@ -1281,12 +1281,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
// member's name.
let null_variant_index = (1 - nndiscr) as usize;
let null_variant_name = adt.variants[null_variant_index].name;
let discrfield = discrfield.iter()
let discrfield_source = discrfield_source.iter()
.skip(1)
.map(|x| x.to_string())
.collect::<Vec<_>>().join("$");
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
discrfield,
discrfield_source,
null_variant_name);

// Create the (singleton) list of descriptions of union members.
Expand Down
4 changes: 2 additions & 2 deletions src/test/debuginfo/struct-in-enum.rs
Expand Up @@ -19,11 +19,11 @@
// gdb-command:run

// 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})

// 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)

// gdb-command:print univariant
Expand Down

0 comments on commit 9966bbd

Please sign in to comment.