Skip to content

Commit 41fddc4

Browse files
[lldb] Print empty enums as if they were unrecognised normal enums (#97553)
Fixes #97514 Given this example: ``` enum E {}; int main() { E x = E(0); E y = E(1); E z = E(2); return 0; } ``` lldb used to print nothing for `x`, but `0x1` for `y` and `0x2` for `z`. At first this seemed like the 0 case needed fixing but the real issue here is that en enum with no enumerators was being detected as a "bitfield like enum". Which is an enum where all enumerators are a single bit value, or the sum of previous single bit values. For these we do not print anything for a value of 0, as we assume it must be the remainder after we've printed the other bits that were set (I think this is also unfortunate, but I'm not addressing that here). Clearly an enum with no enumerators cannot be being used as a bitfield, so check that up front and print it as if it's a normal enum where we didn't match any of the enumerators. This means you now get: ``` (lldb) p x (E) 0 (lldb) p y (E) 1 (lldb) p z (E) 2 ``` Which is a change to decimal from hex, but I think it's overall more consistent. Printing hex here was never a concious decision.
1 parent dde3f17 commit 41fddc4

File tree

3 files changed

+43
-22
lines changed

3 files changed

+43
-22
lines changed

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8656,20 +8656,25 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
86568656
// every enumerator is either a one bit value or a superset of the previous
86578657
// enumerators. Also 0 doesn't make sense when the enumerators are used as
86588658
// flags.
8659-
for (auto *enumerator : enum_decl->enumerators()) {
8660-
llvm::APSInt init_val = enumerator->getInitVal();
8661-
uint64_t val =
8662-
qual_type_is_signed ? init_val.getSExtValue() : init_val.getZExtValue();
8663-
if (qual_type_is_signed)
8664-
val = llvm::SignExtend64(val, 8 * byte_size);
8665-
if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0)
8666-
can_be_bitfield = false;
8667-
covered_bits |= val;
8668-
++num_enumerators;
8669-
if (val == enum_svalue) {
8670-
// Found an exact match, that's all we need to do.
8671-
s.PutCString(enumerator->getNameAsString());
8672-
return true;
8659+
clang::EnumDecl::enumerator_range enumerators = enum_decl->enumerators();
8660+
if (enumerators.empty())
8661+
can_be_bitfield = false;
8662+
else {
8663+
for (auto *enumerator : enumerators) {
8664+
llvm::APSInt init_val = enumerator->getInitVal();
8665+
uint64_t val = qual_type_is_signed ? init_val.getSExtValue()
8666+
: init_val.getZExtValue();
8667+
if (qual_type_is_signed)
8668+
val = llvm::SignExtend64(val, 8 * byte_size);
8669+
if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0)
8670+
can_be_bitfield = false;
8671+
covered_bits |= val;
8672+
++num_enumerators;
8673+
if (val == enum_svalue) {
8674+
// Found an exact match, that's all we need to do.
8675+
s.PutCString(enumerator->getNameAsString());
8676+
return true;
8677+
}
86738678
}
86748679
}
86758680

lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ PRINTEC: use of undeclared identifier 'EC'
2222

2323
RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s
2424
VARS: (const (unnamed struct)) a = <incomplete type "const (unnamed struct)">
25-
VARS: (const (unnamed enum)) e = 0x1
26-
VARS: (const (unnamed enum)) ec = 0x1
25+
VARS: (const (unnamed enum)) e = 1
26+
VARS: (const (unnamed enum)) ec = 1

lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,13 @@ class ValueObjectMockProcessTest : public ::testing::Test {
7171
}
7272

7373
CompilerType
74-
MakeEnumType(const std::vector<std::pair<const char *, int>> enumerators) {
75-
CompilerType uint_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
76-
lldb::eEncodingUint, 32);
74+
MakeEnumType(const std::vector<std::pair<const char *, int>> enumerators,
75+
bool is_signed) {
76+
CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
77+
is_signed ? lldb::eEncodingSint : lldb::eEncodingUint, 32);
7778
CompilerType enum_type = m_type_system->CreateEnumerationType(
7879
"TestEnum", m_type_system->GetTranslationUnitDecl(),
79-
OptionalClangModuleID(), Declaration(), uint_type, false);
80+
OptionalClangModuleID(), Declaration(), int_type, false);
8081

8182
m_type_system->StartTagDeclarationDefinition(enum_type);
8283
Declaration decl;
@@ -123,12 +124,27 @@ class ValueObjectMockProcessTest : public ::testing::Test {
123124
lldb::ProcessSP m_process_sp;
124125
};
125126

127+
TEST_F(ValueObjectMockProcessTest, EmptyEnum) {
128+
// All values of an empty enum should be shown as plain numbers.
129+
TestDumpValueObject(MakeEnumType({}, false),
130+
{{0, {}, "(TestEnum) test_var = 0\n"},
131+
{1, {}, "(TestEnum) test_var = 1\n"},
132+
{2, {}, "(TestEnum) test_var = 2\n"}});
133+
134+
TestDumpValueObject(MakeEnumType({}, true),
135+
{{-2, {}, "(TestEnum) test_var = -2\n"},
136+
{-1, {}, "(TestEnum) test_var = -1\n"},
137+
{0, {}, "(TestEnum) test_var = 0\n"},
138+
{1, {}, "(TestEnum) test_var = 1\n"},
139+
{2, {}, "(TestEnum) test_var = 2\n"}});
140+
}
141+
126142
TEST_F(ValueObjectMockProcessTest, Enum) {
127143
// This is not a bitfield-like enum, so values are printed as decimal by
128144
// default. Also we only show the enumerator name if the value is an
129145
// exact match.
130146
TestDumpValueObject(
131-
MakeEnumType({{"test_2", 2}, {"test_3", 3}}),
147+
MakeEnumType({{"test_2", 2}, {"test_3", 3}}, false),
132148
{{0, {}, "(TestEnum) test_var = 0\n"},
133149
{1, {}, "(TestEnum) test_var = 1\n"},
134150
{2, {}, "(TestEnum) test_var = test_2\n"},
@@ -152,7 +168,7 @@ TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {
152168
// as hex, a value of 0 shows nothing, and values with no exact enumerator are
153169
// shown as combinations of the other values.
154170
TestDumpValueObject(
155-
MakeEnumType({{"test_2", 2}, {"test_4", 4}}),
171+
MakeEnumType({{"test_2", 2}, {"test_4", 4}}, false),
156172
{
157173
{0, {}, "(TestEnum) test_var =\n"},
158174
{1, {}, "(TestEnum) test_var = 0x1\n"},

0 commit comments

Comments
 (0)