about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2022-03-03 12:10:02 +0100
committerMichael Woerister <michaelwoerister@posteo>2022-03-14 16:52:47 +0100
commit3ad299aa670face2085d2abec6e8481fa582068a (patch)
tree0e4cceb87c75f145bbc77fda35ddd2713c611ee5
parent07ebc13d87796622bb6e4ac46a7e6a054bc4c680 (diff)
downloadrust-3ad299aa670face2085d2abec6e8481fa582068a.tar.gz
rust-3ad299aa670face2085d2abec6e8481fa582068a.zip
debuginfo: change cpp-like naming for generator environments so that NatVis works for them
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs140
-rw-r--r--src/test/codegen/async-fn-debug-msvc.rs2
-rw-r--r--src/test/codegen/generator-debug-msvc.rs2
-rw-r--r--src/test/debuginfo/generator-objects.rs31
4 files changed, 125 insertions, 50 deletions
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 6a122addf22..ee0658f486a 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -16,13 +16,14 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
 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::{self, AdtDef, ExistentialProjection, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
 use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use smallvec::SmallVec;
 
+use std::borrow::Cow;
 use std::fmt::Write;
 
 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");
 
             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 {
                 push_item_name(tcx, def.did(), qualified, output);
                 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, ..) => {
             // 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);
-
-            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("::");
+            // 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 cpp_like_debuginfo && matches!(t.kind(), ty::Generator(..)) {
+                let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
+                msvc_enum_fallback(
+                    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.
         ty::Param(_) => {
-            output.push_str(&format!("{:?}", t));
+            write!(output, "{:?}", t).unwrap();
         }
         ty::Error(_)
         | ty::Infer(_)
@@ -408,24 +404,32 @@ fn push_debuginfo_type_name<'tcx>(
     // `EnumMemberDescriptionFactor::create_member_descriptions`.
     fn msvc_enum_fallback<'tcx>(
         tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        def: AdtDef<'tcx>,
-        substs: SubstsRef<'tcx>,
+        ty_and_layout: TyAndLayout<'tcx>,
+        push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
         output: &mut String,
         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$<");
-        push_item_name(tcx, def.did(), true, output);
-        push_generic_params_internal(tcx, substs, output, visited);
+        push_inner(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 {
             tag_encoding: TagEncoding::Niche { dataful_variant, .. },
             tag,
             variants,
             ..
-        } = &layout.variants
+        } = &ty_and_layout.variants
         {
             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 = tag.value.size(&tcx).truncate(max);
 
-            let dataful_variant_name = def.variant(*dataful_variant).name.as_str();
-
-            output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
-        } else if let Variants::Single { index: variant_idx } = &layout.variants {
+            let dataful_variant_name = variant_name(*dataful_variant);
+            write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();
+        } else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants {
             // Uninhabited enums can't be constructed and should never need to be visualized so
             // skip this step for them.
-            if def.variants().len() != 0 {
-                let variant = def.variant(*variant_idx).name.as_str();
-
-                output.push_str(&format!(", {}", variant));
+            if !ty_and_layout.abi.is_uninhabited() {
+                write!(output, ", {}", variant_name(*variant_idx)).unwrap();
             }
         }
         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);
 }
 
+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) {
     // MSVC debugger always treats `>>` as a shift, even when parsing templates,
     // so add a space to avoid confusion.
diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs
index b10e662b5bb..8995605e3dd 100644
--- a/src/test/codegen/async-fn-debug-msvc.rs
+++ b/src/test/codegen/async-fn-debug-msvc.rs
@@ -16,7 +16,7 @@ async fn async_fn_test() {
 
 // 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]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs
index a6e56a6bd57..74b1eb948b0 100644
--- a/src/test/codegen/generator-debug-msvc.rs
+++ b/src/test/codegen/generator-debug-msvc.rs
@@ -20,7 +20,7 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 
 // 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]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs
index aee19736e7e..a972943d58e 100644
--- a/src/test/debuginfo/generator-objects.rs
+++ b/src/test/debuginfo/generator-objects.rs
@@ -37,6 +37,37 @@
 // lldb-command:print b
 // 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)]
 #![omit_gdb_pretty_printer_section]