Generate better debuginfo for niche-layout enums
Previously, we would generate a single struct with the layout of the dataful variant plus an extra field whose name contained the value of the niche (this would only really work for things like `Option<&_>` where we can determine that the `None` case maps to `0` but for enums that have multiple tag only variants, this doesn't work). Now, we generate a union of two structs, one which is the layout of the dataful variant and one which just has a way of reading the discriminant. We also generate an enum which maps the discriminant value to the tag only variants. We also encode information about the range of values which correspond to the dataful variant in the type name and then use natvis to determine which union field we should display to the user. As a result of this change, all niche-layout enums render correctly in WinDbg and Visual Studio!
This commit is contained in:
parent
2a025c1a76
commit
141546c355
3 changed files with 191 additions and 81 deletions
|
@ -3,7 +3,8 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
|
||||
use rustc_target::abi::{TagEncoding, Variants};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
|
@ -46,14 +47,10 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
|
||||
ty::Adt(def, substs) => {
|
||||
if def.is_enum() && cpp_like_names {
|
||||
output.push_str("_enum<");
|
||||
}
|
||||
|
||||
push_item_name(tcx, def.did, qualified, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
|
||||
if def.is_enum() && cpp_like_names {
|
||||
output.push('>');
|
||||
msvc_enum_fallback(tcx, t, def, substs, output, visited);
|
||||
} else {
|
||||
push_item_name(tcx, def.did, qualified, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
|
@ -241,6 +238,50 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn msvc_enum_fallback(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
def: &AdtDef,
|
||||
substs: SubstsRef<'tcx>,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
|
||||
|
||||
if let Variants::Multiple {
|
||||
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
|
||||
tag,
|
||||
variants,
|
||||
..
|
||||
} = &layout.variants
|
||||
{
|
||||
let dataful_variant_layout = &variants[*dataful_variant];
|
||||
|
||||
// calculate the range of values for the dataful variant
|
||||
let dataful_discriminant_range =
|
||||
&dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
|
||||
|
||||
let min = dataful_discriminant_range.start();
|
||||
let min = tag.value.size(&tcx).truncate(*min);
|
||||
|
||||
let max = dataful_discriminant_range.end();
|
||||
let max = tag.value.size(&tcx).truncate(*max);
|
||||
|
||||
output.push_str("_enum<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
|
||||
let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
|
||||
|
||||
output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
|
||||
} else {
|
||||
output.push_str("_enum<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
output.push('>');
|
||||
}
|
||||
}
|
||||
|
||||
fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
|
||||
if qualified {
|
||||
output.push_str(&tcx.crate_name(def_id.krate).as_str());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue