llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: nerix (Nerixyz) <details> <summary>Changes</summary> Some formatters for the MSVC STL didn't work with the PDB symbol file plugins. They were only tested with DWARF. The individual changes are quite small (except for variant), so I'm not sure if they should be separate PRs. The changes are broadly: - Account for different type names (NativePDB has spaces after commas, but not after closing angle brackets) - Fall back to types of members if templates are not available - Account for anonymous unions being "flattened" into the parent type with DIA PDB It also adds tests for both plugins. They are shell tests, because API tests currently only test with DWARF and after #<!-- -->149305 they'd only test with one plugin. They're not as exhaustive as the API tests - their goal is to show that when using PDB, the STL types are still properly shown. For Native PDB I found two bugs which I haven't inspected closer: - For `std::optional`, [`_Has_value`](https://github.com/microsoft/STL/blob/f015db5833e8daf3a5534c4ce2b6c9acc9689b0c/stl/inc/optional#L75) got put into the union into a new struct that contained `_Value` and `_Has_value`. - `std::deque` uses a static constexpr `_Block_size` which doesn't have a value with native PDB (works with DIA). --- Patch is 21.91 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150513.diff 7 Files Affected: - (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+13-19) - (modified) lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp (+17-3) - (modified) lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp (+10-6) - (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp (+10-7) - (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp (+22-10) - (added) lldb/test/Shell/SymbolFile/NativePDB/stl_types.test (+188) - (added) lldb/test/Shell/SymbolFile/PDB/stl_types.test (+197) ``````````diff diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index e69f2f677e9ab..cd7cda4c91f04 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1335,31 +1335,25 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { static void RegisterStdStringSummaryProvider( const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty, llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) { - auto makeSpecifier = [](llvm::StringRef name) { - return std::make_shared<lldb_private::TypeNameSpecifierImpl>( - name, eFormatterMatchExact); - }; - - category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp); - - // std::basic_string<char> category_sp->AddTypeSummary( - makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()), + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + string_ty, eFormatterMatchExact), summary_sp); - // std::basic_string<char,std::char_traits<char>,std::allocator<char> > + + // std::basic_string<char> category_sp->AddTypeSummary( - makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>," - "std::allocator<{0}> >", - char_ty) - .str()), + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + llvm::formatv("std::basic_string<{}>", char_ty).str(), + eFormatterMatchExact), summary_sp); - // std::basic_string<char, std::char_traits<char>, std::allocator<char> > + // std::basic_string<char, std::char_traits<char>, std::allocator<char>> category_sp->AddTypeSummary( - makeSpecifier( - llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, " - "std::allocator<{0}> >", + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + llvm::formatv("std::basic_string<{0}, ?std::char_traits<{0}>, " + "?std::allocator<{0}> ?>", char_ty) - .str()), + .str(), + eFormatterMatchRegex), summary_sp); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp index ea1edbfd3ac9b..3d4dcfa3b4ff5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp @@ -526,9 +526,17 @@ ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) { lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); - if (auto head_sp = - m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"})) - m_head = head_sp.get(); + auto head_sp = + m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}); + if (!head_sp) + return ChildCacheState::eRefetch; + + m_head = head_sp.get(); + if (!m_element_type) { + auto val_sp = head_sp->GetChildMemberWithName("_Myval"); + if (val_sp) + m_element_type = val_sp->GetCompilerType(); + } return ChildCacheState::eRefetch; } @@ -606,6 +614,12 @@ lldb::ChildCacheState MsvcStlListFrontEnd::Update() { m_head = first.get(); m_tail = last.get(); + if (!m_element_type) { + auto val_sp = m_head->GetChildMemberWithName("_Myval"); + if (val_sp) + m_element_type = val_sp->GetCompilerType(); + } + return lldb::ChildCacheState::eRefetch; } diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp index 7fc6eb55d4e3e..f9c8c0be7420d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp @@ -117,12 +117,16 @@ ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) { ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value"); if (candidate) val_sp = candidate; - } else if (m_stdlib == StdLib::MsvcStl) - // Same issue as with LibCxx - val_sp = m_backend.GetChildMemberWithName("_Has_value") - ->GetParent() - ->GetChildAtIndex(0) - ->GetChildMemberWithName("_Value"); + } else if (m_stdlib == StdLib::MsvcStl) { + // PDB flattens anonymous unions to the parent + val_sp = m_backend.GetChildMemberWithName("_Value"); + // With DWARF and NativePDB, same issue as with LibCxx + if (!val_sp) + val_sp = m_backend.GetChildMemberWithName("_Has_value") + ->GetParent() + ->GetChildAtIndex(0) + ->GetChildMemberWithName("_Value"); + } if (!val_sp) return ValueObjectSP(); diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp index 873354381a6da..aa313abb04be2 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp @@ -111,13 +111,6 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() { if (!block_size.IsValid()) return lldb::eRefetch; - auto element_type = deque_type.GetTypeTemplateArgument(0); - if (!element_type) - return lldb::eRefetch; - auto element_size = element_type.GetByteSize(nullptr); - if (!element_size) - return lldb::eRefetch; - auto offset_sp = storage_sp->GetChildMemberWithName("_Myoff"); auto map_size_sp = storage_sp->GetChildMemberWithName("_Mapsize"); auto map_sp = storage_sp->GetChildMemberWithName("_Map"); @@ -138,6 +131,16 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() { if (!ok) return lldb::eRefetch; + auto element_type = deque_type.GetTypeTemplateArgument(0); + if (!element_type) { + element_type = map_sp->GetCompilerType().GetPointeeType().GetPointeeType(); + if (!element_type) + return lldb::eRefetch; + } + auto element_size = element_type.GetByteSize(nullptr); + if (!element_size) + return lldb::eRefetch; + m_map = map_sp.get(); m_exe_ctx_ref = m_backend.GetExecutionContextRef(); m_block_size = block_size.ULongLong(); diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp index 52a3d98d2af4b..b3a93a0786740 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp @@ -42,7 +42,11 @@ namespace { // } ValueObjectSP GetStorageMember(ValueObject &valobj, llvm::StringRef name) { - // Find the union + // DIA PDB flattens the union into the storage + if (valobj.GetNumChildrenIgnoringErrors(3) >= 2) + return valobj.GetChildMemberWithName(name); + + // DWARF and NativePDB: Find the union ValueObjectSP union_sp = valobj.GetChildAtIndex(0); if (!union_sp) return nullptr; @@ -65,14 +69,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::_SMF_control/std::_Variant_base + // by finding the holder of "_Which". This might be down a few levels if a + // variant member isn't trivally 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 +127,12 @@ bool formatters::MsvcStlVariantSummaryProvider( storage_type = storage_type.GetTypedefedType(); CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true); - if (!active_type) - return false; + if (!active_type) { + 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/Shell/SymbolFile/NativePDB/stl_types.test b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test new file mode 100644 index 0000000000000..45960a80211e0 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test @@ -0,0 +1,188 @@ +# REQUIRES: target-windows + +# Test that LLDB can format types from MSVC's STL +# RUN: split-file %s %t +# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp +# RUN: %lldb -f %t.exe -s \ +# RUN: %t/commands.input 2>&1 | FileCheck %s + +#--- main.cpp + +#include <bitset> +#include <coroutine> +#include <deque> +#include <forward_list> +#include <list> +#include <map> +#include <memory> +#include <optional> +#include <set> +#include <string> +#include <tuple> +#include <unordered_map> +#include <unordered_set> +#include <variant> +#include <vector> + +int main() { + std::shared_ptr<int> sp = std::make_shared<int>(41); + std::weak_ptr<int> wp = sp; + std::unique_ptr<int> unique(new int(42)); + std::optional<std::u16string> opt = u"abc"; + std::string str = "str"; + std::u8string u8str = u8"str"; + std::wstring wStr = L"wstr"; + std::tuple<int, bool, float> tuple{1, false, 4.2}; + std::coroutine_handle<> coroHandle; + std::bitset<16> bitset(123); + + std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}}; + auto mapIt = map.find(3); + std::set<int> set{1, 2, 3}; + std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}}; + std::multiset<int> mSet{1, 2, 3}; + + std::variant<int, float, std::string, std::monostate> variant = "wow"; + std::list<int> list{1, 2, 3}; + std::forward_list<int> fwList{1, 2, 3}; + + std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}}; + std::unordered_set<int> uSet{1, 2, 4}; + std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}}; + std::unordered_multiset<int> uMSet{1, 1, 2}; + std::deque<int> deque{1, 2, 3}; + std::vector<int> vec{1, 2, 3}; + return 0; // break here +} + +#--- commands.input + +br s -p "break here" +r + +fr v sp +fr v wp +fr v unique +# FIXME: _Has_value is put into the anonymous union along with _Value +# fr v opt +fr v str +fr v u8str +fr v wStr +fr v tuple +fr v map +fr v mapIt +fr v set +fr v mMap +fr v mSet +fr v variant +fr v list +fr v fwList +fr v uMap +fr v uSet +fr v uMMap +fr v uMSet +# FIXME: Static _Block_size is found but doesn't have a value +# fr v deque +fr v vec + +quit + +# CHECK: (lldb) fr v sp +# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v wp +# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v unique +# CHECK-NEXT: (std::unique_ptr<int, std::default_delete<int>>) unique = 42 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v str +# CHECK-NEXT: (std::basic_string<char, std::char_traits<char>, std::allocator<char>>) str = "str" +# CHECK-NEXT: (lldb) fr v u8str +# CHECK-NEXT: (std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>) u8str = u8"str" +# CHECK-NEXT: (lldb) fr v wStr +# CHECK-NEXT: (std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>) wStr = L"wstr" +# CHECK-NEXT: (lldb) fr v tuple +# CHECK-NEXT: (std::tuple<int, bool, float>) tuple = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = false +# CHECK-NEXT: [2] = 4.{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v map +# CHECK-NEXT: (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) map = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 2, second = 4) +# CHECK-NEXT: [2] = (first = 3, second = 6) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mapIt +# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<int const, int>>>>) mapIt = { +# CHECK-NEXT: first = 3 +# CHECK-NEXT: second = 6 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v set +# CHECK-NEXT: (std::set<int, std::less<int>, std::allocator<int>>) set = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mMap +# CHECK-NEXT: (std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) mMap = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 1, second = 1) +# CHECK-NEXT: [2] = (first = 2, second = 4) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mSet +# CHECK-NEXT: (std::multiset<int, std::less<int>, std::allocator<int>>) mSet = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v variant +# CHECK-NEXT: (std::variant<int, float, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::monostate>) variant = Active Type = std::basic_string<char, std::char_traits<char>, std::allocator<char>> { +# CHECK-NEXT: Value = "wow" +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v list +# CHECK-NEXT: (std::list<int, std::allocator<int>>) list = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v fwList +# CHECK-NEXT: (std::forward_list<int, std::allocator<int>>) fwList = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v uMap +# CHECK-NEXT: (std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMap = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 2, second = 4) +# CHECK-NEXT: [2] = (first = 3, second = 6) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v uSet +# CHECK-NEXT: (std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uSet = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 4 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v uMMap +# CHECK-NEXT: (std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMMap = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 1, second = 1) +# CHECK-NEXT: [2] = (first = 2, second = 4) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v uMSet +# CHECK-NEXT: (std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uMSet = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 1 +# CHECK-NEXT: [2] = 2 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v vec +# CHECK-NEXT: (std::vector<int, std::allocator<int>>) vec = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } diff --git a/lldb/test/Shell/SymbolFile/PDB/stl_types.test b/lldb/test/Shell/SymbolFile/PDB/stl_types.test new file mode 100644 index 0000000000000..0472bf5f27f06 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/PDB/stl_types.test @@ -0,0 +1,197 @@ +# REQUIRES: target-windows + +# Test that LLDB can format types from MSVC's STL +# RUN: split-file %s %t +# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp +# RUN: %lldb -f %t.exe -s \ +# RUN: %t/commands.input 2>&1 | FileCheck %s + +#--- main.cpp + +#include <bitset> +#include <coroutine> +#include <deque> +#include <forward_list> +#include <list> +#include <map> +#include <memory> +#include <optional> +#include <set> +#include <string> +#include <tuple> +#include <unordered_map> +#include <unordered_set> +#include <variant> +#include <vector> + +int main() { + std::shared_ptr<int> sp = std::make_shared<int>(41); + std::weak_ptr<int> wp = sp; + std::unique_ptr<int> unique(new int(42)); + std::optional<std::u16string> opt = u"abc"; + std::string str = "str"; + std::u8string u8str = u8"str"; + std::wstring wStr = L"wstr"; + std::tuple<int, bool, float> tuple{1, false, 4.2}; + std::coroutine_handle<> coroHandle; + std::bitset<16> bitset(123); + + std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}}; + auto mapIt = map.find(3); + std::set<int> set{1, 2, 3}; + std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}}; + std::multiset<int> mSet{1, 2, 3}; + + std::variant<int, float, std::string, std::monostate> variant = "wow"; + std::list<int> list{1, 2, 3}; + std::forward_list<int> fwList{1, 2, 3}; + + std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}}; + std::unordered_set<int> uSet{1, 2, 4}; + std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}}; + std::unordered_multiset<int> uMSet{1, 1, 2}; + std::deque<int> deque{1, 2, 3}; + std::vector<int> vec{1, 2, 3}; + return 0; // break here +} + +#--- commands.input + +br s -p "break here" +r + +fr v sp +fr v wp +fr v unique +fr v opt +fr v str +# FIXME: char8_t is not recognized as a type - +# the string has a void pointer/void array for SSO storage. +# fr v u8str +fr v wStr +fr v tuple +fr v map +fr v mapIt +fr v set +fr v mMap +fr v mSet +fr v variant +fr v list +fr v fwList +fr v uMap +fr v uSet +fr v uMMap +fr v uMSet +# FIXME: Static _Block_size is found but doesn't have a value +fr v deque +fr v vec + +quit + +# CHECK: (lldb) fr v sp +# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v wp +# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v unique +# CHECK-NEXT: (std::unique_ptr<int,std::default_delete<int> >) unique = 42 { +# CHECK-NEXT: pointer = 0x{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v opt +# CHECK-NEXT: (std::optional<std::basic_string<char16_t,std::char_traits<char16_t>,std::allocator<char16_t> > >) opt = Has Value=true { +# CHECK-NEXT: Value = u"abc" +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v str +# CHECK-NEXT: (std::basic_string<char,std::char_traits<char>,std::allocator<char> >) str = "str" +# CHECK-NEXT: (lldb) fr v wStr +# CHECK-NEXT: (std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >) wStr = L"wstr" +# CHECK-NEXT: (lldb) fr v tuple +# CHECK-NEXT: (std::tuple<int,bool,float>) tuple = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = false +# CHECK-NEXT: [2] = 4.{{.*}} +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v map +# CHECK-NEXT: (std::map<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) map = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 2, second = 4) +# CHECK-NEXT: [2] = (first = 3, second = 6) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mapIt +# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,int> > > >) mapIt = { +# CHECK-NEXT: first = 3 +# CHECK-NEXT: second = 6 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v set +# CHECK-NEXT: (std::set<int,std::less<int>,std::allocator<int> >) set = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mMap +# CHECK-NEXT: (std::multimap<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) mMap = size=3 { +# CHECK-NEXT: [0] = (first = 1, second = 2) +# CHECK-NEXT: [1] = (first = 1, second = 1) +# CHECK-NEXT: [2] = (first = 2, second = 4) +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v mSet +# CHECK-NEXT: (std::multiset<int,std::less<int>,std::allocator<int> >) mSet = size=3 { +# CHECK-NEXT: [0] = 1 +# CHECK-NEXT: [1] = 2 +# CHECK-NEXT: [2] = 3 +# CHECK-NEXT: } +# CHECK-NEXT: (lldb) fr v variant +# CHECK-NEXT: (std::variant<int,float,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::monostate>) variant = Active Type = std::basic_string<char,std::char_traits<char>,std::allocator<char> > { +# CHECK-NEXT: Value = "... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/150513 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits