<div dir="ltr"><div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Sep 20, 2018 at 5:51 PM Zachary Turner via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: zturner<br>
Date: Thu Sep 20 08:50:13 2018<br>
New Revision: 342656<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=342656&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=342656&view=rev</a><br>
Log:<br>
[PDB] Add the ability to map forward references to full decls.<br>
<br>
Some records point to an LF_CLASS, LF_UNION, LF_STRUCTURE, or LF_ENUM<br>
which is a forward reference and doesn't contain complete debug<br>
information. In these cases, we'd like to be able to quickly locate the<br>
full record. The TPI stream stores an array of pre-computed record hash<br>
values, one for each type record. If we pre-process this on startup, we<br>
can build a mapping from hash value -> {list of possible matching type<br>
indices}. Since hashes of full records are only based on the name and or<br>
unique name and not the full record contents, we can then use forward<br>
ref record to compute the hash of what *would* be the full record by<br>
just hashing the name, use this to get the list of possible matches, and<br>
iterate those looking for a match on name or unique name.<br>
<br>
llvm-pdbutil is updated to resolve forward references for the purposes<br>
of testing (plus it's just useful).<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D52283" rel="noreferrer" target="_blank">https://reviews.llvm.org/D52283</a><br>
<br>
Added:<br>
    llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp<br>
    llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb   (with props)<br>
    llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test<br>
Modified:<br>
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h<br>
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h<br>
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h<br>
    llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp<br>
    llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp<br>
    llvm/trunk/test/DebugInfo/PDB/every-type.test<br>
    llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test<br>
    llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp<br>
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp<br>
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h<br>
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp<br>
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h<br>
<br>
Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h (original)<br>
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h Thu Sep 20 08:50:13 2018<br>
@@ -343,7 +343,6 @@ struct SrcHeaderBlockEntry {<br>
   char Reserved[8];<br>
 };<br>
<br>
-constexpr int I = sizeof(SrcHeaderBlockEntry);<br>
 static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!");<br>
<br>
 } // namespace pdb<br>
<br>
Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h (original)<br>
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h Thu Sep 20 08:50:13 2018<br>
@@ -18,6 +18,54 @@ namespace pdb {<br>
<br>
 Expected<uint32_t> hashTypeRecord(const llvm::codeview::CVType &Type);<br>
<br>
+struct TagRecordHash {<br>
+  explicit TagRecordHash(codeview::ClassRecord CR, uint32_t Full,<br>
+                         uint32_t Forward)<br>
+      : Class(std::move(CR)), FullRecordHash(Full), ForwardDeclHash(Forward) {<br>
+    State = 0;<br>
+  }<br>
+<br>
+  explicit TagRecordHash(codeview::EnumRecord ER, uint32_t Full,<br>
+                         uint32_t Forward)<br>
+      : Enum(std::move(ER)), FullRecordHash(Full), ForwardDeclHash(Forward) {<br>
+    State = 1;<br>
+  }<br>
+<br>
+  explicit TagRecordHash(codeview::UnionRecord UR, uint32_t Full,<br>
+                         uint32_t Forward)<br>
+      : Union(std::move(UR)), FullRecordHash(Full), ForwardDeclHash(Forward) {<br>
+    State = 2;<br>
+  }<br>
+<br>
+  uint32_t FullRecordHash;<br>
+  uint32_t ForwardDeclHash;<br>
+<br>
+  codeview::TagRecord &getRecord() {<br>
+    switch (State) {<br>
+    case 0:<br>
+      return Class;<br>
+    case 1:<br>
+      return Enum;<br>
+    case 2:<br>
+      return Union;<br>
+    }<br>
+    llvm_unreachable("unreachable!");<br>
+  }<br>
+<br>
+private:<br>
+  union {<br>
+    codeview::ClassRecord Class;<br>
+    codeview::EnumRecord Enum;<br>
+    codeview::UnionRecord Union;<br>
+  };<br>
+<br>
+  uint8_t State = 0;<br>
+};<br>
+<br>
+/// Given a CVType referring to a class, structure, union, or enum, compute<br>
+/// the hash of its forward decl and full decl.<br>
+Expected<TagRecordHash> hashTagRecord(const codeview::CVType &Type);<br>
+<br>
 } // end namespace pdb<br>
 } // end namespace llvm<br>
<br>
<br>
Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h (original)<br>
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h Thu Sep 20 08:50:13 2018<br>
@@ -58,10 +58,17 @@ public:<br>
<br>
   codeview::LazyRandomTypeCollection &typeCollection() { return *Types; }<br>
<br>
+  Expected<codeview::TypeIndex><br>
+  findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const;<br>
+<br>
   BinarySubstreamRef getTypeRecordsSubstream() const;<br>
<br>
   Error commit();<br>
<br>
+  void buildHashMap();<br>
+<br>
+  bool supportsTypeLookup() const;<br>
+<br>
 private:<br>
   PDBFile &Pdb;<br>
   std::unique_ptr<msf::MappedBlockStream> Stream;<br>
@@ -77,6 +84,8 @@ private:<br>
   FixedStreamArray<codeview::TypeIndexOffset> TypeIndexOffsets;<br>
   HashTable<support::ulittle32_t> HashAdjusters;<br>
<br>
+  std::vector<std::vector<codeview::TypeIndex>> HashMap;<br>
+<br>
   const TpiStreamHeader *Header;<br>
 };<br>
 }<br>
<br>
Modified: llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp (original)<br>
+++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp Thu Sep 20 08:50:13 2018<br>
@@ -50,6 +50,32 @@ static Expected<uint32_t> getHashForUdt(<br>
 }<br>
<br>
 template <typename T><br>
+static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) {<br>
+  T Deserialized;<br>
+  if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),<br>
+                                               Deserialized))<br>
+    return std::move(E);<br>
+<br>
+  ClassOptions Opts = Deserialized.getOptions();<br>
+<br>
+  bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);<br>
+<br>
+  uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data());<br>
+<br>
+  // If we don't have a forward ref we can't compute the hash of it from the<br>
+  // full record because it requires hashing the entire buffer.<br>
+  if (!ForwardRef)<br>
+    return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0};<br>
+<br>
+  bool Scoped = bool(Opts & ClassOptions::Scoped);<br>
+<br>
+  StringRef NameToHash =<br>
+      Scoped ? Deserialized.getUniqueName() : Deserialized.getName();<br>
+  uint32_t FullHash = hashStringV1(NameToHash);<br>
+  return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash};<br>
+}<br>
+<br>
+template <typename T><br>
 static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {<br>
   T Deserialized;<br>
   if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),<br>
@@ -60,6 +86,23 @@ static Expected<uint32_t> getSourceLineH<br>
   return hashStringV1(StringRef(Buf, 4));<br>
 }<br>
<br>
+Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {<br>
+  switch (Type.kind()) {<br>
+  case LF_CLASS:<br>
+  case LF_STRUCTURE:<br>
+  case LF_INTERFACE:<br>
+    return getTagRecordHashForUdt<ClassRecord>(Type);<br>
+  case LF_UNION:<br>
+    return getTagRecordHashForUdt<UnionRecord>(Type);<br>
+  case LF_ENUM:<br>
+    return getTagRecordHashForUdt<EnumRecord>(Type);<br>
+  default:<br>
+    assert(false && "Type is not a tag record!");<br>
+  }<br>
+  return make_error<StringError>("Invalid record type",<br>
+                                 inconvertibleErrorCode());<br>
+}<br>
+<br>
 Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {<br>
   switch (Rec.kind()) {<br>
   case LF_CLASS:<br>
<br>
Modified: llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp (original)<br>
+++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp Thu Sep 20 08:50:13 2018<br>
@@ -11,8 +11,11 @@<br>
<br>
 #include "llvm/ADT/iterator_range.h"<br>
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"<br>
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"<br>
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"<br>
 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"<br>
+#include "llvm/DebugInfo/PDB/Native/Hash.h"<br>
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"<br>
 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"<br>
 #include "llvm/DebugInfo/PDB/Native/RawError.h"<br>
@@ -140,6 +143,93 @@ uint16_t TpiStream::getTypeHashStreamAux<br>
 uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }<br>
 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }<br>
<br>
+void TpiStream::buildHashMap() {<br>
+  if (!HashMap.empty())<br>
+    return;<br>
+  if (HashValues.empty())<br>
+    return;<br>
+<br>
+  HashMap.resize(Header->NumHashBuckets);<br>
+<br>
+  TypeIndex TIB{Header->TypeIndexBegin};<br>
+  TypeIndex TIE{Header->TypeIndexEnd};<br>
+  while (TIB < TIE) {<br>
+    uint32_t HV = HashValues[TIB.toArrayIndex()];<br>
+    HashMap[HV].push_back(TIB++);<br>
+  }<br>
+}<br>
+<br>
+bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }<br>
+<br>
+template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {<br>
+  RecordT Record;<br>
+  if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {<br>
+    consumeError(std::move(EC));<br>
+    return ClassOptions::None;<br>
+  }<br>
+  return Record.getOptions();<br>
+}<br>
+<br>
+static bool isUdtForwardRef(CVType CVT) {<br>
+  ClassOptions UdtOptions = ClassOptions::None;<br>
+  switch (CVT.kind()) {<br>
+  case LF_STRUCTURE:<br>
+  case LF_CLASS:<br>
+  case LF_INTERFACE:<br>
+    UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));<br>
+    break;<br>
+  case LF_ENUM:<br>
+    UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));<br>
+    break;<br>
+  case LF_UNION:<br>
+    UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));<br>
+    break;<br>
+  default:<br>
+    return false;<br>
+  }<br>
+  return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;<br>
+}<br>
+<br>
+Expected<TypeIndex><br>
+TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {<br>
+  CVType F = Types->getType(ForwardRefTI);<br>
+  if (!isUdtForwardRef(F))<br>
+    return ForwardRefTI;<br>
+<br>
+  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);<br>
+  if (!ForwardTRH)<br>
+    return ForwardTRH.takeError();<br>
+<br>
+  TagRecordHash Copy = std::move(*ForwardTRH);<br></blockquote><div><br></div><div>lib/DebugInfo/PDB/Native/TpiStream.cpp:203:17: error: unused variable 'Copy' [-Werror,-Wunused-variable]</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;<br>
+<br>
+  for (TypeIndex TI : HashMap[BucketIdx]) {<br>
+    CVType CVT = Types->getType(TI);<br>
+    if (CVT.kind() != F.kind())<br>
+      continue;<br>
+<br>
+    Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);<br>
+    if (!FullTRH)<br>
+      return FullTRH.takeError();<br>
+    if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)<br>
+      continue;<br>
+    TagRecord &ForwardTR = ForwardTRH->getRecord();<br>
+    TagRecord &FullTR = FullTRH->getRecord();<br>
+<br>
+    if (!ForwardTR.hasUniqueName()) {<br>
+      if (ForwardTR.getName() == FullTR.getName())<br>
+        return TI;<br>
+      continue;<br>
+    }<br>
+<br>
+    if (!FullTR.hasUniqueName())<br>
+      continue;<br>
+    if (ForwardTR.getUniqueName() == FullTR.getUniqueName())<br>
+      return TI;<br>
+  }<br>
+  return ForwardRefTI;<br>
+}<br>
+<br>
 BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {<br>
   return TypeRecordsSubstream;<br>
 }<br>
<br>
Added: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp?rev=342656&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp?rev=342656&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp (added)<br>
+++ llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp Thu Sep 20 08:50:13 2018<br>
@@ -0,0 +1,61 @@<br>
+// Build with "cl.exe /Z7 /GR- /GS- /GX- every-class.cpp /link /debug:full /nodefaultlib /incremental:no /entry:main"<br>
+<br>
+#include <stdint.h><br>
+<br>
+// clang-format off<br>
+void *__purecall = 0;<br>
+<br>
+void __cdecl operator delete(void *, unsigned int) {}<br>
+void __cdecl operator delete(void *, unsigned __int64) {}<br>
+<br>
+struct Nothing {};<br>
+struct Constructor { Constructor() {} };<br>
+struct Assignment {<br>
+  Assignment &operator=(Assignment Other) { return *this; }<br>
+};<br>
+struct Cast {<br>
+  operator int() { return 42; }<br>
+};<br>
+<br>
+struct Nested {<br>
+  struct F {};<br>
+};<br>
+struct Operator {<br>
+  int operator+(int X) { return 42; }<br>
+};<br>
+<br>
+class Class {};<br>
+<br>
+union Union {};<br>
+<br>
+enum class Enum {A};<br>
+<br>
+<br>
+template<typename T> void f(T t) {}<br>
+<br>
+int main(int argc, char **argv) {<br>
+  struct Scoped {};<br>
+  <br>
+  struct { } Anonymous;<br>
+<br>
+  f(Nothing{});<br>
+  f(Constructor{});<br>
+  f(Assignment{});<br>
+  f(Cast{});<br>
+  f(Nested{});<br>
+  f(Operator{});<br>
+  f(Nested::F{});<br>
+  f(Scoped{});<br>
+  f(Class{});<br>
+  f(Union{});<br>
+  f(Anonymous);<br>
+  f(Enum::A);<br>
+  <br>
+<br>
+  f<const Nothing>(Nothing{});<br>
+  f<volatile Nothing>(Nothing{});<br>
+  f<const volatile Nothing>(Nothing{});<br>
+  f<__unaligned Nothing>(Nothing{});<br>
+<br>
+  return 0;<br>
+}<br>
<br>
Added: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb?rev=342656&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb?rev=342656&view=auto</a><br>
==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Modified: llvm/trunk/test/DebugInfo/PDB/every-type.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/every-type.test?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/every-type.test?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/PDB/every-type.test (original)<br>
+++ llvm/trunk/test/DebugInfo/PDB/every-type.test Thu Sep 20 08:50:13 2018<br>
@@ -9,12 +9,14 @@ we claim to understand.  We then test th<br>
<br>
<br>
 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \<br>
-RUN:   -dependents %p/Inputs/every-type.pdb | FileCheck --check-prefix=TYPES %s<br>
+RUN:   -dont-resolve-forward-refs -dependents %p/Inputs/every-type.pdb \<br>
+RUN:   | FileCheck --check-prefix=TYPES %s<br>
<br>
 RUN: llvm-pdbutil pdb2yaml -tpi-stream -ipi-stream %p/Inputs/every-type.pdb > %t.pdb.yaml<br>
 RUN: llvm-pdbutil yaml2pdb -pdb=%t.yaml.pdb %t.pdb.yaml<br>
 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \<br>
-RUN:   -dependents %t.yaml.pdb | FileCheck --check-prefix=TYPES %s<br>
+RUN:   -dependents -dont-resolve-forward-refs %t.yaml.pdb \<br>
+RUN:   | FileCheck --check-prefix=TYPES %s<br>
<br>
 TYPES:                           Types (TPI Stream)<br>
 TYPES-NEXT: ============================================================<br>
<br>
Added: llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test?rev=342656&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test?rev=342656&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test (added)<br>
+++ llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test Thu Sep 20 08:50:13 2018<br>
@@ -0,0 +1,98 @@<br>
+; RUN: llvm-pdbutil dump -types %p/Inputs/every-class.pdb \<br>
+; RUN:   | FileCheck %s<br>
+<br>
+; CHECK:                      Types (TPI Stream)                     <br>
+; CHECK: ============================================================<br>
+; CHECK:   Showing 157 records<br>
+; CHECK:   0x1008 | LF_STRUCTURE [size = 124] `main::__l2::<unnamed-type-Anonymous>`<br>
+; CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007<br>
+; CHECK:            options: has unique name | scoped, sizeof 1<br>
+; CHECK:   0x1009 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`<br>
+; CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007<br>
+; CHECK:            options: has unique name | scoped, sizeof 1<br>
+; CHECK:   0x1054 | LF_STRUCTURE [size = 48] `Nested::F`<br>
+; CHECK:            unique name: `.?AUF@Nested@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (-> 0x1057) | has unique name | is nested, sizeof 0<br>
+; CHECK:   0x1056 | LF_STRUCTURE [size = 44] `Nested`<br>
+; CHECK:            unique name: `.?AUNested@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1055<br>
+; CHECK:            options: contains nested class | has unique name, sizeof 1<br>
+; CHECK:   0x1057 | LF_STRUCTURE [size = 48] `Nested::F`<br>
+; CHECK:            unique name: `.?AUF@Nested@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007<br>
+; CHECK:            options: has unique name | is nested, sizeof 1<br>
+; CHECK:   0x1058 | LF_STRUCTURE [size = 52] `Constructor`<br>
+; CHECK:            unique name: `.?AUConstructor@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (-> 0x105C) | has unique name, sizeof 0<br>
+; CHECK:   0x105C | LF_STRUCTURE [size = 52] `Constructor`<br>
+; CHECK:            unique name: `.?AUConstructor@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x105B<br>
+; CHECK:            options: has ctor / dtor | has unique name, sizeof 1<br>
+; CHECK:   0x105D | LF_CLASS [size = 40] `Class`<br>
+; CHECK:            unique name: `.?AVClass@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007<br>
+; CHECK:            options: has unique name, sizeof 1<br>
+; CHECK:   0x105E | LF_UNION [size = 32] `Union`<br>
+; CHECK:            unique name: `.?ATUnion@@`<br>
+; CHECK:            field list: 0x1007<br>
+; CHECK:            options: has unique name | sealed, sizeof 1<br>
+; CHECK:   0x105F | LF_STRUCTURE [size = 48] `Operator`<br>
+; CHECK:            unique name: `.?AUOperator@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (-> 0x1064) | has unique name, sizeof 0<br>
+; CHECK:   0x1064 | LF_STRUCTURE [size = 48] `Operator`<br>
+; CHECK:            unique name: `.?AUOperator@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1063<br>
+; CHECK:            options: has unique name | overloaded operator, sizeof 1<br>
+; CHECK:   0x1066 | LF_ENUM [size = 36] `Enum`<br>
+; CHECK:            unique name: `.?AW4Enum@@`<br>
+; CHECK:            field list: 0x1065, underlying type: 0x0074 (int)<br>
+; CHECK:            options: has unique name<br>
+; CHECK:   0x1067 | LF_STRUCTURE [size = 40] `Cast`<br>
+; CHECK:            unique name: `.?AUCast@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (-> 0x106B) | has unique name, sizeof 0<br>
+; CHECK:   0x106B | LF_STRUCTURE [size = 40] `Cast`<br>
+; CHECK:            unique name: `.?AUCast@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x106A<br>
+; CHECK:            options: conversion operator | has unique name | overloaded operator, sizeof 1<br>
+; CHECK:   0x106C | LF_STRUCTURE [size = 44] `Nothing`<br>
+; CHECK:            unique name: `.?AUNothing@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007<br>
+; CHECK:            options: has unique name, sizeof 1<br>
+; CHECK:   0x106D | LF_STRUCTURE [size = 52] `Assignment`<br>
+; CHECK:            unique name: `.?AUAssignment@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (-> 0x1073) | has unique name, sizeof 0<br>
+; CHECK:   0x1073 | LF_STRUCTURE [size = 52] `Assignment`<br>
+; CHECK:            unique name: `.?AUAssignment@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1072<br>
+; CHECK:            options: has unique name | overloaded operator | overloaded operator=, sizeof 1<br>
+; CHECK:   0x1074 | LF_STRUCTURE [size = 44] `Nothing`<br>
+; CHECK:            unique name: `.?AUNothing@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x106C) | has unique name, sizeof 0<br>
+; CHECK:   0x1081 | LF_UNION [size = 32] `Union`<br>
+; CHECK:            unique name: `.?ATUnion@@`<br>
+; CHECK:            field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x105E) | has unique name, sizeof 0<br>
+; CHECK:   0x1084 | LF_STRUCTURE [size = 124] `main::__l2::<unnamed-type-Anonymous>`<br>
+; CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x1008) | has unique name | scoped, sizeof 0<br>
+; CHECK:   0x108E | LF_STRUCTURE [size = 44] `Nested`<br>
+; CHECK:            unique name: `.?AUNested@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x1056) | has unique name, sizeof 0<br>
+; CHECK:   0x1095 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`<br>
+; CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x1009) | has unique name | scoped, sizeof 0<br>
+; CHECK:   0x1098 | LF_CLASS [size = 40] `Class`<br>
+; CHECK:            unique name: `.?AVClass@@`<br>
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type><br>
+; CHECK:            options: forward ref (<- 0x105D) | has unique name, sizeof 0<br>
<br>
Modified: llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test (original)<br>
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test Thu Sep 20 08:50:13 2018<br>
@@ -1,7 +1,9 @@<br>
-; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s<br>
+; RUN: llvm-pdbutil dump -all -dont-resolve-forward-refs %p/Inputs/empty.pdb \<br>
+; RUN:   | FileCheck -check-prefix=ALL %s<br>
 ; RUN: llvm-pdbutil dump -summary -modules -files \<br>
 ; RUN:              %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s<br>
-; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s<br>
+; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 \<br>
+; RUN:   | FileCheck -check-prefix=BAD-BLOCK-SIZE %s<br>
<br>
 ALL:                                Summary<br>
 ALL-NEXT: ============================================================<br>
<br>
Modified: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp (original)<br>
+++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp Thu Sep 20 08:50:13 2018<br>
@@ -1241,13 +1241,13 @@ static void<br>
 dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,<br>
                    uint32_t NumTypeRecords, uint32_t NumHashBuckets,<br>
                    FixedStreamArray<support::ulittle32_t> HashValues,<br>
-                   bool Bytes, bool Extras) {<br>
+                   TpiStream *Stream, bool Bytes, bool Extras) {<br>
<br>
   Printer.formatLine("Showing {0:N} records", NumTypeRecords);<br>
   uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);<br>
<br>
   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,<br>
-                           NumHashBuckets, HashValues);<br>
+                           NumHashBuckets, HashValues, Stream);<br>
<br>
   if (auto EC = codeview::visitTypeStream(Types, V)) {<br>
     Printer.formatLine("An error occurred dumping type records: {0}",<br>
@@ -1263,7 +1263,8 @@ static void dumpPartialTypeStream(LinePr<br>
       NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());<br>
<br>
   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,<br>
-                           Stream.getNumHashBuckets(), Stream.getHashValues());<br>
+                           Stream.getNumHashBuckets(), Stream.getHashValues(),<br>
+                           &Stream);<br>
<br>
   if (opts::dump::DumpTypeDependents) {<br>
     // If we need to dump all dependents, then iterate each index and find<br>
@@ -1325,7 +1326,8 @@ Error DumpOutputStyle::dumpTypesFromObje<br>
     Types.reset(Reader, 100);<br>
<br>
     if (opts::dump::DumpTypes) {<br>
-      dumpFullTypeStream(P, Types, 0, 0, {}, opts::dump::DumpTypeData, false);<br>
+      dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,<br>
+                         false);<br>
     } else if (opts::dump::DumpTypeExtras) {<br>
       auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);<br>
       auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);<br>
@@ -1394,11 +1396,14 @@ Error DumpOutputStyle::dumpTpiStream(uin<br>
<br>
   auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();<br>
<br>
+  // Enable resolving forward decls.<br>
+  Stream.buildHashMap();<br>
+<br>
   if (DumpTypes || !Indices.empty()) {<br>
     if (Indices.empty())<br>
       dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),<br>
                          Stream.getNumHashBuckets(), Stream.getHashValues(),<br>
-                         DumpBytes, DumpExtras);<br>
+                         &Stream, DumpBytes, DumpExtras);<br>
     else {<br>
       std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());<br>
       dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,<br>
<br>
Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp (original)<br>
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp Thu Sep 20 08:50:13 2018<br>
@@ -12,6 +12,7 @@<br>
 #include "FormatUtil.h"<br>
 #include "LinePrinter.h"<br>
<br>
+#include "llvm-pdbutil.h"<br>
 #include "llvm/DebugInfo/CodeView/CVRecord.h"<br>
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"<br>
 #include "llvm/DebugInfo/CodeView/CodeView.h"<br>
@@ -19,6 +20,7 @@<br>
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"<br>
 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"<br>
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"<br>
 #include "llvm/Support/FormatVariadic.h"<br>
 #include "llvm/Support/MathExtras.h"<br>
<br>
@@ -27,15 +29,37 @@ using namespace llvm::codeview;<br>
 using namespace llvm::pdb;<br>
<br>
 static std::string formatClassOptions(uint32_t IndentLevel,<br>
-                                      ClassOptions Options) {<br>
+                                      ClassOptions Options, TpiStream *Stream,<br>
+                                      TypeIndex CurrentTypeIndex) {<br>
   std::vector<std::string> Opts;<br>
+<br>
+  if (Stream && Stream->supportsTypeLookup() &&<br>
+      !opts::dump::DontResolveForwardRefs &&<br>
+      ((Options & ClassOptions::ForwardReference) != ClassOptions::None)) {<br>
+    // If we're able to resolve forward references, do that.<br>
+    Expected<TypeIndex> ETI =<br>
+        Stream->findFullDeclForForwardRef(CurrentTypeIndex);<br>
+    if (!ETI) {<br>
+      consumeError(ETI.takeError());<br>
+      PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref (???)");<br>
+    } else {<br>
+      const char *Direction = (*ETI == CurrentTypeIndex)<br>
+                                  ? "="<br>
+                                  : ((*ETI < CurrentTypeIndex) ? "<-" : "->");<br>
+      std::string Formatted =<br>
+          formatv("forward ref ({0} {1})", Direction, *ETI).str();<br>
+      PUSH_FLAG(ClassOptions, ForwardReference, Options, std::move(Formatted));<br>
+    }<br>
+  } else {<br>
+    PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");<br>
+  }<br>
+<br>
   PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,<br>
             "has ctor / dtor");<br>
   PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,<br>
             "contains nested class");<br>
   PUSH_FLAG(ClassOptions, HasConversionOperator, Options,<br>
             "conversion operator");<br>
-  PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");<br>
   PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");<br>
   PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");<br>
   PUSH_FLAG(ClassOptions, Nested, Options, "is nested");<br>
@@ -194,6 +218,7 @@ static std::string formatFunctionOptions<br>
 }<br>
<br>
 Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {<br>
+  CurrentTypeIndex = Index;<br>
   // formatLine puts the newline at the beginning, so we use formatLine here<br>
   // to start a new line, and then individual visit methods use format to<br>
   // append to the existing line.<br>
@@ -304,7 +329,8 @@ Error MinimalTypeDumpVisitor::visitKnown<br>
   P.formatLine("vtable: {0}, base list: {1}, field list: {2}",<br>
                Class.VTableShape, Class.DerivationList, Class.FieldList);<br>
   P.formatLine("options: {0}, sizeof {1}",<br>
-               formatClassOptions(P.getIndentLevel(), Class.Options),<br>
+               formatClassOptions(P.getIndentLevel(), Class.Options, Stream,<br>
+                                  CurrentTypeIndex),<br>
                Class.Size);<br>
   return Error::success();<br>
 }<br>
@@ -316,7 +342,8 @@ Error MinimalTypeDumpVisitor::visitKnown<br>
     P.formatLine("unique name: `{0}`", Union.UniqueName);<br>
   P.formatLine("field list: {0}", Union.FieldList);<br>
   P.formatLine("options: {0}, sizeof {1}",<br>
-               formatClassOptions(P.getIndentLevel(), Union.Options),<br>
+               formatClassOptions(P.getIndentLevel(), Union.Options, Stream,<br>
+                                  CurrentTypeIndex),<br>
                Union.Size);<br>
   return Error::success();<br>
 }<br>
@@ -328,7 +355,8 @@ Error MinimalTypeDumpVisitor::visitKnown<br>
   P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,<br>
                Enum.UnderlyingType);<br>
   P.formatLine("options: {0}",<br>
-               formatClassOptions(P.getIndentLevel(), Enum.Options));<br>
+               formatClassOptions(P.getIndentLevel(), Enum.Options, Stream,<br>
+                                  CurrentTypeIndex));<br>
   return Error::success();<br>
 }<br>
<br>
<br>
Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h (original)<br>
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h Thu Sep 20 08:50:13 2018<br>
@@ -20,15 +20,18 @@ class LazyRandomTypeCollection;<br>
<br>
 namespace pdb {<br>
 class LinePrinter;<br>
+class TpiStream;<br>
<br>
 class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {<br>
 public:<br>
   MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,<br>
                          bool Hashes, codeview::LazyRandomTypeCollection &Types,<br>
                          uint32_t NumHashBuckets,<br>
-                         FixedStreamArray<support::ulittle32_t> HashValues)<br>
+                         FixedStreamArray<support::ulittle32_t> HashValues,<br>
+                         pdb::TpiStream *Stream)<br>
       : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),<br>
-        Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues) {}<br>
+        Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),<br>
+        Stream(Stream) {}<br>
<br>
   Error visitTypeBegin(codeview::CVType &Record,<br>
                        codeview::TypeIndex Index) override;<br>
@@ -55,7 +58,9 @@ private:<br>
   bool Hashes = false;<br>
   codeview::LazyRandomTypeCollection &Types;<br>
   uint32_t NumHashBuckets;<br>
+  codeview::TypeIndex CurrentTypeIndex;<br>
   FixedStreamArray<support::ulittle32_t> HashValues;<br>
+  pdb::TpiStream *Stream = nullptr;<br>
 };<br>
 } // namespace pdb<br>
 } // namespace llvm<br>
<br>
Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp (original)<br>
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp Thu Sep 20 08:50:13 2018<br>
@@ -183,6 +183,8 @@ static cl::opt<bool> Enums("enums", cl::<br>
                            cl::sub(DiaDumpSubcommand));<br>
 static cl::opt<bool> Pointers("pointers", cl::desc("Dump enum types"),<br>
                               cl::sub(DiaDumpSubcommand));<br>
+static cl::opt<bool> UDTs("udts", cl::desc("Dump udt types"),<br>
+                          cl::sub(DiaDumpSubcommand));<br>
 static cl::opt<bool> Compilands("compilands",<br>
                                 cl::desc("Dump compiland information"),<br>
                                 cl::sub(DiaDumpSubcommand));<br>
@@ -465,6 +467,12 @@ cl::opt<bool> DumpTypeExtras("type-extra<br>
                              cl::desc("dump type hashes and index offsets"),<br>
                              cl::cat(TypeOptions), cl::sub(DumpSubcommand));<br>
<br>
+cl::opt<bool> DontResolveForwardRefs(<br>
+    "dont-resolve-forward-refs",<br>
+    cl::desc("When dumping type records for classes, unions, enums, and "<br>
+             "structs, don't try to resolve forward references"),<br>
+    cl::cat(TypeOptions), cl::sub(DumpSubcommand));<br>
+<br>
 cl::list<uint32_t> DumpTypeIndex(<br>
     "type-index", cl::ZeroOrMore, cl::CommaSeparated,<br>
     cl::desc("only dump types with the specified hexadecimal type index"),<br>
<br>
Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h?rev=342656&r1=342655&r2=342656&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h?rev=342656&r1=342655&r2=342656&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h (original)<br>
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h Thu Sep 20 08:50:13 2018<br>
@@ -160,6 +160,7 @@ extern llvm::cl::opt<bool> DumpIdExtras;<br>
 extern llvm::cl::list<uint32_t> DumpIdIndex;<br>
 extern llvm::cl::opt<uint32_t> DumpModi;<br>
 extern llvm::cl::opt<bool> JustMyCode;<br>
+extern llvm::cl::opt<bool> DontResolveForwardRefs;<br>
 extern llvm::cl::opt<bool> DumpSymbols;<br>
 extern llvm::cl::opt<bool> DumpSymRecordBytes;<br>
 extern llvm::cl::opt<bool> DumpGSIRecords;<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div></div>