Repository: rust
Issue: DWARF debug info generated for C-style enums breaks assumptions of C/C++ tooling
Labels: A-debuginfo,T-compiler,C-bug

The Rust compiler generates DWARF debug information for enums in several different ways. For [certain types of enums](https://github.com/rust-lang/rust/blob/9580a7115d2d75514f0b329a29fafaa3796bd950/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs#L13) the compiler generates debug information that resembles that of a plain C/C++ `enum` by using [`DW_TAG_enumeration_type`](https://github.com/rust-lang/rust/blob/9580a71/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs#L79-L81). While this generally makes sense, it can cause problems with tooling that expects C/C++ semantics and can't handle debug information for an `enum` type that also has functions associated with it.

In particular, if a Rust C-like enum has an `impl` with some functions, and a codegen unit that calls one of those functions gets the function inlined, then the resulting DWARF debugging information contains a `DW_TAG_enumeration_type` entry with an inner `DW_TAG_subprogram` entry for the inlined function, which is something that I don't think any C or C++ compiler would ever generate.

For example, consider the following code:

`lib.rs`

```rust
mod test;

pub enum Format {
    Dwarf64 = 8,
    Dwarf32 = 4,
}

impl Format {
    #[inline(never)]
    pub fn new() -> Format {
        Format::Dwarf64
    }

    #[inline(always)]
    pub fn word_size(self) -> u8 {
        match self {
            Format::Dwarf32 => 4,
            Format::Dwarf64 => 8,
        }
    }
}
```

`test.rs`

```
pub fn test() -> u8 {
    super::Format::new().word_size()
}
```

Compile the above as follows:

```
$ rustc +stage1 lib.rs --crate-type lib --emit obj -C debuginfo=2 -C opt-level=z -C codegen-units=2 --target x86_64-unknown-linux-gnu
```

And inspect the resulting DWARF information:

```
$ llvm-dwarfdump --all lib.o

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer	("clang LLVM (rustc version 1.61.0-dev)")
              DW_AT_language	(DW_LANG_Rust)
              DW_AT_name	("lib.rs\\@\\lib.e2d200f5-cgu.0")
              DW_AT_stmt_list	(0x00000000)
              DW_AT_comp_dir	(".")
              DW_AT_GNU_pubnames	(0x01)
              DW_AT_low_pc	(0x0000000000000000)
              DW_AT_high_pc	(0x0000000000000003)

0x0000002f:   DW_TAG_namespace
                DW_AT_name	("lib")

0x00000034:     DW_TAG_enumeration_type
                  DW_AT_name	("Format")
                  DW_AT_byte_size	(0x01)
                  DW_AT_alignment	(1)

0x0000003b:       DW_TAG_enumerator
                    DW_AT_name	("Dwarf64")
                    DW_AT_const_value	(8)

0x00000041:       DW_TAG_enumerator
                    DW_AT_name	("Dwarf32")
                    DW_AT_const_value	(4)

0x00000047:       DW_TAG_subprogram
                    DW_AT_low_pc	(0x0000000000000000)
                    DW_AT_high_pc	(0x0000000000000003)
                    DW_AT_frame_base	(DW_OP_reg7 RSP)
                    DW_AT_MIPS_linkage_name	("_ZN3lib6Format3new17h69583b444bb1ea9aE")
                    DW_AT_name	("new")
                    DW_AT_decl_file	("lib.rs")
                    DW_AT_decl_line	(10)
                    DW_AT_type	(0x00000034 "Format")
                    DW_AT_external	(0x01)
```

The existence of `DW_TAG_subprogram` under `DW_TAG_enumeration_type` here causes some third-party tooling that we rely on to be unable to process the debugging information.

I'm not sure what the way forward should be here, so I'm looking for advice. While an `enum` with functions makes total sense in Rust, it's not something that C-family languages have, and the DWARF spec seems to cater primarily to those kinds of languages. Looking at the DWARF v5 spec, section **5.9 Enumeration Type Entries** doesn't preclude an `enum` type with functions, but the description clearly describes an enumeration with the semantics from C and C++.

It's not the end of the world for us if we need to maintain a custom `rustc` patch to make `wants_c_like_enum_debuginfo` always return `false`, which is an easy workaround for this issue, but I figured there might be more tooling out there that does not expect debugging info for enums to contain references to enum functions. Maybe extending `wants_c_like_enum_debuginfo` to also check if there are any `impl` blocks associated with the enum type, or reparenting the `DW_TAG_subprogram` so it's not under the `DW_TAG_enumeration_type` entry? Pinging @michaelwoerister in particular since you recently did some fantastic work refactoring the debuginfo code. This is not caused by your recent changes, but figured you would have some good insight here.

### Meta

`rustc --version --verbose`:
```
rustc 1.61.0-dev
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-pc-windows-msvc
release: 1.61.0-dev
LLVM version: 13.0.0
```

This was just rustc built off the latest commit in `master` as of time of writing.