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 <[email protected]>
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;
+}

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to