[llvm] [CodeView] Expose fallible type accessors in TpiStream (PR #188299)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 30 07:20:35 PDT 2026
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/188299
>From 7f415917c6bd6683515e65f2fc881172ce6bc2c1 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Tue, 24 Mar 2026 18:34:03 +0100
Subject: [PATCH 1/4] [CodeView] Expose fallible type accessors to TpiStream
---
.../DebugInfo/CodeView/LazyRandomTypeCollection.h | 1 +
llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h | 11 +++++++++++
.../CodeView/LazyRandomTypeCollection.cpp | 9 ++++++---
llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp | 14 ++++++++++++++
4 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
index da18339b8662b..7f06e6e97b9e4 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
@@ -72,6 +72,7 @@ class LLVM_ABI LazyRandomTypeCollection : public TypeCollection {
std::optional<CVType> tryGetType(TypeIndex Index);
llvm::Expected<CVType> getTypeOrError(TypeIndex Index);
CVType getType(TypeIndex Index) override;
+
StringRef getTypeName(TypeIndex Index) override;
bool contains(TypeIndex Index) override;
uint32_t size() override;
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
index ec8ac8563b00c..4168eda0ecb7b 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
@@ -67,8 +67,19 @@ class TpiStream {
LLVM_ABI std::vector<codeview::TypeIndex>
findRecordsByName(StringRef Name) const;
+ /// Get a type by its index. \p Index must be a valid type index.
LLVM_ABI codeview::CVType getType(codeview::TypeIndex Index);
+ /// The same as getType() except that the return value is defined
+ /// (empty/invalid) if \p Index doesn't exist. Use codeview::CVType::valid()
+ /// to check the return value.
+ LLVM_ABI codeview::CVType getTypeOrEmpty(codeview::TypeIndex Index);
+
+ LLVM_ABI std::optional<codeview::CVType>
+ tryGetType(codeview::TypeIndex Index);
+
+ LLVM_ABI Expected<codeview::CVType> getTypeOrError(codeview::TypeIndex Index);
+
LLVM_ABI BinarySubstreamRef getTypeRecordsSubstream() const;
LLVM_ABI Error commit();
diff --git a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
index 0b36c5085c086..9dacce90b2e1d 100644
--- a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
+++ b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -87,7 +87,11 @@ CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
assert(!Index.isSimple());
auto EC = ensureTypeExists(Index);
- error(std::move(EC));
+ if (EC) {
+ assert(false && "Invalid type index (use tryGetType or getTypeOrError)");
+ llvm::consumeError(std::move(EC));
+ return {};
+ }
assert(contains(Index));
return Records[Index.toArrayIndex()].Type;
@@ -98,9 +102,8 @@ LazyRandomTypeCollection::getTypeOrError(TypeIndex Index) {
if (Index.isSimple())
return llvm::createStringError("Type index too low (%d)", Index.getIndex());
- if (auto EC = ensureTypeExists(Index)) {
+ if (auto EC = ensureTypeExists(Index))
return EC;
- }
if (!contains(Index))
return llvm::createStringError("Type index too high (%d)",
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
index ff5ae400201c7..62db6265f2a36 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
@@ -222,6 +222,20 @@ codeview::CVType TpiStream::getType(codeview::TypeIndex Index) {
return Types->getType(Index);
}
+codeview::CVType TpiStream::getTypeOrEmpty(codeview::TypeIndex Index) {
+ return Types->tryGetType(Index).value_or({});
+}
+
+std::optional<codeview::CVType>
+TpiStream::tryGetType(codeview::TypeIndex Index) {
+ return Types->tryGetType(Index);
+}
+
+Expected<codeview::CVType>
+TpiStream::getTypeOrError(codeview::TypeIndex Index) {
+ return Types->getTypeOrError(Index);
+}
+
BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
return TypeRecordsSubstream;
}
>From 61d1f7038f5aa7220626b423058c2e8acdb9a0f9 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Tue, 24 Mar 2026 19:32:59 +0100
Subject: [PATCH 2/4] fix: explicit argument to .value_or
---
llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
index 62db6265f2a36..24d2f9e3360ea 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
@@ -223,7 +223,7 @@ codeview::CVType TpiStream::getType(codeview::TypeIndex Index) {
}
codeview::CVType TpiStream::getTypeOrEmpty(codeview::TypeIndex Index) {
- return Types->tryGetType(Index).value_or({});
+ return Types->tryGetType(Index).value_or<CVType>({});
}
std::optional<codeview::CVType>
>From df6e21efd7511415f019691aea285957a3c6f2f9 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 26 Mar 2026 19:37:21 +0100
Subject: [PATCH 3/4] fix: add a test for the accessors
---
llvm/unittests/DebugInfo/PDB/CMakeLists.txt | 1 +
.../unittests/DebugInfo/PDB/TpiStreamTest.cpp | 142 ++++++++++++++++++
2 files changed, 143 insertions(+)
create mode 100644 llvm/unittests/DebugInfo/PDB/TpiStreamTest.cpp
diff --git a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
index b1b9d2d98c944..5cc6f2252fa81 100644
--- a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_unittest_with_input_files(DebugInfoPDBTests
PDBApiTest.cpp
PDBVariantTest.cpp
PublicsStreamTest.cpp
+ TpiStreamTest.cpp
)
target_link_libraries(DebugInfoPDBTests PRIVATE LLVMTestingSupport)
diff --git a/llvm/unittests/DebugInfo/PDB/TpiStreamTest.cpp b/llvm/unittests/DebugInfo/PDB/TpiStreamTest.cpp
new file mode 100644
index 0000000000000..e7339751915bb
--- /dev/null
+++ b/llvm/unittests/DebugInfo/PDB/TpiStreamTest.cpp
@@ -0,0 +1,142 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/Support/Path.h"
+
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::codeview;
+
+extern const char *TestMainArgv0;
+
+// FIXME: This should use ObjectYAML to create a PDB from YAML.
+static std::string getPdbPath() {
+ SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
+ llvm::sys::path::append(InputsDir, "SimpleTest.pdb");
+ return std::string(InputsDir);
+}
+
+// Types:
+// 0x1000 | LF_ARGLIST [size = 8]
+// 0x1001 | LF_PROCEDURE [size = 16]
+static Expected<std::unique_ptr<PDBFile>>
+openSimplePdb(BumpPtrAllocator &Allocator) {
+ std::string PdbPath = getPdbPath();
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+ MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
+ /*RequiresNullTerminator=*/false);
+ EXPECT_TRUE(ErrorOrBuffer);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+
+ auto Stream = std::make_unique<MemoryBufferByteStream>(
+ std::move(Buffer), llvm::endianness::little);
+
+ auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), Allocator);
+ if (Error Err = File->parseFileHeaders())
+ return Err;
+ if (Error Err = File->parseStreamData())
+ return Err;
+ return File;
+}
+
+TEST(TpiStreamTest, getType) {
+ BumpPtrAllocator Allocator;
+ Expected<std::unique_ptr<PDBFile>> FileOrErr = openSimplePdb(Allocator);
+ ASSERT_TRUE(!!FileOrErr);
+ std::unique_ptr<PDBFile> File = std::move(*FileOrErr);
+
+ Expected<TpiStream &> Tpi = File->getPDBTpiStream();
+ ASSERT_TRUE(!!Tpi) << Tpi.takeError();
+
+ ASSERT_EQ(Tpi->getType(TypeIndex(0x1000)).kind(), LF_ARGLIST);
+ ASSERT_EQ(Tpi->getType(TypeIndex(0x1001)).kind(), LF_PROCEDURE);
+}
+
+TEST(TpiStreamTest, getTypeOrEmpty) {
+ BumpPtrAllocator Allocator;
+ Expected<std::unique_ptr<PDBFile>> FileOrErr = openSimplePdb(Allocator);
+ ASSERT_TRUE(!!FileOrErr);
+ std::unique_ptr<PDBFile> File = std::move(*FileOrErr);
+
+ Expected<TpiStream &> Tpi = File->getPDBTpiStream();
+ ASSERT_TRUE(!!Tpi);
+
+ ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0)).valid());
+ ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0xFFF)).valid());
+ ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1002)).valid());
+ ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1003)).valid());
+ ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1234567)).valid());
+
+ ASSERT_EQ(Tpi->getTypeOrEmpty(TypeIndex(0x1000)).kind(), LF_ARGLIST);
+ ASSERT_EQ(Tpi->getTypeOrEmpty(TypeIndex(0x1001)).kind(), LF_PROCEDURE);
+}
+
+TEST(TpiStreamTest, tryGetType) {
+ BumpPtrAllocator Allocator;
+ Expected<std::unique_ptr<PDBFile>> FileOrErr = openSimplePdb(Allocator);
+ ASSERT_TRUE(!!FileOrErr);
+ std::unique_ptr<PDBFile> File = std::move(*FileOrErr);
+
+ Expected<TpiStream &> Tpi = File->getPDBTpiStream();
+ ASSERT_TRUE(!!Tpi);
+
+ ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0)).has_value());
+ ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0xFFF)).has_value());
+ ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1002)).has_value());
+ ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1003)).has_value());
+ ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1234567)).has_value());
+
+ std::optional<CVType> T0 = Tpi->tryGetType(TypeIndex(0x1000));
+ std::optional<CVType> T1 = Tpi->tryGetType(TypeIndex(0x1001));
+ ASSERT_TRUE(T0.has_value());
+ ASSERT_EQ(T0->kind(), LF_ARGLIST);
+ ASSERT_TRUE(T1.has_value());
+ ASSERT_EQ(T1->kind(), LF_PROCEDURE);
+}
+
+TEST(TpiStreamTest, getTypeOrErr) {
+ BumpPtrAllocator Allocator;
+ Expected<std::unique_ptr<PDBFile>> FileOrErr = openSimplePdb(Allocator);
+ ASSERT_TRUE(!!FileOrErr);
+ std::unique_ptr<PDBFile> File = std::move(*FileOrErr);
+
+ Expected<TpiStream &> Tpi = File->getPDBTpiStream();
+ ASSERT_TRUE(!!Tpi);
+
+ Expected<CVType> E0 = Tpi->getTypeOrError(TypeIndex(0));
+ ASSERT_FALSE(E0);
+ ASSERT_EQ(toString(E0.takeError()), "Type index too low (0)");
+ Expected<CVType> E1 = Tpi->getTypeOrError(TypeIndex(0xFFF));
+ ASSERT_FALSE(E1);
+ ASSERT_EQ(toString(E1.takeError()), "Type index too low (4095)");
+ Expected<CVType> E2 = Tpi->getTypeOrError(TypeIndex(0x1002));
+ ASSERT_FALSE(E2);
+ ASSERT_EQ(toString(E2.takeError()), "Type index too high (4098)");
+ Expected<CVType> E3 = Tpi->getTypeOrError(TypeIndex(0x1003));
+ ASSERT_FALSE(E3);
+ ASSERT_EQ(toString(E3.takeError()), "Invalid type index");
+ Expected<CVType> E4 = Tpi->getTypeOrError(TypeIndex(0x123456));
+ ASSERT_FALSE(E4);
+ ASSERT_EQ(toString(E4.takeError()), "Invalid type index");
+
+ Expected<CVType> T0 = Tpi->getTypeOrError(TypeIndex(0x1000));
+ ASSERT_TRUE(!!T0);
+ ASSERT_EQ(T0->kind(), LF_ARGLIST);
+
+ Expected<CVType> T1 = Tpi->getTypeOrError(TypeIndex(0x1001));
+ ASSERT_TRUE(!!T1);
+ ASSERT_EQ(T1->kind(), LF_PROCEDURE);
+}
>From 1e8f8952e43a86ee6b28d71148695ef2e16d4589 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Mon, 30 Mar 2026 16:20:07 +0200
Subject: [PATCH 4/4] fix: document
---
llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
index 4168eda0ecb7b..deaa313c61329 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h
@@ -68,6 +68,7 @@ class TpiStream {
findRecordsByName(StringRef Name) const;
/// Get a type by its index. \p Index must be a valid type index.
+ /// Otherwise, this method asserts in Debug mode.
LLVM_ABI codeview::CVType getType(codeview::TypeIndex Index);
/// The same as getType() except that the return value is defined
@@ -75,9 +76,11 @@ class TpiStream {
/// to check the return value.
LLVM_ABI codeview::CVType getTypeOrEmpty(codeview::TypeIndex Index);
+ /// Get the type at \p Index if it exists or \c std::nullopt otherwise.
LLVM_ABI std::optional<codeview::CVType>
tryGetType(codeview::TypeIndex Index);
+ /// Get the type at \p Index if it exists or an error about the failure.
LLVM_ABI Expected<codeview::CVType> getTypeOrError(codeview::TypeIndex Index);
LLVM_ABI BinarySubstreamRef getTypeRecordsSubstream() const;
More information about the llvm-commits
mailing list