LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 46466 - [DWARF] Does not generate nested enumerations.
Summary: [DWARF] Does not generate nested enumerations.
Status: NEW
Alias: None
Product: libraries
Classification: Unclassified
Component: DebugInfo (show other bugs)
Version: trunk
Hardware: PC All
: P enhancement
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-06-26 02:09 PDT by Carlos Alberto Enciso
Modified: 2020-06-29 16:01 PDT (History)
9 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Carlos Alberto Enciso 2020-06-26 02:09:22 PDT
For the given test:

//----------------------------------------------------------

struct Struct {
  union Union {
    enum NestedEnum { RED, BLUE };
  };
  Union U;
};

Struct S;
int test() {
  return S.U.BLUE;
}

//----------------------------------------------------------

The DWARF generated does not include any references to the enumerators 'RED' and 'BLUE'.

DWARF generated by GCC, CodeView generated by Clang and MSVC, it does include such references.
Comment 1 Carlos Alberto Enciso 2020-06-26 02:23:58 PDT
-------------------------
llvm-dwarf output - Clang
-------------------------
0x00: DW_TAG_compile_unit
        DW_AT_producer	("clang version 11.0.0")

0x2a:   DW_TAG_variable
          DW_AT_name	("S")
          DW_AT_type	(0x0000003f "Struct")

0x3f:   DW_TAG_structure_type
          DW_AT_name	("Struct")

0x48:     DW_TAG_member
            DW_AT_name	("U")
            DW_AT_type	(0x00000054 "Union")

0x54:     DW_TAG_union_type
            DW_AT_name	("Union")

-----------------------
llvm-dwarf output - GCC
-----------------------

0x0b: DW_TAG_compile_unit
        DW_AT_producer    ("GNU C++ 5.5.0 20171010")

0x2d:   DW_TAG_structure_type
          DW_AT_name      ("Struct")

0x39:     DW_TAG_union_type
            DW_AT_name    ("Union")

0x45:       DW_TAG_enumeration_type
              DW_AT_name  ("NestedEnum")

0x51:         DW_TAG_enumerator
                DW_AT_name        ("RED")
                DW_AT_const_value (0x00)

0x57:         DW_TAG_enumerator
                DW_AT_name        ("BLUE")
                DW_AT_const_value (0x01)

0x5f:     DW_TAG_member
            DW_AT_name    ("U")
Comment 2 Carlos Alberto Enciso 2020-06-26 02:32:21 PDT
This is the output from llvm-diva (Sony's tool under development).

llvm-diva --print=scopes,symbols,types test.o --attribute=level,format

DWARF Logical View: (Clang)
---------------------------
Logical View:
[000]           {File} 'test.o' -> elf64-x86-64
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]     9         {Function} extern not_inlined 'test' -> 'int'
[002]     1         {Struct} 'Struct'
[003]     5           {Member} public 'U' -> 'Union'
[003]     2           {Union} 'Union'
[002]     8         {Variable} extern 'S' -> 'Struct'

DWARF Logical View: (GCC)
-------------------------
Logical View:
[000]           {File} 'test.o' -> elf32-littlearm
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'GNU C++14 9.2.1 20191025'
[002]     9         {Function} extern not_inlined 'test' -> 'int'
[002]     1         {Struct} 'Struct'
[003]     5           {Member} public 'U' -> 'Union'
[003]     2           {Union} 'Union'
[004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
[005]                     {Enumerator} 'BLUE' = '0x1'
[005]                     {Enumerator} 'RED' = '0x0'
[002]     8         {Variable} extern 'S' -> 'Struct'

CodeView Logical View: (Clang)
------------------------------
Logical View:
[000]           {File} 'test.o' -> COFF-x86-64
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]               {Function} extern not_inlined 'test' -> 'int'
[002]     1         {Struct} 'Struct'
[003]                 {Member} public 'U' -> 'Union'
[003]     2           {Union} 'Union'
[004]     3             {Enumeration} 'NestedEnum' -> 'int'
[005]                     {Enumerator} 'BLUE' = '0x1'
[005]                     {Enumerator} 'RED' = '0x0'
[002]               {Variable} extern 'S' -> 'Struct'

CodeView Logical View: (MSVC)
-----------------------------
Logical View:
[000]           {File} 'test.o' -> COFF-i386
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'Microsoft (R) Optimizing Compiler'
[002]               {Function} extern not_inlined 'test' -> 'int'
[002]     1         {Struct} 'Struct'
[003]                 {Member} public 'U' -> 'Union'
[003]     2           {Union} 'Union'
[004]     3             {Enumeration} 'NestedEnum' -> 'int'
[005]                     {Enumerator} 'BLUE' = '0x1'
[005]                     {Enumerator} 'RED' = '0x0'
[002]               {Variable} extern 'S' -> 'Struct'

The logical views for the objects generated by GCC (DWARF), Clang (CodeView) and MSVC (CodeView) contains references to the enumerators 'BLUE' and 'RED'.
Comment 3 David Blaikie 2020-06-26 12:28:28 PDT
A simpler example:

struct Struct {
    enum NestedEnum { RED, BLUE };
};

Struct S;
int test() {
  return Struct::BLUE; // enum is emitted in DWARF
  // S.BLUE; // enum not emitted in DWARF
}

If you're interested in fixing this I'd suggest comparing/contrasting these two cases, and perhaps comparing/contrasting the CodeView case too (But I think the CV case works by emitting the nested enum because the outer struct is emitted - whereas I don't think we want to do that in DWARF (eg: "return Struct().BLUE;" should probably emit the enum even though the "Struct" type is not otherwise needed in the DWARF (& should probably be emitted as a declaration) & that probably doesn't produce struct or enum in CodeView - and having the global "Struct S;" should produce the Struct but no enum in DWARF (I'd bet this is GCC's behavior) if the enum is unreferenced (unlike in CodeView, where it's emitted regardless))
Comment 4 Carlos Alberto Enciso 2020-06-29 01:09:30 PDT
For your simpler example, with both variations:

- return Struct::BLUE;
- return S.BLUE;

The CodeView generated by MSVC and Clang, looks the same:

     0 | S_GDATA32 `S`
         type = 0x1009 (Struct)

0x1009 | LF_STRUCTURE `Struct`
         field list: 0x1008
0x1008 | LF_FIELDLIST
         - LF_NESTTYPE [name = `NestedEnum`, parent = 0x1005]
0x1005 | LF_ENUM `Struct::NestedEnum`
         field list: 0x1004
0x1004 | LF_FIELDLIST
         - LF_ENUMERATE [RED = 0]
         - LF_ENUMERATE [BLUE = 1]

The nested enum is emitted as part of the enclosing scope 'Struct'.
Comment 5 Carlos Alberto Enciso 2020-06-29 01:35:04 PDT
Changing the enum to be enum class:

struct Struct {
  enum class NestedEnum { RED, BLUE };
};

int test() {
  return (int)Struct::NestedEnum::BLUE;
}

Only Clang (DWARF) emits the nested enum:

DWARF Logical View: (Clang)
---------------------------
[000]           {File} 'test.o' -> elf64-x86-64
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]     5         {Function} extern not_inlined 'test' -> 'int'
[002]     1         {Struct} 'Struct'
[003]     2           {Enumeration} class 'NestedEnum' -> 'int'
[004]                   {Enumerator} 'BLUE' = '0x1'
[004]                   {Enumerator} 'RED' = '0x0'

DWARF Logical View: (GCC)
-------------------------
Logical View:
[000]           {File} 'test.o' -> elf32-littlearm
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'GNU C++14 9.2.1 20191025'
[002]     5         {Function} extern not_inlined 'test' -> 'int'

CodeView Logical View: (Clang)
------------------------------
Logical View:
[000]           {File} 'test.o' -> COFF-x86-64
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'clang version 11.0.0'
[002]               {Function} extern not_inlined 'test' -> 'int'

CodeView Logical View: (MSVC)
-----------------------------
[000]           {File} 'test.o' -> COFF-i386
[001]             {CompileUnit} 'test.cpp'
[002]               {Producer} 'Microsoft (R) Optimizing Compiler'
[002]               {Function} extern not_inlined 'test' -> 'int'
Comment 6 David Blaikie 2020-06-29 16:01:22 PDT
(In reply to Carlos Alberto Enciso from comment #4)
> For your simpler example, with both variations:
> 
> - return Struct::BLUE;
> - return S.BLUE;
> 
> The CodeView generated by MSVC and Clang, looks the same

Yes, that'd be my expectation - I believe CodeView/MSVC/Clang-cl needs the full definition of the nested type (how it deals with a forward declaration of a nested type (eg: pimpl idiom), I don't know - be nice if we could use that representation for all nested enums on CV, because that's my philosophy for the DWARF output "imagine the nested types were always defined out of line") 

Confirming what I was saying here: "comparing/contrasting the CodeView case too (But I think the CV case works by emitting the nested enum because the outer struct is emitted - whereas I don't think we want to do that in DWARF"(In reply to 

Carlos Alberto Enciso from comment #5)
> Changing the enum to be enum class:
> 
> struct Struct {
>   enum class NestedEnum { RED, BLUE };
> };
> 
> int test() {
>   return (int)Struct::NestedEnum::BLUE;
> }
> 
> Only Clang (DWARF) emits the nested enum

Sure - I'd probably classify that as a bug/missed opportunity for other compilers.