mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
debuginfo: change cpp-like naming for generator environments so that NatVis works for them
This commit is contained in:
parent
07ebc13d87
commit
3ad299aa67
@ -16,13 +16,14 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
|
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
|
||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||||
use rustc_middle::ty::{self, AdtDef, ExistentialProjection, ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_query_system::ich::NodeIdHashingMode;
|
use rustc_query_system::ich::NodeIdHashingMode;
|
||||||
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::debuginfo::wants_c_like_enum_debuginfo;
|
use crate::debuginfo::wants_c_like_enum_debuginfo;
|
||||||
@ -76,7 +77,16 @@ fn push_debuginfo_type_name<'tcx>(
|
|||||||
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).expect("layout error");
|
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).expect("layout error");
|
||||||
|
|
||||||
if def.is_enum() && cpp_like_debuginfo && !wants_c_like_enum_debuginfo(ty_and_layout) {
|
if def.is_enum() && cpp_like_debuginfo && !wants_c_like_enum_debuginfo(ty_and_layout) {
|
||||||
msvc_enum_fallback(tcx, t, def, substs, output, visited);
|
msvc_enum_fallback(
|
||||||
|
tcx,
|
||||||
|
ty_and_layout,
|
||||||
|
&|output, visited| {
|
||||||
|
push_item_name(tcx, def.did(), true, output);
|
||||||
|
push_generic_params_internal(tcx, substs, output, visited);
|
||||||
|
},
|
||||||
|
output,
|
||||||
|
visited,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
push_item_name(tcx, def.did(), qualified, output);
|
push_item_name(tcx, def.did(), qualified, output);
|
||||||
push_generic_params_internal(tcx, substs, output, visited);
|
push_generic_params_internal(tcx, substs, output, visited);
|
||||||
@ -352,40 +362,26 @@ fn push_debuginfo_type_name<'tcx>(
|
|||||||
ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
|
ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
|
||||||
// Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
|
// Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
|
||||||
// "{async_fn_env#0}<T1, T2, ...>", etc.
|
// "{async_fn_env#0}<T1, T2, ...>", etc.
|
||||||
let def_key = tcx.def_key(def_id);
|
// In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
|
||||||
|
// an artificial `enum$<>` type, as defined in msvc_enum_fallback().
|
||||||
if qualified {
|
if cpp_like_debuginfo && matches!(t.kind(), ty::Generator(..)) {
|
||||||
let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
|
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
|
||||||
push_item_name(tcx, parent_def_id, true, output);
|
msvc_enum_fallback(
|
||||||
output.push_str("::");
|
tcx,
|
||||||
|
ty_and_layout,
|
||||||
|
&|output, visited| {
|
||||||
|
push_closure_or_generator_name(tcx, def_id, substs, true, output, visited);
|
||||||
|
},
|
||||||
|
output,
|
||||||
|
visited,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
push_closure_or_generator_name(tcx, def_id, substs, qualified, output, visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut label = String::with_capacity(20);
|
|
||||||
write!(&mut label, "{}_env", generator_kind_label(tcx.generator_kind(def_id))).unwrap();
|
|
||||||
|
|
||||||
push_disambiguated_special_name(
|
|
||||||
&label,
|
|
||||||
def_key.disambiguated_data.disambiguator,
|
|
||||||
cpp_like_debuginfo,
|
|
||||||
output,
|
|
||||||
);
|
|
||||||
|
|
||||||
// We also need to add the generic arguments of the async fn/generator or
|
|
||||||
// the enclosing function (for closures or async blocks), so that we end
|
|
||||||
// up with a unique name for every instantiation.
|
|
||||||
|
|
||||||
// Find the generics of the enclosing function, as defined in the source code.
|
|
||||||
let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
|
|
||||||
let generics = tcx.generics_of(enclosing_fn_def_id);
|
|
||||||
|
|
||||||
// Truncate the substs to the length of the above generics. This will cut off
|
|
||||||
// anything closure- or generator-specific.
|
|
||||||
let substs = substs.truncate_to(tcx, generics);
|
|
||||||
push_generic_params_internal(tcx, substs, output, visited);
|
|
||||||
}
|
}
|
||||||
// Type parameters from polymorphized functions.
|
// Type parameters from polymorphized functions.
|
||||||
ty::Param(_) => {
|
ty::Param(_) => {
|
||||||
output.push_str(&format!("{:?}", t));
|
write!(output, "{:?}", t).unwrap();
|
||||||
}
|
}
|
||||||
ty::Error(_)
|
ty::Error(_)
|
||||||
| ty::Infer(_)
|
| ty::Infer(_)
|
||||||
@ -408,24 +404,32 @@ fn push_debuginfo_type_name<'tcx>(
|
|||||||
// `EnumMemberDescriptionFactor::create_member_descriptions`.
|
// `EnumMemberDescriptionFactor::create_member_descriptions`.
|
||||||
fn msvc_enum_fallback<'tcx>(
|
fn msvc_enum_fallback<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty_and_layout: TyAndLayout<'tcx>,
|
||||||
def: AdtDef<'tcx>,
|
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
output: &mut String,
|
output: &mut String,
|
||||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let layout = tcx.layout_of(tcx.param_env(def.did()).and(ty)).expect("layout error");
|
debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
|
||||||
|
let ty = ty_and_layout.ty;
|
||||||
|
|
||||||
output.push_str("enum$<");
|
output.push_str("enum$<");
|
||||||
push_item_name(tcx, def.did(), true, output);
|
push_inner(output, visited);
|
||||||
push_generic_params_internal(tcx, substs, output, visited);
|
|
||||||
|
let variant_name = |variant_index| match ty.kind() {
|
||||||
|
ty::Adt(adt_def, _) => {
|
||||||
|
debug_assert!(adt_def.is_enum());
|
||||||
|
Cow::from(adt_def.variant(variant_index).name.as_str())
|
||||||
|
}
|
||||||
|
ty::Generator(..) => GeneratorSubsts::variant_name(variant_index),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
if let Variants::Multiple {
|
if let Variants::Multiple {
|
||||||
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
|
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
|
||||||
tag,
|
tag,
|
||||||
variants,
|
variants,
|
||||||
..
|
..
|
||||||
} = &layout.variants
|
} = &ty_and_layout.variants
|
||||||
{
|
{
|
||||||
let dataful_variant_layout = &variants[*dataful_variant];
|
let dataful_variant_layout = &variants[*dataful_variant];
|
||||||
|
|
||||||
@ -439,16 +443,13 @@ fn push_debuginfo_type_name<'tcx>(
|
|||||||
let max = dataful_discriminant_range.end;
|
let max = dataful_discriminant_range.end;
|
||||||
let max = tag.value.size(&tcx).truncate(max);
|
let max = tag.value.size(&tcx).truncate(max);
|
||||||
|
|
||||||
let dataful_variant_name = def.variant(*dataful_variant).name.as_str();
|
let dataful_variant_name = variant_name(*dataful_variant);
|
||||||
|
write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();
|
||||||
output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
|
} else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants {
|
||||||
} else if let Variants::Single { index: variant_idx } = &layout.variants {
|
|
||||||
// Uninhabited enums can't be constructed and should never need to be visualized so
|
// Uninhabited enums can't be constructed and should never need to be visualized so
|
||||||
// skip this step for them.
|
// skip this step for them.
|
||||||
if def.variants().len() != 0 {
|
if !ty_and_layout.abi.is_uninhabited() {
|
||||||
let variant = def.variant(*variant_idx).name.as_str();
|
write!(output, ", {}", variant_name(*variant_idx)).unwrap();
|
||||||
|
|
||||||
output.push_str(&format!(", {}", variant));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push_close_angle_bracket(true, output);
|
push_close_angle_bracket(true, output);
|
||||||
@ -700,6 +701,49 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out
|
|||||||
push_generic_params_internal(tcx, substs, output, &mut visited);
|
push_generic_params_internal(tcx, substs, output, &mut visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_closure_or_generator_name<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
qualified: bool,
|
||||||
|
output: &mut String,
|
||||||
|
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||||
|
) {
|
||||||
|
// Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
|
||||||
|
// "{async_fn_env#0}<T1, T2, ...>", etc.
|
||||||
|
let def_key = tcx.def_key(def_id);
|
||||||
|
let generator_kind = tcx.generator_kind(def_id);
|
||||||
|
|
||||||
|
if qualified {
|
||||||
|
let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
|
||||||
|
push_item_name(tcx, parent_def_id, true, output);
|
||||||
|
output.push_str("::");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut label = String::with_capacity(20);
|
||||||
|
write!(&mut label, "{}_env", generator_kind_label(generator_kind)).unwrap();
|
||||||
|
|
||||||
|
push_disambiguated_special_name(
|
||||||
|
&label,
|
||||||
|
def_key.disambiguated_data.disambiguator,
|
||||||
|
cpp_like_debuginfo(tcx),
|
||||||
|
output,
|
||||||
|
);
|
||||||
|
|
||||||
|
// We also need to add the generic arguments of the async fn/generator or
|
||||||
|
// the enclosing function (for closures or async blocks), so that we end
|
||||||
|
// up with a unique name for every instantiation.
|
||||||
|
|
||||||
|
// Find the generics of the enclosing function, as defined in the source code.
|
||||||
|
let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
|
||||||
|
let generics = tcx.generics_of(enclosing_fn_def_id);
|
||||||
|
|
||||||
|
// Truncate the substs to the length of the above generics. This will cut off
|
||||||
|
// anything closure- or generator-specific.
|
||||||
|
let substs = substs.truncate_to(tcx, generics);
|
||||||
|
push_generic_params_internal(tcx, substs, output, visited);
|
||||||
|
}
|
||||||
|
|
||||||
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
|
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
|
||||||
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
|
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
|
||||||
// so add a space to avoid confusion.
|
// so add a space to avoid confusion.
|
||||||
|
@ -16,7 +16,7 @@ async fn async_fn_test() {
|
|||||||
|
|
||||||
// FIXME: No way to reliably check the filename.
|
// FIXME: No way to reliably check the filename.
|
||||||
|
|
||||||
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn_env$0", {{.*}}, align: {{32|64}},
|
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$<async_fn_debug_msvc::async_fn_test::async_fn_env$0>",
|
||||||
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
|
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
|
||||||
// For brevity, we only check the struct name and members of the last variant.
|
// For brevity, we only check the struct name and members of the last variant.
|
||||||
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
|
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
|
||||||
|
@ -20,7 +20,7 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
|
|||||||
|
|
||||||
// FIXME: No way to reliably check the filename.
|
// FIXME: No way to reliably check the filename.
|
||||||
|
|
||||||
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator_env$0"
|
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$<generator_debug_msvc::generator_test::generator_env$0>"
|
||||||
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
|
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
|
||||||
// For brevity, we only check the struct name and members of the last variant.
|
// For brevity, we only check the struct name and members of the last variant.
|
||||||
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
|
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
|
||||||
|
@ -37,6 +37,37 @@
|
|||||||
// lldb-command:print b
|
// lldb-command:print b
|
||||||
// lldbg-check:(generator_objects::main::{generator_env#0}) $3 =
|
// lldbg-check:(generator_objects::main::{generator_env#0}) $3 =
|
||||||
|
|
||||||
|
// === CDB TESTS ===================================================================================
|
||||||
|
|
||||||
|
// cdb-command: g
|
||||||
|
// cdb-command: dx b
|
||||||
|
// cdb-check: b : Unresumed [Type: enum$<generator_objects::main::generator_env$0>]
|
||||||
|
// cdb-check: [variant] : Unresumed
|
||||||
|
// cdb-check: [+0x000] _ref__a : 0x[...] : 5 [Type: int *]
|
||||||
|
|
||||||
|
// cdb-command: g
|
||||||
|
// cdb-command: dx b
|
||||||
|
// cdb-check: b : Suspend0 [Type: enum$<generator_objects::main::generator_env$0>]
|
||||||
|
// cdb-check: [variant] : Suspend0
|
||||||
|
// cdb-check: [+0x008] c : 6 [Type: int]
|
||||||
|
// cdb-check: [+0x00c] d : 7 [Type: int]
|
||||||
|
// cdb-check: [+0x000] _ref__a : 0x[...] : 5 [Type: int *]
|
||||||
|
|
||||||
|
// cdb-command: g
|
||||||
|
// cdb-command: dx b
|
||||||
|
// cdb-check: b : Suspend1 [Type: enum$<generator_objects::main::generator_env$0>]
|
||||||
|
// cdb-check: [variant] : Suspend1
|
||||||
|
// cdb-check: [+0x008] c : 7 [Type: int]
|
||||||
|
// cdb-check: [+0x00c] d : 8 [Type: int]
|
||||||
|
// cdb-check: [+0x000] _ref__a : 0x[...] : 6 [Type: int *]
|
||||||
|
|
||||||
|
// cdb-command: g
|
||||||
|
// cdb-command: dx b
|
||||||
|
// cdb-check: b : Returned [Type: enum$<generator_objects::main::generator_env$0>]
|
||||||
|
// cdb-check: [<Raw View>] [Type: enum$<generator_objects::main::generator_env$0>]
|
||||||
|
// cdb-check: [variant] : Returned
|
||||||
|
// cdb-check: [+0x000] _ref__a : 0x[...] : 6 [Type: int *]
|
||||||
|
|
||||||
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
|
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
|
||||||
#![omit_gdb_pretty_printer_section]
|
#![omit_gdb_pretty_printer_section]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user