[LLDB] Add type summaries for MSVC STL strings (#143177)

This PR adds type summaries for
`std::{string,wstring,u8string,u16string,u32string}` from the MSVC STL.

See https://github.com/llvm/llvm-project/issues/24834 for the MSVC STL
issue.

The following changes were made:

- `dotest.py` now detects if the MSVC STL is available. It does so by
looking at the target triple, which is an additional argument passed
from Lit. It specifically checks for `windows-msvc` to not match on
`windows-gnu` (i.e. MinGW/Cygwin).
- (The main part): Added support for summarizing `std::(w)string` from
MSVC's STL. Because the type names from the libstdc++ (pre C++ 11)
string types are the same as on MSVC's STL, `CXXCompositeSummaryFormat`
is used with two entries, one for MSVC's STL and one for libstdc++.
With MSVC's STL, `std::u{8,16,32}string` is also handled. These aren't
handled for libstdc++, so I put them in `LoadMsvcStlFormatters`.
This commit is contained in:
nerix
2025-07-08 10:55:18 +02:00
committed by GitHub
parent 29487759e3
commit 45689b26eb
15 changed files with 556 additions and 35 deletions

View File

@@ -831,6 +831,46 @@ def checkLibstdcxxSupport():
configuration.skip_categories.append("libstdcxx")
def canRunMsvcStlTests():
from lldbsuite.test import lldbplatformutil
platform = lldbplatformutil.getPlatform()
if platform != "windows":
return False, f"Don't know how to build with MSVC's STL on {platform}"
with tempfile.NamedTemporaryFile() as f:
cmd = [configuration.compiler, "-xc++", "-o", f.name, "-E", "-"]
p = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)
_, stderr = p.communicate(
"""
#include <yvals_core.h>
#ifndef _MSVC_STL_VERSION
#error _MSVC_STL_VERSION not defined
#endif
"""
)
if not p.returncode:
return True, "Compiling with MSVC STL"
return (False, f"Not compiling with MSVC STL: {stderr}")
def checkMsvcStlSupport():
result, reason = canRunMsvcStlTests()
if result:
return # msvcstl supported
if "msvcstl" in configuration.categories_list:
return # msvcstl category explicitly requested, let it run.
if configuration.verbose:
print(f"msvcstl tests will not be run because: {reason}")
configuration.skip_categories.append("msvcstl")
def canRunWatchpointTests():
from lldbsuite.test import lldbplatformutil
@@ -1044,6 +1084,7 @@ def run_suite():
checkLibcxxSupport()
checkLibstdcxxSupport()
checkMsvcStlSupport()
checkWatchpointSupport()
checkDebugInfoSupport()
checkDebugServerSupport()

View File

@@ -33,6 +33,7 @@ all_categories = {
"lldb-server": "Tests related to lldb-server",
"lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
"llgs": "Tests for the gdb-server functionality of lldb-server",
"msvcstl": "Test for MSVC STL data formatters",
"pexpect": "Tests requiring the pexpect library to be available",
"objc": "Tests related to the Objective-C programming language support",
"pyapi": "Tests related to the Python API",

View File

@@ -32,6 +32,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibStdcpp.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
MsvcStl.cpp
MSVCUndecoratedNameParser.cpp
LINK_COMPONENTS

View File

@@ -46,6 +46,7 @@
#include "LibCxxVariant.h"
#include "LibStdcpp.h"
#include "MSVCUndecoratedNameParser.h"
#include "MsvcStl.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb;
@@ -1331,6 +1332,37 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"${var.__y_} ${var.__m_} ${var.__wdl_}")));
}
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()),
summary_sp);
// 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}> >",
char_ty)
.str()),
summary_sp);
// 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}> >",
char_ty)
.str()),
summary_sp);
}
static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
return;
@@ -1347,18 +1379,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat(
stl_summary_flags, LibStdcppStringSummaryProvider,
"libstdc++ std::(w)string summary provider"));
cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary("std::basic_string<char>",
eFormatterMatchExact, string_summary_sp);
cpp_category_sp->AddTypeSummary(
"std::basic_string<char,std::char_traits<char>,std::allocator<char> >",
eFormatterMatchExact, string_summary_sp);
cpp_category_sp->AddTypeSummary(
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
eFormatterMatchExact, string_summary_sp);
cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
@@ -1370,23 +1390,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::allocator<unsigned char> >",
eFormatterMatchExact, string_summary_sp);
// making sure we force-pick the summary for printing wstring (_M_p is a
// wchar_t*)
lldb::TypeSummaryImplSP std_wstring_summary_sp(
new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact,
std_wstring_summary_sp);
cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t>",
eFormatterMatchExact, std_wstring_summary_sp);
cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t,std::char_traits<"
"wchar_t>,std::allocator<wchar_t> >",
eFormatterMatchExact, std_wstring_summary_sp);
cpp_category_sp->AddTypeSummary(
"std::basic_string<wchar_t, std::char_traits<wchar_t>, "
"std::allocator<wchar_t> >",
eFormatterMatchExact, std_wstring_summary_sp);
cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
@@ -1595,6 +1598,81 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
}
/// Load formatters that are formatting types from more than one STL
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
return;
TypeSummaryImpl::Flags stl_summary_flags;
stl_summary_flags.SetCascades(true)
.SetSkipPointers(false)
.SetSkipReferences(false)
.SetDontShowChildren(true)
.SetDontShowValue(false)
.SetShowMembersOneLiner(false)
.SetHideItemNames(false);
using StringElementType = StringPrinter::StringElementType;
RegisterStdStringSummaryProvider(
cpp_category_sp, "std::string", "char",
std::make_shared<CXXFunctionSummaryFormat>(
stl_summary_flags,
[](ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options) {
if (IsMsvcStlStringType(valobj))
return MsvcStlStringSummaryProvider<StringElementType::ASCII>(
valobj, stream, options);
return LibStdcppStringSummaryProvider(valobj, stream, options);
},
"MSVC STL/libstdc++ std::string summary provider"));
RegisterStdStringSummaryProvider(
cpp_category_sp, "std::wstring", "wchar_t",
std::make_shared<CXXFunctionSummaryFormat>(
stl_summary_flags,
[](ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options) {
if (IsMsvcStlStringType(valobj))
return MsvcStlWStringSummaryProvider(valobj, stream, options);
return LibStdcppStringSummaryProvider(valobj, stream, options);
},
"MSVC STL/libstdc++ std::wstring summary provider"));
}
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
return;
TypeSummaryImpl::Flags stl_summary_flags;
stl_summary_flags.SetCascades(true)
.SetSkipPointers(false)
.SetSkipReferences(false)
.SetDontShowChildren(true)
.SetDontShowValue(false)
.SetShowMembersOneLiner(false)
.SetHideItemNames(false);
using StringElementType = StringPrinter::StringElementType;
RegisterStdStringSummaryProvider(
cpp_category_sp, "std::u8string", "char8_t",
std::make_shared<CXXFunctionSummaryFormat>(
stl_summary_flags,
MsvcStlStringSummaryProvider<StringElementType::UTF8>,
"MSVC STL std::u8string summary provider"));
RegisterStdStringSummaryProvider(
cpp_category_sp, "std::u16string", "char16_t",
std::make_shared<CXXFunctionSummaryFormat>(
stl_summary_flags,
MsvcStlStringSummaryProvider<StringElementType::UTF16>,
"MSVC STL std::u16string summary provider"));
RegisterStdStringSummaryProvider(
cpp_category_sp, "std::u32string", "char32_t",
std::make_shared<CXXFunctionSummaryFormat>(
stl_summary_flags,
MsvcStlStringSummaryProvider<StringElementType::UTF32>,
"MSVC STL std::u32string summary provider"));
}
static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
return;
@@ -1709,6 +1787,8 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
// LLDB prioritizes the last loaded matching formatter.
LoadLibCxxFormatters(g_category);
LoadLibStdcppFormatters(g_category);
LoadMsvcStlFormatters(g_category);
LoadCommonStlFormatters(g_category);
LoadSystemFormatters(g_category);
}
});

View File

@@ -0,0 +1,155 @@
//===-- MsvcStl.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "MsvcStl.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "lldb/ValueObject/ValueObject.h"
#include "Plugins/Language/CPlusPlus/CxxStringTypes.h"
#include "lldb/lldb-forward.h"
#include <optional>
#include <tuple>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
using StringElementType = StringPrinter::StringElementType;
template <StringElementType element_type>
static constexpr uint64_t StringElementByteSize() {
switch (element_type) {
case StringElementType::ASCII:
case StringElementType::UTF8:
return 1;
case StringElementType::UTF16:
return 2;
case StringElementType::UTF32:
return 3;
}
return 0;
}
static ValueObjectSP ExtractMsvcStlStringData(ValueObject &valobj) {
return valobj.GetChildAtNamePath({"_Mypair", "_Myval2"});
}
/// Determine the size in bytes of \p valobj (a MSVC STL std::string object) and
/// extract its data payload. Return the size + payload pair.
static std::optional<std::pair<uint64_t, ValueObjectSP>>
ExtractMsvcStlStringInfo(ValueObject &valobj, uint64_t element_size) {
ValueObjectSP valobj_pair_sp = ExtractMsvcStlStringData(valobj);
if (!valobj_pair_sp || !valobj_pair_sp->GetError().Success())
return {};
ValueObjectSP size_sp = valobj_pair_sp->GetChildMemberWithName("_Mysize");
ValueObjectSP capacity_sp = valobj_pair_sp->GetChildMemberWithName("_Myres");
ValueObjectSP bx_sp = valobj_pair_sp->GetChildMemberWithName("_Bx");
if (!size_sp || !capacity_sp || !bx_sp)
return {};
bool success = false;
uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
if (!success)
return {};
uint64_t capacity = capacity_sp->GetValueAsUnsigned(0, &success);
if (!success)
return {};
size_t bufSize = std::max<size_t>(16 / element_size, 1);
bool isShortString = capacity < bufSize;
if (isShortString) {
ValueObjectSP buf_sp = bx_sp->GetChildMemberWithName("_Buf");
if (buf_sp)
return std::make_pair(size, buf_sp);
return {};
}
ValueObjectSP ptr_sp = bx_sp->GetChildMemberWithName("_Ptr");
if (ptr_sp)
return std::make_pair(size, ptr_sp);
return {};
}
template <StringPrinter::StringElementType element_type>
static bool
MsvcStlStringSummaryProviderImpl(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options,
std::string prefix_token) {
auto string_info =
ExtractMsvcStlStringInfo(valobj, StringElementByteSize<element_type>());
if (!string_info)
return false;
auto [size, location_sp] = *string_info;
return StringBufferSummaryProvider<element_type>(
stream, summary_options, location_sp, size, prefix_token);
}
template <StringPrinter::StringElementType element_type>
static bool formatStringImpl(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options,
std::string prefix_token) {
StreamString scratch_stream;
const bool success = MsvcStlStringSummaryProviderImpl<element_type>(
valobj, scratch_stream, summary_options, prefix_token);
if (success)
stream << scratch_stream.GetData();
else
stream << "Summary Unavailable";
return true;
}
bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) {
std::vector<uint32_t> indexes;
return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true,
indexes) > 0;
}
bool lldb_private::formatters::MsvcStlWStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
return formatStringImpl<StringElementType::UTF16>(valobj, stream,
summary_options, "L");
}
template <>
bool lldb_private::formatters::MsvcStlStringSummaryProvider<
StringElementType::ASCII>(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
return MsvcStlStringSummaryProviderImpl<StringElementType::ASCII>(
valobj, stream, summary_options, "");
}
template <>
bool lldb_private::formatters::MsvcStlStringSummaryProvider<
StringElementType::UTF8>(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
return MsvcStlStringSummaryProviderImpl<StringElementType::UTF8>(
valobj, stream, summary_options, "u8");
}
template <>
bool lldb_private::formatters::MsvcStlStringSummaryProvider<
StringElementType::UTF16>(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
return MsvcStlStringSummaryProviderImpl<StringElementType::UTF16>(
valobj, stream, summary_options, "u");
}
template <>
bool lldb_private::formatters::MsvcStlStringSummaryProvider<
StringElementType::UTF32>(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>(
valobj, stream, summary_options, "U");
}

View File

@@ -0,0 +1,35 @@
//===-- MsvcStl.h -----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H
#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Utility/Stream.h"
#include "lldb/ValueObject/ValueObject.h"
namespace lldb_private {
namespace formatters {
bool IsMsvcStlStringType(ValueObject &valobj);
template <StringPrinter::StringElementType element_type>
bool MsvcStlStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions
&summary_options); // VC 2015+ std::string,u8string,u16string,u32string
bool MsvcStlWStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options); // VC 2015+ std::wstring
} // namespace formatters
} // namespace lldb_private
#endif

View File

@@ -10,10 +10,6 @@ from lldbsuite.test import lldbutil
class SkipSummaryDataFormatterTestCase(TestBase):
@expectedFailureAll(
oslist=["windows"],
bugnumber="llvm.org/pr24462, Data formatters have problems on Windows",
)
def test_with_run_command(self):
"""Test data formatter commands."""
self.build()

View File

@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp
include Makefile.rules

View File

@@ -0,0 +1,120 @@
# coding=utf8
"""
Test std::*string summaries with MSVC's STL.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class MsvcStlStringDataFormatterTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@add_test_categories(["msvcstl"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
main_spec = lldb.SBFileSpec("main.cpp")
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", main_spec
)
frame = thread.frames[0]
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd("type format clear", check=False)
self.runCmd("type summary clear", check=False)
self.runCmd("type filter clear", check=False)
self.runCmd("type synth clear", check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
self.expect(
"frame variable",
substrs=[
'(std::wstring) wempty = L""',
'(std::wstring) s = L"hello world! מזל טוב!"',
'(std::wstring) S = L"!!!!"',
"(const wchar_t *) mazeltov = 0x",
'L"מזל טוב"',
'(std::string) empty = ""',
'(std::string) q = "hello world"',
'(std::string) Q = "quite a long std::strin with lots of info inside it"',
'(std::string) overwritten_zero = "abc"',
'(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
'(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
'(std::u16string) u16_string = u"ß水氶"',
'(std::u16string) u16_empty = u""',
'(std::u32string) u32_string = U"🍄🍅🍆🍌"',
'(std::u32string) u32_empty = U""',
"(std::string *) null_str = nullptr",
],
)
thread.StepOver()
TheVeryLongOne = frame.FindVariable("TheVeryLongOne")
summaryOptions = lldb.SBTypeSummaryOptions()
summaryOptions.SetCapping(lldb.eTypeSummaryUncapped)
uncappedSummaryStream = lldb.SBStream()
TheVeryLongOne.GetSummary(uncappedSummaryStream, summaryOptions)
uncappedSummary = uncappedSummaryStream.GetData()
self.assertGreater(
uncappedSummary.find("someText"),
0,
"uncappedSummary does not include the full string",
)
summaryOptions.SetCapping(lldb.eTypeSummaryCapped)
cappedSummaryStream = lldb.SBStream()
TheVeryLongOne.GetSummary(cappedSummaryStream, summaryOptions)
cappedSummary = cappedSummaryStream.GetData()
self.assertLessEqual(
cappedSummary.find("someText"), 0, "cappedSummary includes the full string"
)
self.expect_expr(
"s", result_type="std::wstring", result_summary='L"hello world! מזל טוב!"'
)
self.expect_expr("q", result_type="std::string", result_summary='"hello world"')
self.expect_expr(
"Q",
result_type="std::string",
result_summary='"quite a long std::strin with lots of info inside it"',
)
self.expect(
"frame variable",
substrs=[
'(std::wstring) S = L"!!!!!"',
"(const wchar_t *) mazeltov = 0x",
'L"מזל טוב"',
'(std::string) q = "hello world"',
'(std::string) Q = "quite a long std::strin with lots of info inside it"',
'(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
'(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
'(std::u16string) u16_string = u"ß水氶"',
'(std::u32string) u32_string = U"🍄🍅🍆🍌"',
'(std::u32string) u32_empty = U""',
"(std::string *) null_str = nullptr",
],
)
# Finally, make sure that if the string is not readable, we give an error:
bkpt_2 = target.BreakpointCreateBySourceRegex(
"Break here to look at bad string", main_spec
)
self.assertEqual(bkpt_2.GetNumLocations(), 1, "Got one location")
threads = lldbutil.continue_to_breakpoint(process, bkpt_2)
self.assertEqual(len(threads), 1, "Stopped at second breakpoint")
frame = threads[0].frames[0]
var = frame.FindVariable("in_str")
self.assertTrue(var.GetError().Success(), "Made variable")
self.assertIsNone(var.GetSummary())

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
CXX_SOURCES := main.cpp
CXXFLAGS_EXTRAS := -std=c++20 -O0
include Makefile.rules

View File

@@ -0,0 +1,33 @@
# coding=utf8
"""
Test std::u8string summary with MSVC's STL.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class MsvcStlU8StringDataFormatterTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@add_test_categories(["msvcstl"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
)
self.expect(
"frame variable",
substrs=[
'(std::u8string) u8_string_small = u8"🍄"',
'(std::u8string) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
'(std::u8string) u8_empty = u8""',
'(std::u8string) u8_text = u8"ABC"',
],
)

View File

@@ -0,0 +1,14 @@
#include <string>
#ifndef _MSVC_STL_VERSION
// this is more of a sanity check that the categories work as expected
#error Not using MSVC STL
#endif
int main() {
std::u8string u8_string_small(u8"🍄");
std::u8string u8_string(u8"❤️👍📄📁😃🧑‍🌾");
std::u8string u8_empty(u8"");
std::u8string u8_text(u8"ABC");
u8_text.assign(u8"ABCd"); // Set break point at this line.
}

View File

@@ -4,5 +4,4 @@ from lldbsuite.test import decorators
lldbinline.MakeInlineTest(
__file__,
globals(),
[decorators.expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772")],
)

View File

@@ -10,7 +10,6 @@ from lldbsuite.test import lldbutil
class SBValuePersistTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772")
def test(self):
"""Test SBValue::Persist"""
self.build()