[llvm] [CodeView] Support LF_CLASS2 and friends (PR #228761)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 3 12:52:21 PDT 2026
https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/228761
None
>From ee094eb006d3dc3f115bd18b59736b45f377b3be Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sat, 3 Oct 2026 21:48:04 +0200
Subject: [PATCH] [CodeView] Support LF_CLASS2 and friends
---
.../DebugInfo/CodeView/CodeViewRecordIO.h | 12 ++
.../llvm/DebugInfo/CodeView/CodeViewTypes.def | 12 +-
.../llvm/DebugInfo/CodeView/TypeRecord.h | 24 ++-
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 18 +-
.../DebugInfo/CodeView/TypeIndexDiscovery.cpp | 4 +
.../DebugInfo/CodeView/TypeRecordHelpers.cpp | 8 +
.../DebugInfo/CodeView/TypeRecordMapping.cpp | 87 ++++++--
.../LogicalView/Readers/LVCodeViewVisitor.cpp | 8 +-
.../DebugInfo/PDB/Native/NativeExeSymbol.cpp | 13 +-
.../DebugInfo/PDB/Native/NativeTypeUDT.cpp | 4 +
llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp | 4 +
llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp | 8 +
llvm/test/DebugInfo/COFF/tag-types2.ll | 198 ++++++++++++++++++
llvm/test/DebugInfo/PDB/DIA/tag-types2.test | 71 +++++++
.../test/DebugInfo/PDB/Inputs/tag-types2.yaml | 146 +++++++++++++
.../test/DebugInfo/PDB/Native/tag-types2.test | 73 +++++++
llvm/test/tools/llvm-pdbutil/tag-types2.yaml | 148 +++++++++++++
.../llvm-pdbutil/TypeReferenceTracker.cpp | 4 +
.../CodeView/TypeIndexDiscoveryTest.cpp | 16 ++
19 files changed, 817 insertions(+), 41 deletions(-)
create mode 100644 llvm/test/DebugInfo/COFF/tag-types2.ll
create mode 100644 llvm/test/DebugInfo/PDB/DIA/tag-types2.test
create mode 100644 llvm/test/DebugInfo/PDB/Inputs/tag-types2.yaml
create mode 100644 llvm/test/DebugInfo/PDB/Native/tag-types2.test
create mode 100644 llvm/test/tools/llvm-pdbutil/tag-types2.yaml
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h b/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
index 668428e487e11..90033371e11e6 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
@@ -112,6 +112,18 @@ class CodeViewRecordIO {
return Reader->readInteger(Value);
}
+ template <typename Trunc, typename T>
+ Error mapTruncInteger(T &Value, const Twine &Comment = "") {
+ static_assert(sizeof(Trunc) <= sizeof(T));
+
+ Trunc Truncated = static_cast<Trunc>(Value);
+ auto EC = mapInteger(Truncated, Comment);
+ if (!EC && isReading())
+ Value = Truncated;
+
+ return EC;
+ }
+
template <typename T> Error mapEnum(T &Value, const Twine &Comment = "") {
if (!isStreaming() && sizeof(Value) > maxFieldLength())
return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
index 86a74292dbb11..9830d8c797230 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
@@ -50,6 +50,13 @@ TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class)
TYPE_RECORD(LF_UNION, 0x1506, Union)
TYPE_RECORD(LF_ENUM, 0x1507, Enum)
+
+TYPE_RECORD_ALIAS(LF_CLASS2, 0x1608, Class2, Class)
+TYPE_RECORD_ALIAS(LF_STRUCTURE2, 0x1609, Struct2, Class)
+TYPE_RECORD_ALIAS(LF_INTERFACE2, 0x160b, Interface2, Class)
+
+TYPE_RECORD_ALIAS(LF_UNION2, 0x160a, Union2, Union)
+
TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
@@ -83,11 +90,6 @@ TYPE_RECORD(LF_STRING_ID, 0x1605, StringId)
TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine)
TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine)
-CV_TYPE(LF_CLASS2, 0x1608)
-CV_TYPE(LF_STRUCTURE2, 0x1609)
-CV_TYPE(LF_UNION2, 0x160a)
-CV_TYPE(LF_INTERFACE2, 0x160b)
-
TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList)
TYPE_RECORD(LF_PRECOMP, 0x1509, Precomp)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
index 5a84fac5f5903..4f12fc5938d12 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -417,7 +417,7 @@ class TagRecord : public TypeRecord {
protected:
TagRecord() = default;
explicit TagRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
- TagRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
+ TagRecord(TypeRecordKind Kind, uint64_t MemberCount, ClassOptions Options,
TypeIndex FieldList, StringRef Name, StringRef UniqueName)
: TypeRecord(Kind), MemberCount(MemberCount), Options(Options),
FieldList(FieldList), Name(Name), UniqueName(UniqueName) {}
@@ -448,25 +448,29 @@ class TagRecord : public TypeRecord {
return (Options & ClassOptions::Scoped) != ClassOptions::None;
}
- uint16_t getMemberCount() const { return MemberCount; }
+ uint64_t getMemberCount() const { return MemberCount; }
ClassOptions getOptions() const { return Options; }
TypeIndex getFieldList() const { return FieldList; }
StringRef getName() const { return Name; }
StringRef getUniqueName() const { return UniqueName; }
- uint16_t MemberCount = 0;
+ /// Number of members in the associated field list.
+ ///
+ /// Note that the full 64 bit range can only be used by the *2 records.
+ /// The others use a 16 bit value for this.
+ uint64_t MemberCount = 0;
ClassOptions Options = ClassOptions::None;
TypeIndex FieldList;
StringRef Name;
StringRef UniqueName;
};
-// LF_CLASS, LF_STRUCTURE, LF_INTERFACE
+// LF_CLASS, LF_STRUCTURE, LF_INTERFACE, LF_CLASS2, LF_STRUCTURE2, LF_INTERFACE2
class ClassRecord : public TagRecord {
public:
ClassRecord() = default;
explicit ClassRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
- ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
+ ClassRecord(TypeRecordKind Kind, uint64_t MemberCount, ClassOptions Options,
TypeIndex FieldList, TypeIndex DerivationList,
TypeIndex VTableShape, uint64_t Size, StringRef Name,
StringRef UniqueName)
@@ -494,14 +498,18 @@ class ClassRecord : public TagRecord {
uint64_t Size = 0;
};
-// LF_UNION
+// LF_UNION, LF_UNION2
struct UnionRecord : public TagRecord {
UnionRecord() = default;
explicit UnionRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
UnionRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList,
uint64_t Size, StringRef Name, StringRef UniqueName)
- : TagRecord(TypeRecordKind::Union, MemberCount, Options, FieldList, Name,
- UniqueName),
+ : UnionRecord(TypeRecordKind::Union, MemberCount, Options, FieldList,
+ Size, Name, UniqueName) {}
+ UnionRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
+ TypeIndex FieldList, uint64_t Size, StringRef Name,
+ StringRef UniqueName)
+ : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName),
Size(Size) {}
HfaKind getHfa() const {
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 84ea5e349f01d..a417151610000 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -74,6 +74,12 @@
using namespace llvm;
using namespace llvm::codeview;
+static cl::opt<bool> UseTagRecord2(
+ "use-codeview-tagrecord2", cl::Hidden,
+ cl::desc(
+ "Use the *2 versions for tag records in CodeView (LF_CLASS2, etc.)"),
+ cl::init(false));
+
namespace {
class CVMCAdapter : public CodeViewRecordStreamer {
public:
@@ -2205,9 +2211,9 @@ static MethodKind translateMethodKindFlags(const DISubprogram *SP,
static TypeRecordKind getRecordKind(const DICompositeType *Ty) {
switch (Ty->getTag()) {
case dwarf::DW_TAG_class_type:
- return TypeRecordKind::Class;
+ return UseTagRecord2 ? TypeRecordKind::Class2 : TypeRecordKind::Class;
case dwarf::DW_TAG_structure_type:
- return TypeRecordKind::Struct;
+ return UseTagRecord2 ? TypeRecordKind::Struct2 : TypeRecordKind::Struct;
default:
llvm_unreachable("unexpected tag");
}
@@ -2511,7 +2517,9 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
- UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
+ TypeRecordKind Kind =
+ UseTagRecord2 ? TypeRecordKind::Union2 : TypeRecordKind::Union;
+ UnionRecord UR(Kind, 0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
TypeIndex FwdDeclTI = TypeTable.writeLeafType(UR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
@@ -2532,7 +2540,9 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
std::string FullName = getFullyQualifiedName(Ty);
- UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
+ TypeRecordKind Kind =
+ UseTagRecord2 ? TypeRecordKind::Union2 : TypeRecordKind::Union;
+ UnionRecord UR(Kind, FieldCount, CO, FieldTI, SizeInBytes, FullName,
Ty->getIdentifier());
TypeIndex UnionTI = TypeTable.writeLeafType(UR);
diff --git a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index 745c53a8de32a..e1f8085ff21c3 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -327,9 +327,13 @@ static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
case TypeLeafKind::LF_CLASS:
case TypeLeafKind::LF_STRUCTURE:
case TypeLeafKind::LF_INTERFACE:
+ case TypeLeafKind::LF_CLASS2:
+ case TypeLeafKind::LF_STRUCTURE2:
+ case TypeLeafKind::LF_INTERFACE2:
Refs.push_back({TiRefKind::TypeRef, 4, 3});
break;
case TypeLeafKind::LF_UNION:
+ case TypeLeafKind::LF_UNION2:
Refs.push_back({TiRefKind::TypeRef, 4, 1});
break;
case TypeLeafKind::LF_ENUM:
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
index 35acfcf18d175..dee90e18a5e58 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
@@ -30,12 +30,16 @@ bool llvm::codeview::isUdtForwardRef(CVType CVT) {
case LF_STRUCTURE:
case LF_CLASS:
case LF_INTERFACE:
+ case LF_STRUCTURE2:
+ case LF_CLASS2:
+ case LF_INTERFACE2:
UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
break;
case LF_ENUM:
UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
break;
case LF_UNION:
+ case LF_UNION2:
UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
break;
default:
@@ -173,8 +177,12 @@ uint64_t llvm::codeview::getSizeInBytesForTypeRecord(CVType CVT) {
case LF_STRUCTURE:
case LF_CLASS:
case LF_INTERFACE:
+ case LF_STRUCTURE2:
+ case LF_CLASS2:
+ case LF_INTERFACE2:
return getUdtSize<ClassRecord>(std::move(CVT));
case LF_UNION:
+ case LF_UNION2:
return getUdtSize<UnionRecord>(std::move(CVT));
default:
assert(false && "not an aggregate");
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index e8c9744935bf7..a58af389d8f74 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -19,6 +19,7 @@
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/ErrorExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -410,20 +411,47 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
}
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
- assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
- (CVR.kind() == TypeLeafKind::LF_CLASS) ||
- (CVR.kind() == TypeLeafKind::LF_INTERFACE));
-
std::string PropertiesNames = getFlagNames(
IO, static_cast<uint16_t>(Record.Options), getClassOptionNames());
- error(IO.mapInteger(Record.MemberCount, "MemberCount"));
- error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
- error(IO.mapInteger(Record.FieldList, "FieldList"));
- error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
- error(IO.mapInteger(Record.VTableShape, "VShape"));
- error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
- error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
- Record.hasUniqueName()));
+
+ // The original and *2 versions are handled in the same high level record as
+ // they're almost identical except for the widths of members. The *2 versions
+ // store the properties as 32 bits and the member count as an encoded integer.
+ TypeLeafKind Kind = CVR.kind();
+ if (Kind == TypeLeafKind::LF_STRUCTURE2 || Kind == TypeLeafKind::LF_CLASS2 ||
+ Kind == TypeLeafKind::LF_INTERFACE2) {
+ uint32_t Options = llvm::to_underlying(Record.Options);
+ error(IO.mapInteger(Options, "Properties" + PropertiesNames));
+ if (IO.isReading())
+ Record.Options = static_cast<ClassOptions>(Options);
+
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
+ error(IO.mapInteger(Record.VTableShape, "VShape"));
+ error(IO.mapEncodedInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+ } else {
+ assert(Kind == TypeLeafKind::LF_STRUCTURE ||
+ Kind == TypeLeafKind::LF_CLASS ||
+ Kind == TypeLeafKind::LF_INTERFACE);
+
+ // This is not an error to avoid failing to write all type records.
+ assert(
+ (IO.isReading() ||
+ Record.MemberCount <= std::numeric_limits<uint16_t>::max()) &&
+ "use the *2 versions of this record if there are 2^16 or more members");
+
+ error(IO.mapTruncInteger<uint16_t>(Record.MemberCount, "MemberCount"));
+ error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
+ error(IO.mapInteger(Record.VTableShape, "VShape"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+ }
return Error::success();
}
@@ -431,12 +459,33 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
std::string PropertiesNames = getFlagNames(
IO, static_cast<uint16_t>(Record.Options), getClassOptionNames());
- error(IO.mapInteger(Record.MemberCount, "MemberCount"));
- error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
- error(IO.mapInteger(Record.FieldList, "FieldList"));
- error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
- error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
- Record.hasUniqueName()));
+
+ if (CVR.kind() == LF_UNION2) {
+ uint32_t Options = llvm::to_underlying(Record.Options);
+ error(IO.mapInteger(Options, "Properties" + PropertiesNames));
+ if (IO.isReading())
+ Record.Options = static_cast<ClassOptions>(Options);
+
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapEncodedInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+ } else {
+ // This is not an error to avoid failing to write all type records.
+ assert(
+ (IO.isReading() ||
+ Record.MemberCount <= std::numeric_limits<uint16_t>::max()) &&
+ "use the *2 versions of this record if there are 2^16 or more members");
+
+ error(IO.mapTruncInteger<uint16_t>(Record.MemberCount, "MemberCount"));
+
+ error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+ }
return Error::success();
}
@@ -444,7 +493,7 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
std::string PropertiesNames = getFlagNames(
IO, static_cast<uint16_t>(Record.Options), getClassOptionNames());
- error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
+ error(IO.mapTruncInteger<uint16_t>(Record.MemberCount, "NumEnumerators"));
error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
error(IO.mapInteger(Record.FieldList, "FieldListType"));
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
index 77e90db429478..d1500ed1e248d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -86,9 +86,10 @@ static StringRef getRecordName(LazyRandomTypeCollection &Types, TypeIndex TI) {
};
TypeRecordKind RK = static_cast<TypeRecordKind>(CVReference.kind());
- if (RK == TypeRecordKind::Class || RK == TypeRecordKind::Struct)
+ if (RK == TypeRecordKind::Class || RK == TypeRecordKind::Class2 ||
+ RK == TypeRecordKind::Struct || RK == TypeRecordKind::Struct2)
GetName(ClassRecord(RK));
- else if (RK == TypeRecordKind::Union)
+ else if (RK == TypeRecordKind::Union || RK == TypeRecordKind::Union2)
GetName(UnionRecord(RK));
else if (RK == TypeRecordKind::Enum)
GetName(EnumRecord(RK));
@@ -3073,6 +3074,7 @@ LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) {
CurrentScope->setTag(dwarf::DW_TAG_array_type);
return CurrentScope;
case TypeLeafKind::LF_CLASS:
+ case TypeLeafKind::LF_CLASS2:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setTag(dwarf::DW_TAG_class_type);
CurrentScope->setIsClass();
@@ -3089,11 +3091,13 @@ LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) {
CurrentScope->setTag(dwarf::DW_TAG_subprogram);
return CurrentScope;
case TypeLeafKind::LF_STRUCTURE:
+ case TypeLeafKind::LF_STRUCTURE2:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setIsStructure();
CurrentScope->setTag(dwarf::DW_TAG_structure_type);
return CurrentScope;
case TypeLeafKind::LF_UNION:
+ case TypeLeafKind::LF_UNION2:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setIsUnion();
CurrentScope->setTag(dwarf::DW_TAG_union_type);
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
index 8571ca632f52b..01eed4ad5f405 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
@@ -46,9 +46,16 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const {
case PDB_SymType::PointerType:
return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER);
case PDB_SymType::UDT:
- return Session.getSymbolCache().createTypeEnumerator(
- {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION,
- codeview::LF_INTERFACE});
+ return Session.getSymbolCache().createTypeEnumerator({
+ codeview::LF_STRUCTURE,
+ codeview::LF_STRUCTURE2,
+ codeview::LF_CLASS,
+ codeview::LF_CLASS2,
+ codeview::LF_UNION,
+ codeview::LF_UNION2,
+ codeview::LF_INTERFACE,
+ codeview::LF_INTERFACE2,
+ });
case PDB_SymType::VTableShape:
return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE);
case PDB_SymType::FunctionSig:
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp
index c69cca166f041..2b02ea703915a 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp
@@ -112,12 +112,16 @@ PDB_UdtType NativeTypeUDT::getUdtKind() const {
switch (Tag->Kind) {
case TypeRecordKind::Class:
+ case TypeRecordKind::Class2:
return PDB_UdtType::Class;
case TypeRecordKind::Union:
+ case TypeRecordKind::Union2:
return PDB_UdtType::Union;
case TypeRecordKind::Struct:
+ case TypeRecordKind::Struct2:
return PDB_UdtType::Struct;
case TypeRecordKind::Interface:
+ case TypeRecordKind::Interface2:
return PDB_UdtType::Interface;
default:
llvm_unreachable("Unexpected udt kind");
diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
index 4cb4472354267..7946a9a75b4b5 100644
--- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
@@ -206,11 +206,15 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const {
std::move(CVT));
break;
case codeview::LF_CLASS:
+ case codeview::LF_CLASS2:
case codeview::LF_STRUCTURE:
+ case codeview::LF_STRUCTURE2:
case codeview::LF_INTERFACE:
+ case codeview::LF_INTERFACE2:
Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT));
break;
case codeview::LF_UNION:
+ case codeview::LF_UNION2:
Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT));
break;
case codeview::LF_POINTER:
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
index 941ce78027a21..dbbda0c16ca77 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -88,10 +88,14 @@ static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
switch (Type.kind()) {
case LF_CLASS:
+ case LF_CLASS2:
case LF_STRUCTURE:
+ case LF_STRUCTURE2:
case LF_INTERFACE:
+ case LF_INTERFACE2:
return getTagRecordHashForUdt<ClassRecord>(Type);
case LF_UNION:
+ case LF_UNION2:
return getTagRecordHashForUdt<UnionRecord>(Type);
case LF_ENUM:
return getTagRecordHashForUdt<EnumRecord>(Type);
@@ -105,10 +109,14 @@ Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
switch (Rec.kind()) {
case LF_CLASS:
+ case LF_CLASS2:
case LF_STRUCTURE:
+ case LF_STRUCTURE2:
case LF_INTERFACE:
+ case LF_INTERFACE2:
return getHashForUdt<ClassRecord>(Rec);
case LF_UNION:
+ case LF_UNION2:
return getHashForUdt<UnionRecord>(Rec);
case LF_ENUM:
return getHashForUdt<EnumRecord>(Rec);
diff --git a/llvm/test/DebugInfo/COFF/tag-types2.ll b/llvm/test/DebugInfo/COFF/tag-types2.ll
new file mode 100644
index 0000000000000..f7ebe62c48b26
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/tag-types2.ll
@@ -0,0 +1,198 @@
+; RUN: llc < %s -filetype=obj | llvm-readobj - --codeview | FileCheck --check-prefixes=ONE,BOTH %s
+; RUN: llc < %s -filetype=obj -use-codeview-tagrecord2 | llvm-readobj - --codeview | FileCheck --check-prefixes=TWO,BOTH %s
+
+; BOTH: CodeViewTypes [
+; BOTH: Section: .debug$T (5)
+; ONE: Union (0x1000) {
+; TWO: Union2 (0x1000) {
+; ONE-NEXT: TypeLeafKind: LF_UNION (0x1506)
+; TWO-NEXT: TypeLeafKind: LF_UNION2 (0x160A)
+; BOTH-NEXT: MemberCount: 0
+; BOTH-NEXT: Properties [ (0x280)
+; BOTH-NEXT: ForwardReference (0x80)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: 0x0
+; BOTH-NEXT: SizeOf: 0
+; BOTH-NEXT: Name: AUnion
+; BOTH-NEXT: LinkageName: .?ATAUnion@@
+; BOTH-NEXT: }
+; BOTH: FieldList (0x1001) {
+; BOTH: TypeLeafKind: LF_FIELDLIST (0x1203)
+; BOTH: }
+; BOTH: Enum (0x1002) {
+; BOTH-NEXT: TypeLeafKind: LF_ENUM (0x1507)
+; BOTH-NEXT: NumEnumerators: 3
+; BOTH-NEXT: Properties [ (0x200)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: UnderlyingType: int (0x74)
+; BOTH-NEXT: FieldListType: <field list> (0x1001)
+; BOTH-NEXT: Name: AEnum
+; BOTH-NEXT: LinkageName: .?AW4AEnum@@
+; BOTH-NEXT: }
+; BOTH: StringId (0x1003) {
+; BOTH: }
+; BOTH: UdtSourceLine (0x1004) {
+; BOTH: }
+; BOTH: Pointer (0x1005) {
+; BOTH: PointeeType: AUnion (0x1000)
+; BOTH: }
+; ONE: Class (0x1006) {
+; TWO: Class2 (0x1006) {
+; ONE-NEXT: TypeLeafKind: LF_CLASS (0x1504)
+; TWO-NEXT: TypeLeafKind: LF_CLASS2 (0x1608)
+; BOTH-NEXT: MemberCount: 0
+; BOTH-NEXT: Properties [ (0x280)
+; BOTH-NEXT: ForwardReference (0x80)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: 0x0
+; BOTH-NEXT: DerivedFrom: 0x0
+; BOTH-NEXT: VShape: 0x0
+; BOTH-NEXT: SizeOf: 0
+; BOTH-NEXT: Name: AClass
+; BOTH-NEXT: LinkageName: .?AVAClass@@
+; BOTH-NEXT: }
+; ONE: Struct (0x1007) {
+; TWO: Struct2 (0x1007) {
+; ONE-NEXT: TypeLeafKind: LF_STRUCTURE (0x1505)
+; TWO-NEXT: TypeLeafKind: LF_STRUCTURE2 (0x1609)
+; BOTH-NEXT: MemberCount: 0
+; BOTH-NEXT: Properties [ (0x280)
+; BOTH-NEXT: ForwardReference (0x80)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: 0x0
+; BOTH-NEXT: DerivedFrom: 0x0
+; BOTH-NEXT: VShape: 0x0
+; BOTH-NEXT: SizeOf: 0
+; BOTH-NEXT: Name: AStruct
+; BOTH-NEXT: LinkageName: .?AUAStruct@@
+; BOTH-NEXT: }
+; BOTH: FieldList (0x1008) {
+; BOTH: TypeLeafKind: LF_FIELDLIST (0x1203)
+; BOTH: }
+; ONE: Union (0x1009) {
+; TWO: Union2 (0x1009) {
+; ONE-NEXT: TypeLeafKind: LF_UNION (0x1506)
+; TWO-NEXT: TypeLeafKind: LF_UNION2 (0x160A)
+; BOTH-NEXT: MemberCount: 4
+; BOTH-NEXT: Properties [ (0x600)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: Sealed (0x400)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: <field list> (0x1008)
+; BOTH-NEXT: SizeOf: 8
+; BOTH-NEXT: Name: AUnion
+; BOTH-NEXT: LinkageName: .?ATAUnion@@
+; BOTH-NEXT: }
+; BOTH: UdtSourceLine (0x100A) {
+; BOTH: }
+; BOTH: FieldList (0x100B) {
+; BOTH: TypeLeafKind: LF_FIELDLIST (0x1203)
+; BOTH: }
+; ONE: Class (0x100C) {
+; TWO: Class2 (0x100C) {
+; ONE-NEXT: TypeLeafKind: LF_CLASS (0x1504)
+; TWO-NEXT: TypeLeafKind: LF_CLASS2 (0x1608)
+; BOTH-NEXT: MemberCount: 1
+; BOTH-NEXT: Properties [ (0x200)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: <field list> (0x100B)
+; BOTH-NEXT: DerivedFrom: 0x0
+; BOTH-NEXT: VShape: 0x0
+; BOTH-NEXT: SizeOf: 8
+; BOTH-NEXT: Name: AClass
+; BOTH-NEXT: LinkageName: .?AVAClass@@
+; BOTH-NEXT: }
+; BOTH: UdtSourceLine (0x100D) {
+; BOTH: }
+; BOTH: Pointer (0x100E) {
+; BOTH: PointeeType: AClass (0x1006)
+; BOTH: }
+; BOTH: FieldList (0x100F) {
+; BOTH: TypeLeafKind: LF_FIELDLIST (0x1203)
+; BOTH: }
+; ONE: Struct (0x1010) {
+; TWO: Struct2 (0x1010) {
+; ONE-NEXT: TypeLeafKind: LF_STRUCTURE (0x1505)
+; TWO-NEXT: TypeLeafKind: LF_STRUCTURE2 (0x1609)
+; BOTH-NEXT: MemberCount: 1
+; BOTH-NEXT: Properties [ (0x200)
+; BOTH-NEXT: HasUniqueName (0x200)
+; BOTH-NEXT: ]
+; BOTH-NEXT: FieldList: <field list> (0x100F)
+; BOTH-NEXT: DerivedFrom: 0x0
+; BOTH-NEXT: VShape: 0x0
+; BOTH-NEXT: SizeOf: 8
+; BOTH-NEXT: Name: AStruct
+; BOTH-NEXT: LinkageName: .?AUAStruct@@
+; BOTH-NEXT: }
+; BOTH: ]
+
+; BOTH: Subsection [
+; BOTH: SubSectionType: Symbols (0xF1)
+; BOTH: SubSectionSize: 0x30
+; BOTH: UDTSym {
+; BOTH: Kind: S_UDT (0x1108)
+; BOTH: Type: AUnion (0x1009)
+; BOTH: UDTName: AUnion
+; BOTH: }
+; BOTH: UDTSym {
+; BOTH: Kind: S_UDT (0x1108)
+; BOTH: Type: AClass (0x100C)
+; BOTH: UDTName: AClass
+; BOTH: }
+; BOTH: UDTSym {
+; BOTH: Kind: S_UDT (0x1108)
+; BOTH: Type: AStruct (0x1010)
+; BOTH: UDTName: AStruct
+; BOTH: }
+; BOTH: ]
+
+source_filename = "tag-types.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.51.36260"
+
+%union.AUnion = type { ptr }
+
+@"?u@@3TAUnion@@A" = dso_local global %union.AUnion zeroinitializer, align 8, !dbg !0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!26, !27, !28, !29, !30}
+!llvm.ident = !{!31}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "u", linkageName: "?u@@3TAUnion@@A", scope: !2, file: !3, line: 17, type: !12, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !11, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "tag-types.cpp", directory: "/tmp")
+!4 = !{!5}
+!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AEnum", file: !3, line: 9, baseType: !6, size: 32, elements: !7, identifier: ".?AW4AEnum@@")
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{!8, !9, !10}
+!8 = !DIEnumerator(name: "Foo", value: 0)
+!9 = !DIEnumerator(name: "Bar", value: 1)
+!10 = !DIEnumerator(name: "Baz", value: 2)
+!11 = !{!0}
+!12 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "AUnion", file: !3, line: 10, size: 64, flags: DIFlagTypePassByValue, elements: !13, identifier: ".?ATAUnion@@")
+!13 = !{!14, !15, !17, !21}
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "e", scope: !12, file: !3, line: 11, baseType: !5, size: 32)
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !12, file: !3, line: 12, baseType: !16, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !12, file: !3, line: 13, baseType: !18, size: 64)
+!18 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "AClass", file: !3, line: 6, size: 64, flags: DIFlagTypePassByValue, elements: !19, identifier: ".?AVAClass@@")
+!19 = !{!20}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !18, file: !3, line: 7, baseType: !16, size: 64)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: !12, file: !3, line: 14, baseType: !22, size: 64)
+!22 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "AStruct", file: !3, line: 2, size: 64, flags: DIFlagTypePassByValue, elements: !23, identifier: ".?AUAStruct@@")
+!23 = !{!24}
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "clazz", scope: !22, file: !3, line: 3, baseType: !25, size: 64)
+!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
+!26 = !{i32 2, !"CodeView", i32 1}
+!27 = !{i32 2, !"Debug Info Version", i32 3}
+!28 = !{i32 8, !"PIC Level", i32 2}
+!29 = !{i32 7, !"uwtable", i32 2}
+!30 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!31 = !{!"clang"}
diff --git a/llvm/test/DebugInfo/PDB/DIA/tag-types2.test b/llvm/test/DebugInfo/PDB/DIA/tag-types2.test
new file mode 100644
index 0000000000000..284304c07b16e
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/DIA/tag-types2.test
@@ -0,0 +1,71 @@
+; RUN: llvm-pdbutil yaml2pdb %p/../Inputs/tag-types2.yaml -pdb=%t.pdb
+; RUN: llvm-pdbutil diadump -udts %t.pdb | FileCheck %s
+
+; CHECK: {
+; CHECK: symIndexId: 1
+; CHECK: symTag: UDT
+; CHECK: name: AUnion
+; CHECK: length: 8
+; CHECK: udtKind: union
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
+; CHECK: {
+; CHECK: symIndexId: 3
+; CHECK: symTag: UDT
+; CHECK: name: AClass
+; CHECK: virtualTableShapeId: 4
+; CHECK: length: 8
+; CHECK: udtKind: class
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
+; CHECK: {
+; CHECK: symIndexId: 5
+; CHECK: symTag: UDT
+; CHECK: name: AStruct
+; CHECK: virtualTableShapeId: 4
+; CHECK: length: 8
+; CHECK: udtKind: struct
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
diff --git a/llvm/test/DebugInfo/PDB/Inputs/tag-types2.yaml b/llvm/test/DebugInfo/PDB/Inputs/tag-types2.yaml
new file mode 100644
index 0000000000000..e0ec0a504448c
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/Inputs/tag-types2.yaml
@@ -0,0 +1,146 @@
+---
+TpiStream:
+ Version: VC80
+ Records:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 116
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 0
+ Name: Foo
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 1
+ Name: Bar
+ - Kind: LF_ENUMERATE
+ Enumerator:
+ Attrs: 3
+ Value: 2
+ Name: Baz
+ - Kind: LF_ENUM
+ Enum:
+ NumEnumerators: 3
+ Options: [ None, HasUniqueName ]
+ FieldList: 4098
+ Name: AEnum
+ UniqueName: '.?AW4AEnum@@'
+ UnderlyingType: 116
+ - Kind: LF_UNION2
+ Union:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AUnion
+ UniqueName: '.?ATAUnion@@'
+ Size: 0
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4100
+ Attrs: 65548
+ - Kind: LF_CLASS2
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AClass
+ UniqueName: '.?AVAClass@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_STRUCTURE2
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AStruct
+ UniqueName: '.?AUAStruct@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4099
+ FieldOffset: 0
+ Name: e
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4101
+ FieldOffset: 0
+ Name: u
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4102
+ FieldOffset: 0
+ Name: c
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4103
+ FieldOffset: 0
+ Name: s
+ - Kind: LF_UNION2
+ Union:
+ MemberCount: 4
+ Options: [ None, HasUniqueName, Sealed ]
+ FieldList: 4104
+ Name: AUnion
+ UniqueName: '.?ATAUnion@@'
+ Size: 8
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 1
+ Type: 4101
+ FieldOffset: 0
+ Name: u
+ - Kind: LF_CLASS2
+ Class:
+ MemberCount: 1
+ Options: [ None, HasUniqueName ]
+ FieldList: 4106
+ Name: AClass
+ UniqueName: '.?AVAClass@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4102
+ Attrs: 65548
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 4108
+ FieldOffset: 0
+ Name: clazz
+ - Kind: LF_STRUCTURE2
+ Class:
+ MemberCount: 1
+ Options: [ None, HasUniqueName ]
+ FieldList: 4109
+ Name: AStruct
+ UniqueName: '.?AUAStruct@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
+...
diff --git a/llvm/test/DebugInfo/PDB/Native/tag-types2.test b/llvm/test/DebugInfo/PDB/Native/tag-types2.test
new file mode 100644
index 0000000000000..c254739c68450
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/Native/tag-types2.test
@@ -0,0 +1,73 @@
+; Test that we can report LF_CLASS2 and friends as UDTs.
+; The only difference to the DIA/ test is in the symbol indexes.
+; RUN: llvm-pdbutil yaml2pdb %p/../Inputs/tag-types2.yaml -pdb=%t.pdb
+; RUN: llvm-pdbutil diadump -native -udts %t.pdb | FileCheck %s
+
+; CHECK: {
+; CHECK: symIndexId: 2
+; CHECK: symTag: UDT
+; CHECK: name: AUnion
+; CHECK: length: 8
+; CHECK: udtKind: union
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
+; CHECK: {
+; CHECK: symIndexId: 3
+; CHECK: symTag: UDT
+; CHECK: name: AClass
+; CHECK: virtualTableShapeId: 4
+; CHECK: length: 8
+; CHECK: udtKind: class
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
+; CHECK: {
+; CHECK: symIndexId: 5
+; CHECK: symTag: UDT
+; CHECK: name: AStruct
+; CHECK: virtualTableShapeId: 4
+; CHECK: length: 8
+; CHECK: udtKind: struct
+; CHECK: constructor: 0
+; CHECK: constType: 0
+; CHECK: hasAssignmentOperator: 0
+; CHECK: hasCastOperator: 0
+; CHECK: hasNestedTypes: 0
+; CHECK: overloadedOperator: 0
+; CHECK: isInterfaceUdt: 0
+; CHECK: intrinsic: 0
+; CHECK: nested: 0
+; CHECK: packed: 0
+; CHECK: isRefUdt: 0
+; CHECK: scoped: 0
+; CHECK: unalignedType: 0
+; CHECK: isValueUdt: 0
+; CHECK: volatileType: 0
+; CHECK: }
diff --git a/llvm/test/tools/llvm-pdbutil/tag-types2.yaml b/llvm/test/tools/llvm-pdbutil/tag-types2.yaml
new file mode 100644
index 0000000000000..b12699c5970bf
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/tag-types2.yaml
@@ -0,0 +1,148 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types --type-extras %t.pdb | FileCheck --check-prefix=YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --tpi-stream %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=PDB2YAML %s
+
+# YAML2PDB: 0x1000 | LF_UNION2 [size = 36, hash = 0x211D0] `AUnion`
+# YAML2PDB-NEXT: unique name: `.?ATAUnion@@`
+# YAML2PDB-NEXT: field list: <no type>
+# YAML2PDB-NEXT: options: forward ref (-> 0x1003) | has unique name, sizeof 0
+# YAML2PDB-NEXT: 0x1001 | LF_CLASS2 [size = 44, hash = 0x252B1] `AClass`
+# YAML2PDB-NEXT: unique name: `.?AVAClass@@`
+# YAML2PDB-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# YAML2PDB-NEXT: options: forward ref (-> 0x1004) | has unique name, sizeof 0
+# YAML2PDB-NEXT: 0x1002 | LF_STRUCTURE2 [size = 48, hash = 0x301BC] `AStruct`
+# YAML2PDB-NEXT: unique name: `.?AUAStruct@@`
+# YAML2PDB-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# YAML2PDB-NEXT: options: forward ref (-> 0x1005) | has unique name, sizeof 0
+# YAML2PDB-NEXT: 0x1003 | LF_UNION2 [size = 36, hash = 0x399E2] `AUnion`
+# YAML2PDB-NEXT: unique name: `.?ATAUnion@@`
+# YAML2PDB-NEXT: field list: 0x1008
+# YAML2PDB-NEXT: options: has unique name | sealed, sizeof 8
+# YAML2PDB-NEXT: 0x1004 | LF_CLASS2 [size = 44, hash = 0x952C] `AClass`
+# YAML2PDB-NEXT: unique name: `.?AVAClass@@`
+# YAML2PDB-NEXT: vtable: <no type>, base list: <no type>, field list: 0x100A
+# YAML2PDB-NEXT: options: has unique name, sizeof 8
+# YAML2PDB-NEXT: 0x1005 | LF_STRUCTURE2 [size = 48, hash = 0x2293A] `AStruct`
+# YAML2PDB-NEXT: unique name: `.?AUAStruct@@`
+# YAML2PDB-NEXT: vtable: <no type>, base list: <no type>, field list: 0x100D
+# YAML2PDB-NEXT: options: has unique name, sizeof 8
+
+# PDB2YAML: Records:
+# PDB2YAML-NEXT: - Kind: LF_UNION2
+# PDB2YAML-NEXT: Union:
+# PDB2YAML-NEXT: MemberCount: 0
+# PDB2YAML-NEXT: Options: [ None, ForwardReference, HasUniqueName ]
+# PDB2YAML-NEXT: FieldList: 0
+# PDB2YAML-NEXT: Name: AUnion
+# PDB2YAML-NEXT: UniqueName: '.?ATAUnion@@'
+# PDB2YAML-NEXT: Size: 0
+# PDB2YAML-NEXT: - Kind: LF_CLASS2
+# PDB2YAML-NEXT: Class:
+# PDB2YAML-NEXT: MemberCount: 0
+# PDB2YAML-NEXT: Options: [ None, ForwardReference, HasUniqueName ]
+# PDB2YAML-NEXT: FieldList: 0
+# PDB2YAML-NEXT: Name: AClass
+# PDB2YAML-NEXT: UniqueName: '.?AVAClass@@'
+# PDB2YAML-NEXT: DerivationList: 0
+# PDB2YAML-NEXT: VTableShape: 0
+# PDB2YAML-NEXT: Size: 0
+# PDB2YAML-NEXT: - Kind: LF_STRUCTURE2
+# PDB2YAML-NEXT: Class:
+# PDB2YAML-NEXT: MemberCount: 0
+# PDB2YAML-NEXT: Options: [ None, ForwardReference, HasUniqueName ]
+# PDB2YAML-NEXT: FieldList: 0
+# PDB2YAML-NEXT: Name: AStruct
+# PDB2YAML-NEXT: UniqueName: '.?AUAStruct@@'
+# PDB2YAML-NEXT: DerivationList: 0
+# PDB2YAML-NEXT: VTableShape: 0
+# PDB2YAML-NEXT: Size: 0
+# PDB2YAML-NEXT: - Kind: LF_UNION2
+# PDB2YAML-NEXT: Union:
+# PDB2YAML-NEXT: MemberCount: 4
+# PDB2YAML-NEXT: Options: [ None, HasUniqueName, Sealed ]
+# PDB2YAML-NEXT: FieldList: 4104
+# PDB2YAML-NEXT: Name: AUnion
+# PDB2YAML-NEXT: UniqueName: '.?ATAUnion@@'
+# PDB2YAML-NEXT: Size: 8
+# PDB2YAML-NEXT: - Kind: LF_CLASS2
+# PDB2YAML-NEXT: Class:
+# PDB2YAML-NEXT: MemberCount: 1
+# PDB2YAML-NEXT: Options: [ None, HasUniqueName ]
+# PDB2YAML-NEXT: FieldList: 4106
+# PDB2YAML-NEXT: Name: AClass
+# PDB2YAML-NEXT: UniqueName: '.?AVAClass@@'
+# PDB2YAML-NEXT: DerivationList: 0
+# PDB2YAML-NEXT: VTableShape: 0
+# PDB2YAML-NEXT: Size: 8
+# PDB2YAML-NEXT: - Kind: LF_STRUCTURE2
+# PDB2YAML-NEXT: Class:
+# PDB2YAML-NEXT: MemberCount: 1
+# PDB2YAML-NEXT: Options: [ None, HasUniqueName ]
+# PDB2YAML-NEXT: FieldList: 4109
+# PDB2YAML-NEXT: Name: AStruct
+# PDB2YAML-NEXT: UniqueName: '.?AUAStruct@@'
+# PDB2YAML-NEXT: DerivationList: 0
+# PDB2YAML-NEXT: VTableShape: 0
+# PDB2YAML-NEXT: Size: 8
+
+TpiStream:
+ Version: VC80
+ Records:
+ - Kind: LF_UNION2
+ Union:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AUnion
+ UniqueName: '.?ATAUnion@@'
+ Size: 0
+ - Kind: LF_CLASS2
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AClass
+ UniqueName: '.?AVAClass@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_STRUCTURE2
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: AStruct
+ UniqueName: '.?AUAStruct@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_UNION2
+ Union:
+ MemberCount: 4
+ Options: [ None, HasUniqueName, Sealed ]
+ FieldList: 4104
+ Name: AUnion
+ UniqueName: '.?ATAUnion@@'
+ Size: 8
+ - Kind: LF_CLASS2
+ Class:
+ MemberCount: 1
+ Options: [ None, HasUniqueName ]
+ FieldList: 4106
+ Name: AClass
+ UniqueName: '.?AVAClass@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
+ - Kind: LF_STRUCTURE2
+ Class:
+ MemberCount: 1
+ Options: [ None, HasUniqueName ]
+ FieldList: 4109
+ Name: AStruct
+ UniqueName: '.?AUAStruct@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 8
diff --git a/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
index c7653b7c06d48..d302717b1723b 100644
--- a/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
+++ b/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
@@ -150,9 +150,13 @@ void TypeReferenceTracker::markReferencedTypes() {
default:
break;
case LF_CLASS:
+ case LF_CLASS2:
case LF_INTERFACE:
+ case LF_INTERFACE2:
case LF_STRUCTURE:
+ case LF_STRUCTURE2:
case LF_UNION:
+ case LF_UNION2:
case LF_ENUM:
addOneTypeRef(TiRefKind::TypeRef,
cantFail(Tpi->findFullDeclForForwardRef(RefTI)));
diff --git a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
index 810aeada33da7..3082a115d2cbf 100644
--- a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
+++ b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
@@ -613,3 +613,19 @@ TEST_F(TypeIndexIteratorTest, RegRelativeIndir) {
writeSymbolRecords(RR);
checkTypeReferences(0, RR.Type);
}
+
+TEST_F(TypeIndexIteratorTest, Class2) {
+ ClassRecord CR(TypeRecordKind::Class2);
+ CR.FieldList = TypeIndex::Int32();
+ CR.DerivationList = TypeIndex::Float32();
+ CR.VTableShape = TypeIndex::UInt32();
+ writeTypeRecords(CR);
+ checkTypeReferences(0, CR.FieldList, CR.DerivationList, CR.VTableShape);
+}
+
+TEST_F(TypeIndexIteratorTest, Union2) {
+ UnionRecord UR(TypeRecordKind::Union2);
+ UR.FieldList = TypeIndex::Int32();
+ writeTypeRecords(UR);
+ checkTypeReferences(0, UR.FieldList);
+}
More information about the llvm-commits
mailing list