[Lldb-commits] [lldb] [LLDB] Fix MS STL `variant` with non-trivial types and PDB (PR #171489)

via lldb-commits lldb-commits at lists.llvm.org
Wed Dec 10 08:57:22 PST 2025


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/171489

>From 3860c0b95ce99e944d1598513428c5e81aeea395 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 6 Nov 2025 19:51:20 +0100
Subject: [PATCH 1/2] [LLDB] Fix MS STL `variant` with non-trivial types and
 PDB

---
 .../Language/CPlusPlus/MsvcStlVariant.cpp     | 25 +++++++++++++------
 .../variant/TestDataFormatterStdVariant.py    | 23 +++++++++++++++++
 .../generic/variant/main.cpp                  |  5 ++++
 3 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 52a3d98d2af4b..3391ca33a9277 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -67,12 +67,18 @@ std::optional<int64_t> GetIndexValue(ValueObject &valobj) {
 ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) {
   // We need to find the std::_Variant_storage base class.
 
-  // -> std::_SMF_control (typedef to std::_Variant_base)
-  ValueObjectSP container_sp = outer.GetSP()->GetChildAtIndex(0);
-  if (!container_sp)
+  // Navigate "down" to std::_Variant_base by finding the holder of "_Which".
+  // This might be down a few levels if a variant member isn't trivially
+  // destructible/copyable/etc.
+  ValueObjectSP which_sp = outer.GetChildMemberWithName("_Which");
+  if (!which_sp)
+    return nullptr;
+  ValueObject *parent = which_sp->GetParent();
+  if (!parent)
     return nullptr;
-  // -> std::_Variant_storage
-  container_sp = container_sp->GetChildAtIndex(0);
+
+  // Now go to std::_Variant_storage
+  ValueObjectSP container_sp = parent->GetChildAtIndex(0);
   if (!container_sp)
     return nullptr;
 
@@ -119,8 +125,13 @@ bool formatters::MsvcStlVariantSummaryProvider(
     storage_type = storage_type.GetTypedefedType();
 
   CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);
-  if (!active_type)
-    return false;
+  if (!active_type) {
+    // PDB: get the type from the head as we don't have template arguments there
+    ValueObjectSP head = GetHead(*storage);
+    active_type = head->GetCompilerType();
+    if (!active_type)
+      return false;
+  }
 
   stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
   return true;
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
index 9f32ad97c1f0a..d5c4f5c34cfe0 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
@@ -9,6 +9,8 @@
 
 
 class StdVariantDataFormatterTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+
     def do_test(self):
         """Test that that file and class static variables display correctly."""
 
@@ -48,6 +50,14 @@ def cleanup():
             ],
         )
 
+        self.expect_expr(
+            "v4",
+            result_summary=" Active Type = int ",
+            result_children=[
+                ValueCheck(name="Value", value="4"),
+            ],
+        )
+
         lldbutil.continue_to_breakpoint(self.process, bkpt)
 
         self.expect(
@@ -67,6 +77,19 @@ def cleanup():
             substrs=["v3 =  Active Type = char  {", "Value = 'A'", "}"],
         )
 
+        string_name = (
+            "std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
+            if self.getDebugInfo() == "pdb"
+            else "std::basic_string<char>"
+        )
+        self.expect_expr(
+            "v4",
+            result_summary=f" Active Type = {string_name} ",
+            result_children=[
+                ValueCheck(name="Value", summary='"a string"'),
+            ],
+        )
+
         self.expect("frame variable v_valueless", substrs=["v_valueless =  No Value"])
 
         self.expect(
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/main.cpp
index 620b97b7306f9..9983104ca9628 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/main.cpp
@@ -49,6 +49,8 @@ int main() {
       S>
       v_300_types_valueless;
 
+  std::variant<int, bool, std::string> v4 = 4;
+
   v_valueless = 5;
   v_300_types_valueless.emplace<0>(10);
 
@@ -70,6 +72,9 @@ int main() {
   // state when we change its value.
   v1 = 2.0;
   d = std::get<double>(v1);
+
+  v4 = "a string";
+
   printf("%f\n", d); // break here
 
   try {

>From ae5ecead822566dbe5317a1e6372428a36173540 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 10 Dec 2025 17:57:05 +0100
Subject: [PATCH 2/2] fix: comments

---
 lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 3391ca33a9277..96470eaf572e4 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -77,7 +77,7 @@ ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) {
   if (!parent)
     return nullptr;
 
-  // Now go to std::_Variant_storage
+  // Now go to std::_Variant_storage.
   ValueObjectSP container_sp = parent->GetChildAtIndex(0);
   if (!container_sp)
     return nullptr;
@@ -126,7 +126,8 @@ bool formatters::MsvcStlVariantSummaryProvider(
 
   CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);
   if (!active_type) {
-    // PDB: get the type from the head as we don't have template arguments there
+    // PDB: get the type from the head as we don't have template arguments
+    // there.
     ValueObjectSP head = GetHead(*storage);
     active_type = head->GetCompilerType();
     if (!active_type)



More information about the lldb-commits mailing list