[PATCH] D42082: Add DWARF for discriminated unions

Tom Tromey via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 17 07:27:28 PST 2018


tromey added a comment.

In https://reviews.llvm.org/D42082#977666, @probinson wrote:

> As I poke around the web looking for how a Rust enum-with-value works, it appears that Rust has what in Pascal would be a tagged variant record with no invariant part and no default variant.


The Rust compiler can introduce a default variant by optimizing out other variants.  The test case in this patch is a reduced version of output from a case where that happened.

Recent versions of the compiler can do this in more situations, but the "non-zero" optimization goes back quite a ways.  Code looks like:

  enum NonZero {
      None,
      Some(String),
  }

Because the string cannot be zero, the two variants share space and zero is used as the discriminant for `None`.

>   DW_TAG_struct_type // type entry for the enum-with-fields
>     DW_TAG_variant_part // because DWARF says variant_part is owned by the struct_type
>         DW_AT_discr // reference to the discriminator field
>       DW_TAG_member // this is the discriminator field, where the enum value is stored
>       DW_TAG_variant // wrapper for the first variant
>           DW_AT_discr_value // first discriminant value
>         DW_TAG_member ... // member(s) for the first variant
>       DW_TAG_variant // wrapper for the second variant
>           DW_AT_discr_value // second discriminant value 
>         DW_TAG_member ... // member(s) for the second variant
>       // etc
> 
> 
> Is that what you are trying to produce?

Almost; in DWARF the discriminant has to be a member of the outer structure.  So the output ends up a little funny.  Here's one from a test case:

  <3><444>: Abbrev Number: 6 (DW_TAG_structure_type)
     <445>   DW_AT_name        : (indirect string, offset: 0xa7f7f): Option<&u8>
     <449>   DW_AT_byte_size   : 8
     <44a>   DW_AT_alignment   : 8
  <4><44b>: Abbrev Number: 9 (DW_TAG_member)
     <44c>   DW_AT_type        : <0x509>
     <450>   DW_AT_alignment   : 8
     <451>   DW_AT_data_member_location: 0
     <452>   DW_AT_artificial  : 1
  <4><452>: Abbrev Number: 10 (DW_TAG_variant_part)
     <453>   DW_AT_discr       : <0x44b>
  <5><457>: Abbrev Number: 11 (DW_TAG_variant)
     <458>   DW_AT_discr_value : 0
  <6><459>: Abbrev Number: 12 (DW_TAG_member)
     <45a>   DW_AT_type        : <0x46b>
     <45e>   DW_AT_alignment   : 8
     <45f>   DW_AT_data_member_location: 0
  <6><460>: Abbrev Number: 0
  <5><461>: Abbrev Number: 13 (DW_TAG_variant)
  <6><462>: Abbrev Number: 12 (DW_TAG_member)
     <463>   DW_AT_type        : <0x472>
     <467>   DW_AT_alignment   : 8
     <468>   DW_AT_data_member_location: 0

Here the discriminant member is DIE 0x44b; the rest is as you wrote.

DWARF allows some other constructs, like extra members in the outer struct, and lists of discriminant values.  However, Rust doesn't need this, so I did not implement them.  This is also why the interface talks about "discriminated unions" and not variants -- it is more limited.

Another approach I've considered is to just not use the DWARF variant record support at all and instead introduce a new `DW_TAG_Rust_enum`.  This would be simpler in some ways, but I figured I'd first try to use what DWARF provides.


Repository:
  rL LLVM

https://reviews.llvm.org/D42082





More information about the llvm-commits mailing list