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.
------------------------- 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")
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'.
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))
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'.
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'
(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.