[Lldb-commits] [lldb] [lldb][NativePDB] Use active bits for constant width (PR #196104)
via lldb-commits
lldb-commits at lists.llvm.org
Wed May 6 09:07:27 PDT 2026
https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/196104
Static constants with bit widths less than 16 (e.g. char/unsigned char) in classes were not available. These constants are still encoded with 16 bits ([here](https://github.com/llvm/llvm-project/blob/dd145eb8997878143f648a7601741f6409330963/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp#L341-L343)) even though they only need less bits. When we tried to create an initializer for them, we'd check if the bit width (=16) was small enough to fit into the target (<16). This would fail.
This was a problem in the following code:
```cpp
struct Foo {
// width(unsigned char) = 8, but 255 was encoded and read as 16 bit
static constexpr unsigned char u8_max = 255;
};
```
This PR fixes the issue by using `APSInt::getActiveBits` for unsigned types and `APSInt::getSignificantBits` for signed types. They get the number of bits required to encode the value. For example a constant 64 would need 7 bits in unsigned and 8 bits in signed types.
>From d03cc888cca7c4503f2ba0f1a9ec2ee4dae411bb Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 6 May 2026 17:51:40 +0200
Subject: [PATCH] [lldb][NativePDB] Use active bits for constant width
---
.../NativePDB/UdtRecordCompleter.cpp | 18 ++-
.../Inputs/globals-fundamental.lldbinit | 7 +-
.../NativePDB/globals-fundamental.cpp | 20 ++++
.../NativePDB/static-class-constants.cpp | 109 ++++++++++++++++++
4 files changed, 148 insertions(+), 6 deletions(-)
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/static-class-constants.cpp
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 84813ad677d1c..9840b976d2713 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -179,10 +179,18 @@ Error UdtRecordCompleter::visitKnownMember(
clang::QualType qual_type = decl->getType();
unsigned type_width = decl->getASTContext().getIntWidth(qual_type);
- unsigned constant_width = constant.Value.getBitWidth();
+
+ // Get the minimum bit width to encode this constant value.
+ // The bit width of the APSInt might be larger than the bits required to
+ // encode the value.
+ unsigned min_constant_width = 0;
+ if (qual_type->isUnsignedIntegerOrEnumerationType())
+ min_constant_width = constant.Value.getActiveBits();
+ else
+ min_constant_width = constant.Value.getSignificantBits();
if (qual_type->isIntegralOrEnumerationType()) {
- if (type_width >= constant_width) {
+ if (type_width >= min_constant_width) {
TypeSystemClang::SetIntegerInitializerForVariable(
decl, constant.Value.extOrTrunc(type_width));
} else {
@@ -191,7 +199,7 @@ Error UdtRecordCompleter::visitKnownMember(
"which resolves to a wider constant value ({4} bits). "
"Ignoring constant.",
m_derived_ct.GetTypeName(), static_data_member.Name,
- member_ct.GetTypeName(), type_width, constant_width);
+ member_ct.GetTypeName(), type_width, min_constant_width);
}
} else {
lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();
@@ -199,7 +207,7 @@ Error UdtRecordCompleter::visitKnownMember(
case lldb::eBasicTypeFloat:
case lldb::eBasicTypeDouble:
case lldb::eBasicTypeLongDouble:
- if (type_width == constant_width) {
+ if (type_width == min_constant_width) {
TypeSystemClang::SetFloatingInitializerForVariable(
decl, basic_type_enum == lldb::eBasicTypeFloat
? llvm::APFloat(constant.Value.bitsToFloat())
@@ -212,7 +220,7 @@ Error UdtRecordCompleter::visitKnownMember(
"which resolves to a constant value of mismatched width "
"({4} bits). Ignoring constant.",
m_derived_ct.GetTypeName(), static_data_member.Name,
- member_ct.GetTypeName(), type_width, constant_width);
+ member_ct.GetTypeName(), type_width, min_constant_width);
}
break;
default:
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/globals-fundamental.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/globals-fundamental.lldbinit
index 4af8b658742b3..8af31b80eb67f 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/globals-fundamental.lldbinit
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/globals-fundamental.lldbinit
@@ -62,10 +62,15 @@ target variable CD
target variable ConstexprBFalse
target variable ConstexprBTrue
+target variable ConstexprCMin
+target variable ConstexprCMax
target variable ConstexprCA
target variable ConstexprCZ
+target variable ConstexprSCMin
+target variable ConstexprSCMax
target variable ConstexprSCa
target variable ConstexprSCz
+target variable ConstexprUCMax
target variable ConstexprUC24
target variable ConstexprUC42
target variable ConstexprC16_24
@@ -219,4 +224,4 @@ target variable CRWCP
target modules dump ast
-quit
\ No newline at end of file
+quit
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp b/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
index 299dd0b02671d..999d09bae9c6c 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
@@ -199,18 +199,33 @@ constexpr bool ConstexprBFalse = false;
constexpr bool ConstexprBTrue = true;
// CHECK-NEXT: (lldb) target variable ConstexprBTrue
// CHECK-NEXT: (const bool) ConstexprBTrue = true
+constexpr char ConstexprCMin = -128;
+// CHECK-NEXT: (lldb) target variable ConstexprCMin
+// CHECK-NEXT: (const char) ConstexprCMin = '\x80'
+constexpr char ConstexprCMax = 127;
+// CHECK-NEXT: (lldb) target variable ConstexprCMax
+// CHECK-NEXT: (const char) ConstexprCMax = '\x7f'
constexpr char ConstexprCA = 'A';
// CHECK-NEXT: (lldb) target variable ConstexprCA
// CHECK-NEXT: (const char) ConstexprCA = 'A'
constexpr char ConstexprCZ = 'Z';
// CHECK-NEXT: (lldb) target variable ConstexprCZ
// CHECK-NEXT: (const char) ConstexprCZ = 'Z'
+constexpr signed char ConstexprSCMin = -128;
+// CHECK-NEXT: (lldb) target variable ConstexprSCMin
+// CHECK-NEXT: (const signed char) ConstexprSCMin = '\x80'
+constexpr signed char ConstexprSCMax = 127;
+// CHECK-NEXT: (lldb) target variable ConstexprSCMax
+// CHECK-NEXT: (const signed char) ConstexprSCMax = '\x7f'
constexpr signed char ConstexprSCa = 'a';
// CHECK-NEXT: (lldb) target variable ConstexprSCa
// CHECK-NEXT: (const signed char) ConstexprSCa = 'a'
constexpr signed char ConstexprSCz = 'z';
// CHECK-NEXT: (lldb) target variable ConstexprSCz
// CHECK-NEXT: (const signed char) ConstexprSCz = 'z'
+constexpr unsigned char ConstexprUCMax = 255;
+// CHECK-NEXT: (lldb) target variable ConstexprUCMax
+// CHECK-NEXT: (const unsigned char) ConstexprUCMax = '\xff'
constexpr unsigned char ConstexprUC24 = 24;
// CHECK-NEXT: (lldb) target variable ConstexprUC24
// CHECK-NEXT: (const unsigned char) ConstexprUC24 = '\x18'
@@ -725,10 +740,15 @@ const wchar_t &CRWCP = WCP;
// CHECK-NEXT: |-VarDecl {{.*}} CD 'const double'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprBFalse 'const bool'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprBTrue 'const bool'
+// CHECK-NEXT: |-VarDecl {{.*}} ConstexprCMin 'const char'
+// CHECK-NEXT: |-VarDecl {{.*}} ConstexprCMax 'const char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprCA 'const char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprCZ 'const char'
+// CHECK-NEXT: |-VarDecl {{.*}} ConstexprSCMin 'const signed char'
+// CHECK-NEXT: |-VarDecl {{.*}} ConstexprSCMax 'const signed char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprSCa 'const signed char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprSCz 'const signed char'
+// CHECK-NEXT: |-VarDecl {{.*}} ConstexprUCMax 'const unsigned char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprUC24 'const unsigned char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprUC42 'const unsigned char'
// CHECK-NEXT: |-VarDecl {{.*}} ConstexprC16_24 'const char16_t'
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/static-class-constants.cpp b/lldb/test/Shell/SymbolFile/NativePDB/static-class-constants.cpp
new file mode 100644
index 0000000000000..e65618f9774ba
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/static-class-constants.cpp
@@ -0,0 +1,109 @@
+// REQUIRES: lld, x86
+
+// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -GS- -c /Fo%t.obj -- %s
+// RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb
+// RUN: %lldb -f %t.exe -o "type lookup Foo" | FileCheck %s
+
+enum class U8Enum : unsigned char {
+ Max = 255,
+};
+enum class I8Enum : char {
+ Min = 127,
+ Max = -128,
+};
+enum class U16Enum : unsigned short {
+ Max = 65535,
+};
+enum class I16Enum : short {
+ Min = -32768,
+ Max = 32767,
+};
+enum class U32Enum : unsigned {
+ Max = 4294967295U,
+};
+enum class I32Enum : int {
+ Min = -2147483648,
+ Max = 2147483647,
+};
+enum class U64Enum : unsigned long long {
+ Max = 18446744073709551615ULL,
+};
+enum class I64Enum : long long {
+ Min = -9223372036854775807LL - 1,
+ Max = 9223372036854775807LL,
+};
+
+// CHECK: struct Foo {
+struct Foo {
+ // CHECK-NEXT: static const U8Enum u8_enum_max = 255Ui8;
+ static constexpr U8Enum u8_enum_max = U8Enum::Max;
+
+ // CHECK-NEXT: static const I8Enum i8_enum_min = 127i8;
+ static constexpr I8Enum i8_enum_min = I8Enum::Min;
+ // CHECK-NEXT: static const I8Enum i8_enum_max = -128i8;
+ static constexpr I8Enum i8_enum_max = I8Enum::Max;
+
+ // CHECK-NEXT: static const U16Enum u16_enum_max = 65535Ui16;
+ static constexpr U16Enum u16_enum_max = U16Enum::Max;
+
+ // CHECK-NEXT: static const I16Enum i16_enum_min = -32768i16;
+ static constexpr I16Enum i16_enum_min = I16Enum::Min;
+ // CHECK-NEXT: static const I16Enum i16_enum_max = 32767i16;
+ static constexpr I16Enum i16_enum_max = I16Enum::Max;
+
+ // CHECK-NEXT: static const U32Enum u32_enum_max = 4294967295U;
+ static constexpr U32Enum u32_enum_max = U32Enum::Max;
+
+ // CHECK-NEXT: static const I32Enum i32_enum_min = -2147483648;
+ static constexpr I32Enum i32_enum_min = I32Enum::Min;
+ // CHECK-NEXT: static const I32Enum i32_enum_max = 2147483647;
+ static constexpr I32Enum i32_enum_max = I32Enum::Max;
+
+ // CHECK-NEXT: static const U64Enum u64_enum_max = 18446744073709551615ULL;
+ static constexpr U64Enum u64_enum_max = U64Enum::Max;
+
+ // CHECK-NEXT: static const I64Enum i64_enum_min = -9223372036854775808LL;
+ static constexpr I64Enum i64_enum_min = I64Enum::Min;
+ // CHECK-NEXT: static const I64Enum i64_enum_max = 9223372036854775807LL;
+ static constexpr I64Enum i64_enum_max = I64Enum::Max;
+
+ // CHECK-NEXT: static const unsigned char u8_max = 255Ui8;
+ static constexpr unsigned char u8_max = 255;
+
+ // CHECK-NEXT: static const char i8_min = -128i8;
+ static constexpr char i8_min = -128;
+ // CHECK-NEXT: static const char i8_max = 127i8;
+ static constexpr char i8_max = 127;
+
+ // CHECK-NEXT: static const unsigned short u16_max = 65535Ui16;
+ static constexpr unsigned short u16_max = 65535;
+
+ // CHECK-NEXT: static const short i16_min = -32768i16;
+ static constexpr short i16_min = -32767 - 1;
+ // CHECK-NEXT: static const short i16_max = 32767i16;
+ static constexpr short i16_max = 32767;
+
+ // CHECK-NEXT: static const unsigned int u32_max = 4294967295U;
+ static constexpr unsigned u32_max = 4294967295;
+
+ // CHECK-NEXT: static const int i32_min = -2147483648;
+ static constexpr int i32_min = -2147483648;
+ // CHECK-NEXT: static const int i32_max = 2147483647;
+ static constexpr int i32_max = 2147483647;
+
+ // CHECK-NEXT: static const unsigned long long u64_max = 18446744073709551615ULL;
+ static constexpr unsigned long long u64_max = 18446744073709551615ULL;
+
+ // CHECK-NEXT: static const long long i64_min = -9223372036854775808LL;
+ static constexpr long long i64_min = -9223372036854775807LL - 1;
+ // CHECK-NEXT: static const long long i64_max = 9223372036854775807LL;
+ static constexpr long long i64_max = 9223372036854775807LL;
+
+ // CHECK-NEXT: int i;
+ int i;
+};
+
+int main() {
+ Foo f{42};
+ return f.i;
+}
More information about the lldb-commits
mailing list