DW_AT_discr_value elided in DWARF for some enum variants #104625
Open
Description
opened on Nov 20, 2022
Code
There is a regression from 1.64.0 to 1.65.0 in the DWARF emitted for some variants for some enums, as the below program shows:
#[repr(u32)]
pub enum DontKnowWhyThisIsNeededButItIs {
Blargh,
}
//
// When compiled on 1.65.0 or later, the `ThisIsBad` variant in the below
// `Foo` enum does not have a `DW_AT_discr_value` in the DWARF, as displayed
// by `dwarfdump`:
//
//
// ```
// ...
// < 2><0x00000049> DW_TAG_structure_type
// DW_AT_name Foo
// DW_AT_byte_size 0x0000000c
// DW_AT_alignment 0x00000004
// < 3><0x00000050> DW_TAG_variant_part
// DW_AT_discr <0x00000055>
// < 4><0x00000055> DW_TAG_member
// DW_AT_type <0x00000180>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// DW_AT_artificial yes(1)
// < 4><0x0000005c> DW_TAG_variant
// DW_AT_discr_value 1
// < 5><0x0000005e> DW_TAG_member
// DW_AT_name ThisIsFine
// DW_AT_type <0x00000094>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x0000006a> DW_TAG_variant
// < 5><0x0000006b> DW_TAG_member
// DW_AT_name ThisIsBad
// DW_AT_type <0x0000009b>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x00000077> DW_TAG_variant
// DW_AT_discr_value 3
// < 5><0x00000079> DW_TAG_member
// DW_AT_name ThisIsAlsoFine
// DW_AT_type <0x000000b9>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x00000085> DW_TAG_variant
// DW_AT_discr_value 4
// < 5><0x00000087> DW_TAG_member
// DW_AT_name ThisIsFineToo
// DW_AT_type <0x000000cc>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// ...
// ```
//
// By contrast, when compiled on 1.64.0, all variants have a
// `DW_AT_discr_value` as expected:
//
// ```
// ...
// < 2><0x00000049> DW_TAG_structure_type
// DW_AT_name Foo
// DW_AT_byte_size 0x0000000c
// DW_AT_alignment 0x00000004
// < 3><0x00000050> DW_TAG_variant_part
// DW_AT_discr <0x00000055>
// < 4><0x00000055> DW_TAG_member
// DW_AT_type <0x00000181>
// DW_AT_alignment 0x00000001
// DW_AT_data_member_location 0
// DW_AT_artificial yes(1)
// < 4><0x0000005c> DW_TAG_variant
// DW_AT_discr_value 0
// < 5><0x0000005e> DW_TAG_member
// DW_AT_name ThisIsFine
// DW_AT_type <0x00000095>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x0000006a> DW_TAG_variant
// DW_AT_discr_value 1
// < 5><0x0000006c> DW_TAG_member
// DW_AT_name ThisIsBad
// DW_AT_type <0x0000009c>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x00000078> DW_TAG_variant
// DW_AT_discr_value 2
// < 5><0x0000007a> DW_TAG_member
// DW_AT_name ThisIsAlsoFine
// DW_AT_type <0x000000ba>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// < 4><0x00000086> DW_TAG_variant
// DW_AT_discr_value 3
// < 5><0x00000088> DW_TAG_member
// DW_AT_name ThisIsFineToo
// DW_AT_type <0x000000cd>
// DW_AT_alignment 0x00000004
// DW_AT_data_member_location 0
// ...
// ```
//
// Note that this is pretty squirrely; if the `#[repr(u32)]` is absent on the
// `DontKnowWhyThisIsNeededButItIs` enum (for example), the `ThisIsBad` member
// will correctly have a `DW_AT_discr_value` -- as it will if the
// `DontKnowWhyThisIsNeededButItIs` is absent entirely, or if the first tuple
// has fewer than 5 elements. Finally (and perhaps most vexing?) it will also
// be chased away if there is a second variant that has the identical signature
// as `ThisIsBad` -- in which case all variants will correctly have a
// `DW_AT_discr_value`.
//
pub enum Foo {
ThisIsFine,
ThisIsBad(
(u8, u8, u8, u8, u8),
DontKnowWhyThisIsNeededButItIs,
),
ThisIsAlsoFine(
(u8, u8, u8, u8, u8),
),
ThisIsFineToo(
(u8, u8, u8, u8),
DontKnowWhyThisIsNeededButItIs,
),
ThisIsMaybeFine(
(u8, u8, u8, u8),
DontKnowWhyThisIsNeededButItIs,
),
}
#[allow(dead_code)]
static QUUX: Option<Foo> = None;
fn main() {}
Version it worked on
As the comment in the program indicates, the DWARF for the Foo
enum looks like this on 1.64.0 and earlier:
< 2><0x00000049> DW_TAG_structure_type
DW_AT_name Foo
DW_AT_byte_size 0x0000000c
DW_AT_alignment 0x00000004
< 3><0x00000050> DW_TAG_variant_part
DW_AT_discr <0x00000055>
< 4><0x00000055> DW_TAG_member
DW_AT_type <0x00000181>
DW_AT_alignment 0x00000001
DW_AT_data_member_location 0
DW_AT_artificial yes(1)
< 4><0x0000005c> DW_TAG_variant
DW_AT_discr_value 0
< 5><0x0000005e> DW_TAG_member
DW_AT_name ThisIsFine
DW_AT_type <0x00000095>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x0000006a> DW_TAG_variant
DW_AT_discr_value 1
< 5><0x0000006c> DW_TAG_member
DW_AT_name ThisIsBad
DW_AT_type <0x0000009c>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x00000078> DW_TAG_variant
DW_AT_discr_value 2
< 5><0x0000007a> DW_TAG_member
DW_AT_name ThisIsAlsoFine
DW_AT_type <0x000000ba>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x00000086> DW_TAG_variant
DW_AT_discr_value 3
< 5><0x00000088> DW_TAG_member
DW_AT_name ThisIsFineToo
DW_AT_type <0x000000cd>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
rustc --version --verbose
:
rustc 1.64.0 (a55dd71d5 2022-09-19)
binary: rustc
commit-hash: a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52
commit-date: 2022-09-19
host: x86_64-unknown-linux-gnu
release: 1.64.0
LLVM version: 14.0.6
Version with regression
But on 1.65.0 and later, it looks like this:
< 2><0x00000049> DW_TAG_structure_type
DW_AT_name Foo
DW_AT_byte_size 0x0000000c
DW_AT_alignment 0x00000004
< 3><0x00000050> DW_TAG_variant_part
DW_AT_discr <0x00000055>
< 4><0x00000055> DW_TAG_member
DW_AT_type <0x00000180>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
DW_AT_artificial yes(1)
< 4><0x0000005c> DW_TAG_variant
DW_AT_discr_value 1
< 5><0x0000005e> DW_TAG_member
DW_AT_name ThisIsFine
DW_AT_type <0x00000094>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x0000006a> DW_TAG_variant
< 5><0x0000006b> DW_TAG_member
DW_AT_name ThisIsBad
DW_AT_type <0x0000009b>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x00000077> DW_TAG_variant
DW_AT_discr_value 3
< 5><0x00000079> DW_TAG_member
DW_AT_name ThisIsAlsoFine
DW_AT_type <0x000000b9>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
< 4><0x00000085> DW_TAG_variant
DW_AT_discr_value 4
< 5><0x00000087> DW_TAG_member
DW_AT_name ThisIsFineToo
DW_AT_type <0x000000cc>
DW_AT_alignment 0x00000004
DW_AT_data_member_location 0
rustc --version --verbose
:
rustc 1.65.0 (897e37553 2022-11-02)
binary: rustc
commit-hash: 897e37553bba8b42751c67658967889d11ecd120
commit-date: 2022-11-02
host: x86_64-unknown-linux-gnu
release: 1.65.0
LLVM version: 15.0.0
Unsurprisingly, there is an LLVM version bump across these two versions.
If it helps to have context about how we hit this, we saw this in the debugger (Humility) for our embedded Rust operating system (Hubris); see oxidecomputer/humility#263 for details.
Thanks in advance to anyone who looks at this -- the DWARF emitted by Rust has been invaluable for our work!
Activity