https://github.com/phyBrackets updated 
https://github.com/llvm/llvm-project/pull/182442

>From 94218e0815c4552e3ff9949e752f18aeb16bdd08 Mon Sep 17 00:00:00 2001
From: Shivam Kunwar <[email protected]>
Date: Fri, 20 Feb 2026 11:51:31 +0530
Subject: [PATCH 1/2] [DebugInfo] Emit DW_AT_const_value for constexpr array
 static members

---
 clang/lib/CodeGen/CGDebugInfo.cpp             | 47 ++++++++++++
 .../CodeGenCXX/debug-info-constexpr-array.cpp | 23 ++++++
 llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp     | 11 ++-
 .../X86/debug-info-constexpr-array.ll         | 73 +++++++++++++++++++
 4 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGenCXX/debug-info-constexpr-array.cpp
 create mode 100644 llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 5e452245ee627..951cb3d6b5b7e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2092,6 +2092,53 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, 
llvm::DIType *RecordTy,
         C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
       if (Value->isFloat())
         C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
+      if (Value->isArray()) {
+        // Handle constexpr array constants for debug info
+        // We handle arrays of integer types (char, short, int, long),
+        // which covers the most common and useful cases.
+        if (const auto *ArrayTy =
+                CGM.getContext().getAsArrayType(Var->getType())) {
+          QualType ElemQTy = ArrayTy->getElementType();
+          if (ElemQTy->isIntegerType()) {
+            unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy);
+            unsigned NumElts = Value->getArraySize();
+            unsigned NumInits = Value->getArrayInitializedElts();
+            SmallVector<uint64_t, 64> Vals;
+            Vals.reserve(NumElts);
+            bool Success = true;
+            for (unsigned I = 0; I < NumInits && Success; ++I) {
+              const APValue &Elt = Value->getArrayInitializedElt(I);
+              if (Elt.isInt())
+                Vals.push_back(Elt.getInt().getZExtValue());
+              else
+                Success = false;
+            }
+            // Fill remaining elements with the filler value (e.g., the
+            // null terminator region for strings).
+            if (Success && NumInits < NumElts) {
+              const APValue &Filler = Value->getArrayFiller();
+              if (Filler.isInt())
+                Vals.resize(NumElts, Filler.getInt().getZExtValue());
+              else
+                Success = false;
+            }
+            if (Success && Vals.size() == NumElts) {
+              if (ElemBitWidth == 8) {
+                SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end());
+                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes);
+              } else if (ElemBitWidth == 16) {
+                SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end());
+                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
+              } else if (ElemBitWidth == 32) {
+                SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end());
+                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
+              } else if (ElemBitWidth == 64) {
+                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals);
+              }
+            }
+          }
+        }
+      }
     }
   }
 
diff --git a/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp 
b/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp
new file mode 100644
index 0000000000000..289eb9f7e7a9c
--- /dev/null
+++ b/clang/test/CodeGenCXX/debug-info-constexpr-array.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm \
+// RUN:   -debug-info-kind=standalone -o - %s | FileCheck %s
+
+struct Test {
+  static inline constexpr char STR[] = "Hello";
+  static inline constexpr int NUMS[] = {1, 2, 3};
+  static inline constexpr unsigned char BYTES[] = {0xDE, 0xAD};
+};
+
+void use() {
+  (void)Test::STR;
+  (void)Test::NUMS;
+  (void)Test::BYTES;
+}
+
+// "Hello\0" as [6 x i8]
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "STR"{{.*}}extraData: 
[6 x i8] c"Hello\00"
+
+// {1, 2, 3} as [3 x i32]
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "NUMS"{{.*}}extraData: 
[3 x i32] [i32 1, i32 2, i32 3]
+
+// {0xDE, 0xAD} as [2 x i8]
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "BYTES"{{.*}}extraData: 
[2 x i8] c"\DE\AD"
\ No newline at end of file
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index baffd81b4f336..d3a03429f82f4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -2036,8 +2036,17 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const 
DIDerivedType *DT) {
 
   if (const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(DT->getConstant()))
     addConstantValue(StaticMemberDIE, CI, Ty);
-  if (const ConstantFP *CFP = dyn_cast_or_null<ConstantFP>(DT->getConstant()))
+  else if (const ConstantFP *CFP =
+               dyn_cast_or_null<ConstantFP>(DT->getConstant()))
     addConstantFPValue(StaticMemberDIE, CFP);
+  else if (auto *CDS =
+               dyn_cast_or_null<ConstantDataSequential>(DT->getConstant())) {
+    StringRef RawData = CDS->getRawDataValues();
+    auto *Block = new (DIEValueAllocator) DIEBlock;
+    for (unsigned char Byte : RawData)
+      addUInt(*Block, dwarf::DW_FORM_data1, Byte);
+    addBlock(StaticMemberDIE, dwarf::DW_AT_const_value, Block);
+  }
 
   if (uint32_t AlignInBytes = DT->getAlignInBytes())
     addUInt(StaticMemberDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata,
diff --git a/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll 
b/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll
new file mode 100644
index 0000000000000..ef699f7e8a6c1
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/debug-info-constexpr-array.ll
@@ -0,0 +1,73 @@
+; RUN: llc -mtriple=x86_64-linux-gnu -filetype=obj %s -o %t.o
+; RUN: llvm-dwarfdump --debug-info %t.o | FileCheck %s
+;
+; Reduced from clang output for:
+;   struct Test {
+;     static inline constexpr char STR[] = "Hello";
+;     static inline constexpr int NUMS[] = {1, 2, 3};
+;     static inline constexpr unsigned char BYTES[] = {0xDE, 0xAD};
+;   };
+;   void use() { (void)Test::STR; (void)Test::NUMS; (void)Test::BYTES; }
+
+; CHECK:      DW_TAG_structure_type
+; CHECK:        DW_AT_name ("Test")
+;
+; CHECK:      DW_TAG_member
+; CHECK:        DW_AT_name ("STR")
+; CHECK:        DW_AT_const_value (<0x06> 48 65 6c 6c 6f 00 )
+;
+; CHECK:      DW_TAG_member
+; CHECK:        DW_AT_name ("NUMS")
+; CHECK:        DW_AT_const_value (<0x0c> 01 00 00 00 02 00 00 00 03 00 00 00 )
+;
+; CHECK:      DW_TAG_member
+; CHECK:        DW_AT_name ("BYTES")
+; CHECK:        DW_AT_const_value (<0x02> de ad )
+
+@_ZN4Test3STRE = linkonce_odr constant [6 x i8] c"Hello\00", align 1, !dbg !0
+@_ZN4Test4NUMSE = linkonce_odr constant [3 x i32] [i32 1, i32 2, i32 3], align 
4, !dbg !5
+@_ZN4Test5BYTESE = linkonce_odr constant [2 x i8] c"\DE\AD", align 1, !dbg !28
+
+define dso_local void @_Z3usev() !dbg !33 {
+  ret void, !dbg !36
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!30, !31}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "STR", linkageName: "_ZN4Test3STRE", 
scope: !2, file: !7, line: 5, type: !17, isLocal: false, isDefinition: true, 
declaration: !16)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, 
producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: 
FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.cpp", directory: "")
+!4 = !{!0, !5, !28}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "NUMS", linkageName: "_ZN4Test4NUMSE", 
scope: !2, file: !7, line: 6, type: !8, isLocal: false, isDefinition: true, 
declaration: !13)
+!7 = !DIFile(filename: "test.cpp", directory: "")
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 96, 
elements: !11)
+!9 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !10)
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DISubrange(count: 3)
+!13 = !DIDerivedType(tag: DW_TAG_member, name: "NUMS", scope: !14, file: !7, 
line: 6, baseType: !8, flags: DIFlagStaticMember, extraData: [3 x i32] [i32 1, 
i32 2, i32 3])
+!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Test", 
file: !7, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !15, 
identifier: "_ZTS4Test")
+!15 = !{!16, !13, !22}
+!16 = !DIDerivedType(tag: DW_TAG_member, name: "STR", scope: !14, file: !7, 
line: 5, baseType: !17, flags: DIFlagStaticMember, extraData: [6 x i8] 
c"Hello\00")
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 48, 
elements: !20)
+!18 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !19)
+!19 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!20 = !{!21}
+!21 = !DISubrange(count: 6)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "BYTES", scope: !14, file: !7, 
line: 7, baseType: !23, flags: DIFlagStaticMember, extraData: [2 x i8] 
c"\DE\AD")
+!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 16, 
elements: !26)
+!24 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !25)
+!25 = !DIBasicType(name: "unsigned char", size: 8, encoding: 
DW_ATE_unsigned_char)
+!26 = !{!27}
+!27 = !DISubrange(count: 2)
+!28 = !DIGlobalVariableExpression(var: !29, expr: !DIExpression())
+!29 = distinct !DIGlobalVariable(name: "BYTES", linkageName: 
"_ZN4Test5BYTESE", scope: !2, file: !7, line: 7, type: !23, isLocal: false, 
isDefinition: true, declaration: !22)
+!30 = !{i32 2, !"Debug Info Version", i32 3}
+!31 = !{i32 1, !"wchar_size", i32 4}
+!33 = distinct !DISubprogram(name: "use", linkageName: "_Z3usev", scope: !7, 
file: !7, line: 10, type: !34, scopeLine: 10, flags: DIFlagPrototyped, spFlags: 
DISPFlagDefinition, unit: !2)
+!34 = !DISubroutineType(types: !35)
+!35 = !{null}
+!36 = !DILocation(line: 14, column: 1, scope: !33)
\ No newline at end of file

>From 5779b6ec25dade8fd548b148034c21052c12f557 Mon Sep 17 00:00:00 2001
From: Shivam Kunwar <[email protected]>
Date: Mon, 23 Feb 2026 12:12:16 +0530
Subject: [PATCH 2/2] refactored based on the review comments

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 94 +++++++++++++++++--------------
 1 file changed, 51 insertions(+), 43 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 951cb3d6b5b7e..ff64117b5e727 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2094,50 +2094,58 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl 
*Var, llvm::DIType *RecordTy,
         C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
       if (Value->isArray()) {
         // Handle constexpr array constants for debug info
-        // We handle arrays of integer types (char, short, int, long),
-        // which covers the most common and useful cases.
-        if (const auto *ArrayTy =
-                CGM.getContext().getAsArrayType(Var->getType())) {
-          QualType ElemQTy = ArrayTy->getElementType();
-          if (ElemQTy->isIntegerType()) {
-            unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy);
-            unsigned NumElts = Value->getArraySize();
-            unsigned NumInits = Value->getArrayInitializedElts();
-            SmallVector<uint64_t, 64> Vals;
-            Vals.reserve(NumElts);
-            bool Success = true;
-            for (unsigned I = 0; I < NumInits && Success; ++I) {
-              const APValue &Elt = Value->getArrayInitializedElt(I);
-              if (Elt.isInt())
-                Vals.push_back(Elt.getInt().getZExtValue());
-              else
-                Success = false;
-            }
-            // Fill remaining elements with the filler value (e.g., the
-            // null terminator region for strings).
-            if (Success && NumInits < NumElts) {
-              const APValue &Filler = Value->getArrayFiller();
-              if (Filler.isInt())
-                Vals.resize(NumElts, Filler.getInt().getZExtValue());
-              else
-                Success = false;
-            }
-            if (Success && Vals.size() == NumElts) {
-              if (ElemBitWidth == 8) {
-                SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end());
-                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes);
-              } else if (ElemBitWidth == 16) {
-                SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end());
-                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
-              } else if (ElemBitWidth == 32) {
-                SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end());
-                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
-              } else if (ElemBitWidth == 64) {
-                C = llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals);
-              }
-            }
+        // We handle arrays of integer types (char, short, int, long)
+        // with element width up to 64 bits.
+        auto TryEmitArrayConstant = [&]() -> llvm::Constant * {
+          const auto *ArrayTy = 
CGM.getContext().getAsArrayType(Var->getType());
+          if (!ArrayTy)
+            return nullptr;
+
+          const QualType ElemQTy = ArrayTy->getElementType();
+          if (!ElemQTy->isIntegerType())
+            return nullptr;
+
+          const unsigned ElemBitWidth = CGM.getContext().getTypeSize(ElemQTy);
+          // ConstantDataArray only supports 8/16/32/64-bit elements, and
+          // getZExtValue() asserts on wider types (e.g. __int128).
+          if (ElemBitWidth > 64)
+            return nullptr;
+
+          const unsigned NumElts = Value->getArraySize();
+          const unsigned NumInits = Value->getArrayInitializedElts();
+
+          // Preallocate with filler value, then overwrite initialized 
elements.
+          uint64_t FillVal = 0;
+          if (NumInits < NumElts) {
+            const APValue &Filler = Value->getArrayFiller();
+            if (!Filler.isInt())
+              return nullptr;
+            FillVal = Filler.getInt().getZExtValue();
           }
-        }
+
+          SmallVector<uint64_t, 64> Vals(NumElts, FillVal);
+          for (unsigned I = 0; I < NumInits; ++I) {
+            const APValue &Elt = Value->getArrayInitializedElt(I);
+            if (!Elt.isInt())
+              return nullptr;
+            Vals[I] = Elt.getInt().getZExtValue();
+          }
+
+          if (ElemBitWidth == 8) {
+            SmallVector<uint8_t, 64> Bytes(Vals.begin(), Vals.end());
+            return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Bytes);
+          } else if (ElemBitWidth == 16) {
+            SmallVector<uint16_t, 64> Elts(Vals.begin(), Vals.end());
+            return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
+          } else if (ElemBitWidth == 32) {
+            SmallVector<uint32_t, 32> Elts(Vals.begin(), Vals.end());
+            return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Elts);
+          } else if (ElemBitWidth == 64) {
+            return llvm::ConstantDataArray::get(CGM.getLLVMContext(), Vals);
+          }
+          return nullptr;
+        };
+        C = TryEmitArrayConstant();
       }
     }
   }

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

Reply via email to