[Lldb-commits] [lldb] Use `llvm::APInt` for `VariantMember` Discriminants (PR #188487)

via lldb-commits lldb-commits at lists.llvm.org
Sat Apr 11 02:32:36 PDT 2026


https://github.com/Walnut356 updated https://github.com/llvm/llvm-project/pull/188487

>From 2feb0dde6dc49145b21a5b8edd087a9a93af187f Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356 at users.noreply.github.com>
Date: Sat, 11 Apr 2026 04:32:12 -0500
Subject: [PATCH] use `llvm::APInt` for variant discriminants

---
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 45 ++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index cb33fc21bfba9..a98c9855a339b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -13,6 +13,7 @@
 #include "DWARFDebugInfo.h"
 #include "DWARFDeclContext.h"
 #include "DWARFDefines.h"
+#include "DWARFFormValue.h"
 #include "SymbolFileDWARF.h"
 #include "SymbolFileDWARFDebugMap.h"
 #include "SymbolFileDWARFDwo.h"
@@ -2568,7 +2569,7 @@ struct VariantMember {
   explicit VariantMember(DWARFDIE &die, ModuleSP module_sp);
   bool IsDefault() const;
 
-  std::optional<uint32_t> discr_value;
+  std::optional<llvm::APInt> discr_value;
   DWARFFormValue type_ref;
   ConstString variant_name;
   uint32_t byte_offset;
@@ -2596,8 +2597,35 @@ bool VariantMember::IsDefault() const { return !discr_value; }
 
 VariantMember::VariantMember(DWARFDIE &die, lldb::ModuleSP module_sp) {
   assert(die.Tag() == llvm::dwarf::DW_TAG_variant);
-  this->discr_value =
-      die.GetAttributeValueAsOptionalUnsigned(DW_AT_discr_value);
+
+  DWARFFormValue discr_form;
+  die.GetDIE()->GetAttributeValue(die.GetCU(), DW_AT_discr_value, discr_form);
+
+  // Rust can output 128-bit discrs (e.g. NonNull<u128>) as `DW_FORM_block1`.
+  // There is a `data16`, but the DIE function treats it as a block anyway.
+  // Handling is included for it just in case rust's output changes to the
+  // `data16` version.
+  dw_form_t form = discr_form.Form();
+  if ((form == DW_FORM_block1 && discr_form.Unsigned() == 16) ||
+      form == DW_FORM_data16) {
+    const uint8_t *block_data = discr_form.BlockData();
+
+    DataExtractor extractor(block_data, 16, die.GetCU()->GetByteOrder(),
+                            die.GetCU()->GetAddressByteSize());
+    lldb::offset_t offset = 0;
+    uint64_t lo = extractor.GetU64(&offset);
+    uint64_t hi = extractor.GetU64(&offset);
+    uint64_t words[] = {lo, hi};
+    this->discr_value = llvm::APInt(128, words);
+  } else {
+    if (auto result =
+            die.GetAttributeValueAsOptionalUnsigned(DW_AT_discr_value)) {
+      this->discr_value =
+          llvm::APInt(sizeof(uint64_t) * 8, result.value(), false);
+    } else {
+      this->discr_value = std::nullopt;
+    };
+  }
 
   for (auto child_die : die.children()) {
     switch (child_die.Tag()) {
@@ -3834,9 +3862,14 @@ void DWARFASTParserClang::ParseRustVariantPart(
 
     m_ast.CompleteTagDeclarationDefinition(field_type);
 
-    auto name = has_discriminant
-                    ? llvm::formatv("$variant${0}", member.discr_value.value())
-                    : std::string("$variant$");
+    auto name = std::string("$variant$");
+    if (has_discriminant) {
+      // u128::MAX = 340282366920938463463374607431768211455 which is 39 digits
+      // long + 1 for null terminator.
+      llvm::SmallString<40> discr_str;
+      member.discr_value.value().toStringUnsigned(discr_str);
+      name.append(discr_str.c_str());
+    }
 
     auto variant_decl = m_ast.AddFieldToRecordType(
         inner_holder, llvm::StringRef(name), field_type, 0);



More information about the lldb-commits mailing list