Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] Fix printing of unsigned enum bitfields when they contain the max value #96202

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8639,8 +8639,13 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
const clang::EnumDecl *enum_decl = enutype->getDecl();
assert(enum_decl);
lldb::offset_t offset = byte_offset;
const uint64_t enum_svalue = data.GetMaxS64Bitfield(
&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
bool qual_type_is_signed = qual_type->isSignedIntegerOrEnumerationType();
const uint64_t enum_svalue =
qual_type_is_signed
? data.GetMaxS64Bitfield(&offset, byte_size, bitfield_bit_size,
bitfield_bit_offset)
: data.GetMaxU64Bitfield(&offset, byte_size, bitfield_bit_size,
bitfield_bit_offset);
bool can_be_bitfield = true;
uint64_t covered_bits = 0;
int num_enumerators = 0;
Expand All @@ -8652,8 +8657,11 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
// enumerators. Also 0 doesn't make sense when the enumerators are used as
// flags.
for (auto *enumerator : enum_decl->enumerators()) {
uint64_t val = enumerator->getInitVal().getSExtValue();
val = llvm::SignExtend64(val, 8*byte_size);
llvm::APSInt init_val = enumerator->getInitVal();
uint64_t val =
qual_type_is_signed ? init_val.getSExtValue() : init_val.getZExtValue();
if (qual_type_is_signed)
val = llvm::SignExtend64(val, 8 * byte_size);
if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0)
can_be_bitfield = false;
covered_bits |= val;
Expand All @@ -8673,7 +8681,7 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
// No exact match, but we don't think this is a bitfield. Print the value as
// decimal.
if (!can_be_bitfield) {
if (qual_type->isSignedIntegerOrEnumerationType())
if (qual_type_is_signed)
s.Printf("%" PRIi64, enum_svalue);
else
s.Printf("%" PRIu64, enum_uvalue);
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/commands/expression/bitfield_enums/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Test that the expression parser accounts for the underlying type of bitfield
enums when looking for matching values.
"""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestBitfieldEnum(TestBase):
def test_bitfield_enums(self):
self.build()

lldbutil.run_to_source_breakpoint(
self, "// break here", lldb.SBFileSpec("main.cpp", False)
)

self.expect_expr(
"bfs",
result_type="BitfieldStruct",
result_children=[
ValueCheck(name="signed_min", value="min"),
ValueCheck(name="signed_other", value="-1"),
ValueCheck(name="signed_max", value="max"),
ValueCheck(name="unsigned_min", value="min"),
ValueCheck(name="unsigned_other", value="1"),
ValueCheck(name="unsigned_max", value="max"),
Copy link
Collaborator Author

@DavidSpickett DavidSpickett Jun 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior to this change, this printed 3 instead of max.

],
)
24 changes: 24 additions & 0 deletions lldb/test/API/commands/expression/bitfield_enums/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
enum class SignedEnum : int { min = -2, max = 1 };
enum class UnsignedEnum : unsigned { min = 0, max = 3 };

struct BitfieldStruct {
SignedEnum signed_min : 2;
SignedEnum signed_other : 2;
SignedEnum signed_max : 2;
UnsignedEnum unsigned_min : 2;
UnsignedEnum unsigned_other : 2;
UnsignedEnum unsigned_max : 2;
};

int main() {
BitfieldStruct bfs;
bfs.signed_min = SignedEnum::min;
bfs.signed_other = static_cast<SignedEnum>(-1);
bfs.signed_max = SignedEnum::max;

bfs.unsigned_min = UnsignedEnum::min;
bfs.unsigned_other = static_cast<UnsignedEnum>(1);
bfs.unsigned_max = UnsignedEnum::max;

return 0; // break here
}
Loading