From 3860c0b95ce99e944d1598513428c5e81aeea395 Mon Sep 17 00:00:00 2001 From: Nerixyz 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 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, std::allocator>" + if self.getDebugInfo() == "pdb" + else "std::basic_string" + ) + 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 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(v1); + + v4 = "a string"; + printf("%f\n", d); // break here try { From ae5ecead822566dbe5317a1e6372428a36173540 Mon Sep 17 00:00:00 2001 From: Nerixyz 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)