Skip to content

Conversation

@Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Jul 21, 2025

Adds synthetic children and a summary provider for std::atomic on MSVC's STL. This currently only supports DWARF because it relies on the template argument. Once there are PDB tests, this will probably use the return type of some method like value() because template types aren't available there.

Towards #24834.

@llvmbot
Copy link
Member

llvmbot commented Jul 21, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

Adds synthetic children and a summary provider for std::atomic on MSVC's STL. This currently only supports DWARF because it relies on the template argument. Once there are PDB tests, this will probably use the return type of some method like value() because template types aren't available there.

Towards #24834.


Full diff: https://github.com/llvm/llvm-project/pull/149801.diff

5 Files Affected:

  • (modified) lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt (+1)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+14)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+7)
  • (added) lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp (+102)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py (+6)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 5905d9b9a6d03..ce4e2d6f0f5af 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -34,6 +34,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   LibStdcppTuple.cpp
   LibStdcppUniquePointer.cpp
   MsvcStl.cpp
+  MsvcStlAtomic.cpp
   MsvcStlSmartPointer.cpp
   MsvcStlTuple.cpp
   MsvcStlVector.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index a0d5e1dfe3227..16b4d55d2db73 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1763,6 +1763,9 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       .SetDontShowValue(false)
       .SetShowMembersOneLiner(false)
       .SetHideItemNames(false);
+  SyntheticChildren::Flags stl_synth_flags;
+  stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
+      false);
 
   using StringElementType = StringPrinter::StringElementType;
 
@@ -1784,6 +1787,17 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
           stl_summary_flags,
           MsvcStlStringSummaryProvider<StringElementType::UTF32>,
           "MSVC STL std::u32string summary provider"));
+
+  stl_summary_flags.SetDontShowChildren(false);
+  stl_summary_flags.SetSkipPointers(false);
+
+  AddCXXSynthetic(cpp_category_sp, MsvcStlAtomicSyntheticFrontEndCreator,
+                  "MSVC STL std::atomic synthetic children",
+                  "^std::atomic<.+>$", stl_synth_flags, true);
+
+  AddCXXSummary(cpp_category_sp, MsvcStlAtomicSummaryProvider,
+                "MSVC STL std::atomic summary provider", "^std::atomic<.+>$",
+                stl_summary_flags, true);
 }
 
 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
index c08eecfdecee7..3ac12c17a96e1 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
@@ -71,6 +71,13 @@ SyntheticChildrenFrontEnd *
 MsvcStlOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                         lldb::ValueObjectSP valobj_sp);
 
+// MSVC STL std::atomic<>
+bool MsvcStlAtomicSummaryProvider(ValueObject &valobj, Stream &stream,
+                                  const TypeSummaryOptions &options);
+SyntheticChildrenFrontEnd *
+MsvcStlAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *,
+                                      lldb::ValueObjectSP valobj_sp);
+
 } // namespace formatters
 } // namespace lldb_private
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
new file mode 100644
index 0000000000000..3ec324577ac76
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
@@ -0,0 +1,102 @@
+//===-- MsvcStlAtomic.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/DataFormatters/TypeSynthetic.h"
+
+using namespace lldb;
+
+namespace lldb_private {
+namespace formatters {
+
+class MsvcStlAtomicSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  MsvcStlAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+  llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+  lldb::ChildCacheState Update() override;
+
+  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
+
+private:
+  ValueObject *m_storage = nullptr;
+  CompilerType m_element_type;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::
+    MsvcStlAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+    : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+  if (valobj_sp)
+    Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+    MsvcStlAtomicSyntheticFrontEnd::CalculateNumChildren() {
+  return m_storage ? 1 : 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::GetChildAtIndex(
+    uint32_t idx) {
+  if (idx == 0)
+    return m_storage->Cast(m_element_type)->Clone(ConstString("Value"));
+  return nullptr;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::Update() {
+  m_storage = nullptr;
+  m_element_type.Clear();
+
+  ValueObjectSP storage_sp = m_backend.GetChildMemberWithName("_Storage");
+  if (!storage_sp)
+    return lldb::ChildCacheState::eRefetch;
+
+  m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
+  if (!m_element_type)
+    return lldb::ChildCacheState::eRefetch;
+
+  m_storage = storage_sp.get();
+  return lldb::ChildCacheState::eRefetch;
+}
+
+llvm::Expected<size_t> lldb_private::formatters::
+    MsvcStlAtomicSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
+  if (name == "Value")
+    return 0;
+  return llvm::createStringError("Type has no child named '%s'",
+                                 name.AsCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::MsvcStlAtomicSyntheticFrontEndCreator(
+    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+  return new MsvcStlAtomicSyntheticFrontEnd(valobj_sp);
+}
+
+bool lldb_private::formatters::MsvcStlAtomicSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+  auto synth_sp = valobj.GetSyntheticValue();
+  if (!synth_sp)
+    return false;
+
+  auto value_sp = synth_sp->GetChildAtIndex(0);
+  std::string summary;
+  if (value_sp->GetSummaryAsCString(summary, options) && !summary.empty()) {
+    stream << summary;
+    return true;
+  }
+  return false;
+}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
index 8186e1d66985b..bdf12ca3b86db 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
@@ -67,3 +67,9 @@ def do_test(self):
     def test_libcxx(self):
         self.build(dictionary={"USE_LIBCPP": 1})
         self.do_test()
+
+    @add_test_categories(["msvcstl"])
+    def test_msvcstl(self):
+        # No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
+        self.build()
+        self.do_test()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
stl_summary_flags.SetSkipPointers(false);

We already set this above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you don't set this? I think we probably do want this to be true? Would that make std::atomic look like:

(std::atomic<int>) val = 5

?

(i.e., just not print the synthetic child?)

I know that's not what libc++/libstdc++ does, but we probably should?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be done separately since that's what libc++ and libstdc++ already do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would that make std::atomic look like:

(std::atomic<int>) val = 5

?

Yes. I don't think that's always desired. Atomics can store structs as well (not sure why) and users might want to inspect these. This is also done in the tests here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I wondered if for summaries that can't be formatted without children this would then fall back to showing the children. But yea maybe not. Either way, not something you have to deal with here

@Nerixyz Nerixyz force-pushed the feat/lldb-atomic-fmt branch from 679f4fa to 6d27113 Compare July 22, 2025 10:26
@Michael137 Michael137 merged commit f78c4ce into llvm:main Jul 22, 2025
9 checks passed
@Nerixyz Nerixyz deleted the feat/lldb-atomic-fmt branch July 22, 2025 12:34
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jul 28, 2025
Adds synthetic children and a summary provider for `std::atomic` on
MSVC's STL. This currently only supports DWARF because it relies on the
template argument. Once there are PDB tests, this will probably use the
return type of some method like `value()` because template types aren't
available there.

Towards llvm#24834.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants