Skip to content

Commit 8433e2a

Browse files
[debuginfo] Remove the notion of a 'fallback variant' from the CPP-like enum debuginfo encoding.
1 parent dfb2c89 commit 8433e2a

File tree

2 files changed

+135
-29
lines changed

2 files changed

+135
-29
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,6 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
105105
/// that case. Both `DISCR_BEGIN` and `DISCR_END` are inclusive bounds.
106106
/// Note that these ranges can wrap around, so that `DISCR_END < DISCR_BEGIN`.
107107
///
108-
/// The field in the top-level union that corresponds to the dataful variant
109-
/// is called `variant_fallback` instead of `variant<index>`. This is mainly
110-
/// an optimization that enables a shorter NatVis definition. That way we
111-
/// only need to specify a `tag == variantX.DISCR_EXACT` entry for the indexed
112-
/// variants. Otherwise we'd need to have that and then an additional entry
113-
/// checking `in_range(variantX.DISCR_BEGIN, variantX.DISCR_END)` for each
114-
/// index.
115-
///
116108
/// Single-variant enums don't actually have a tag field. In this case we
117109
/// emit a static tag field (that always has the value 0) so we can use the
118110
/// same representation (and NatVis).
@@ -123,6 +115,72 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
123115
/// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`,
124116
/// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`,
125117
/// and so on.
118+
///
119+
///
120+
/// The following pseudocode shows how to decode an enum value in a debugger:
121+
///
122+
/// ```ignore
123+
///
124+
/// fn find_active_variant(enum_value) -> (VariantName, VariantValue) {
125+
/// let is_128_bit = enum_value.has_field("tag128_lo");
126+
///
127+
/// if !is_128_bit {
128+
/// // Note: `tag` can be a static field for enums with only one
129+
/// // inhabited variant.
130+
/// let tag = enum_value.field("tag").value;
131+
///
132+
/// // For each variant, check if it is a match. Only one of them will match,
133+
/// // so if we find it we can return it immediately.
134+
/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) {
135+
/// if variant_field.has_field("DISCR_EXACT") {
136+
/// // This variant corresponds to a single tag value
137+
/// if variant_field.field("DISCR_EXACT").value == tag {
138+
/// return (variant_field.field("NAME"), variant_field.value);
139+
/// }
140+
/// } else {
141+
/// // This is a range variant
142+
/// let begin = variant_field.field("DISCR_BEGIN");
143+
/// let end = variant_field.field("DISCR_END");
144+
///
145+
/// if tag >= begin && tag <= end {
146+
/// return (variant_field.field("NAME"), variant_field.value);
147+
/// }
148+
/// }
149+
/// }
150+
/// } else {
151+
/// // Basically the same as with smaller tags, we just have to
152+
/// // stitch the values together.
153+
/// let tag: u128 = (enum_value.field("tag128_lo").value as u128) |
154+
/// (enum_value.field("tag128_hi").value as u128 << 64);
155+
///
156+
/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) {
157+
/// if variant_field.has_field("DISCR128_EXACT_LO") {
158+
/// let discr_exact = (variant_field.field("DISCR128_EXACT_LO" as u128) |
159+
/// (variant_field.field("DISCR128_EXACT_HI") as u128 << 64);
160+
///
161+
/// // This variant corresponds to a single tag value
162+
/// if discr_exact.value == tag {
163+
/// return (variant_field.field("NAME"), variant_field.value);
164+
/// }
165+
/// } else {
166+
/// // This is a range variant
167+
/// let begin = (variant_field.field("DISCR128_BEGIN_LO").value as u128) |
168+
/// (variant_field.field("DISCR128_BEGIN_HI").value as u128 << 64);
169+
/// let end = (variant_field.field("DISCR128_END_LO").value as u128) |
170+
/// (variant_field.field("DISCR128_END_HI").value as u128 << 64);
171+
///
172+
/// if tag >= begin && tag <= end {
173+
/// return (variant_field.field("NAME"), variant_field.value);
174+
/// }
175+
/// }
176+
/// }
177+
/// }
178+
///
179+
/// // We should have found an active variant at this point.
180+
/// unreachable!();
181+
/// }
182+
///
183+
/// ```
126184
pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
127185
cx: &CodegenCx<'ll, 'tcx>,
128186
unique_type_id: UniqueTypeId<'tcx>,
@@ -290,7 +348,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
290348
build_field_di_node(
291349
cx,
292350
enum_type_di_node,
293-
&variant_union_field_name(variant_index, None),
351+
&variant_union_field_name(variant_index),
294352
// NOTE: We use the size and align of the entire type, not from variant_layout
295353
// since the later is sometimes smaller (if it has fewer fields).
296354
size_and_align_of(enum_type_and_layout),
@@ -691,8 +749,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
691749
.source_info
692750
.unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
693751

694-
let field_name =
695-
variant_union_field_name(variant_member_info.variant_index, dataful_variant_index);
752+
let field_name = variant_union_field_name(variant_member_info.variant_index);
696753
let (size, align) = size_and_align_of(enum_type_and_layout);
697754

698755
let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node(
@@ -795,10 +852,7 @@ struct VariantFieldInfo<'ll> {
795852
discr: DiscrResult,
796853
}
797854

798-
fn variant_union_field_name(
799-
variant_index: VariantIdx,
800-
dataful_variant_index: Option<VariantIdx>,
801-
) -> Cow<'static, str> {
855+
fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> {
802856
const PRE_ALLOCATED: [&str; 16] = [
803857
"variant0",
804858
"variant1",
@@ -818,10 +872,6 @@ fn variant_union_field_name(
818872
"variant15",
819873
];
820874

821-
if Some(variant_index) == dataful_variant_index {
822-
return Cow::from("variant_fallback");
823-
}
824-
825875
PRE_ALLOCATED
826876
.get(variant_index.as_usize())
827877
.map(|&s| Cow::from(s))

0 commit comments

Comments
 (0)