[llvm] [DebugInfo][CodeView] Resolve forward references to types without unique name (PR #203781)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 14 11:49:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-debuginfo
Author: Nerixyz (Nerixyz)
<details>
<summary>Changes</summary>
In the following code:
```
// header.h
typedef struct lua_State lua_State;
lua_State *getState();
// source.c
#include "header.h"
struct lua_State { int field; };
lua_State *getState() {
static lua_State state = {.field=42}; // make sure the type is emitted
return &state;
}
// main.cpp
extern "C" {
#include "header.h"
}
int main() { return getState() != 0; }
```
We'll get two forward references for `lua_State` when compiling with clang-cl. One with a unique name (from C++) and one without (from C). There's one complete definition for the type (from `source.c`). Since this is from C, it doesn't have a unique name. Before, we could only resolve the forward reference from C, not from C++.
With this PR, we can resolve both references. I also tested that the VS debugger resolves the reference correctly.
I'm not sure if this is a clang bug, because when compiling with MSVC, the C type also has a unique name. Clang omits the unique name, because C doesn't have ODR like C++.
---
Full diff: https://github.com/llvm/llvm-project/pull/203781.diff
3 Files Affected:
- (modified) llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp (+7-1)
- (added) llvm/test/tools/llvm-pdbutil/forward-cxx-to-c-odr.test (+116)
- (added) llvm/test/tools/llvm-pdbutil/forward-cxx-to-c.test (+89)
``````````diff
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
index 24d2f9e3360ea..ad996c7fec80e 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp
@@ -209,8 +209,14 @@ TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
continue;
}
- if (!FullTR.hasUniqueName())
+ if (!FullTR.hasUniqueName()) {
+ // `ForwardTR` does have a unique name, but the type we found doesn't.
+ // Remember this type, but look for better candidates in the bucket first.
+ if (ForwardTR.getName() == FullTR.getName())
+ ForwardRefTI = TI;
continue;
+ }
+
if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
return TI;
}
diff --git a/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c-odr.test b/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c-odr.test
new file mode 100644
index 0000000000000..9a13c80cca6bc
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c-odr.test
@@ -0,0 +1,116 @@
+# Test that we prefer types with unique names when resolving forward references
+# from records with unique names.
+
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types %t.pdb | FileCheck %s
+
+# The forward reference from 0x1002 -> 0x100A is important here.
+# In contrast to `forward-cxx-to-c.test`, we should resolve the reference to
+# 0x100A here, because both have a unique name (even if 0x1008 is lower).
+# For 0x1004, we resolve 0x1008, because of the missing unique name.
+
+# CHECK: 0x1002 | LF_STRUCTURE [size = 48] `lua_State`
+# CHECK-NEXT: unique name: `.?AUlua_State@@`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT: options: forward ref (-> 0x100A) | has unique name, sizeof 0
+# CHECK: 0x1004 | LF_STRUCTURE [size = 32] `lua_State`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT: options: forward ref (-> 0x1008), sizeof 0
+# CHECK: 0x1007 | LF_FIELDLIST [size = 20]
+# CHECK-NEXT: - LF_MEMBER [name = `field`, Type = 0x0074 (int), offset = 0, attrs = public]
+# CHECK-NEXT: 0x1008 | LF_STRUCTURE [size = 32] `lua_State`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: 0x1007
+# CHECK-NEXT: options: , sizeof 4
+# CHECK-NEXT: 0x1009 | LF_FIELDLIST [size = 32]
+# CHECK-NEXT: - LF_MEMBER [name = `differentField`, Type = 0x0074 (int), offset = 0, attrs = public]
+# CHECK-NEXT: 0x100A | LF_STRUCTURE [size = 48] `lua_State`
+# CHECK-NEXT: unique name: `.?AUlua_State@@`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: 0x1007
+# CHECK-NEXT: options: has unique name, sizeof 4
+
+---
+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_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: lua_State
+ UniqueName: '.?AUlua_State@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4098
+ Attrs: 65548
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference ]
+ FieldList: 0
+ Name: lua_State
+ UniqueName: ''
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4100
+ Attrs: 65548
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 4101
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 0
+ Name: field
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 1
+ Options: [ None ]
+ FieldList: 4103
+ Name: lua_State
+ UniqueName: ''
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 0
+ Name: differentField
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 1
+ Options: [ None, HasUniqueName ]
+ FieldList: 4103
+ Name: lua_State
+ UniqueName: '.?AUlua_State@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+...
diff --git a/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c.test b/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c.test
new file mode 100644
index 0000000000000..7a2810cc79ed4
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/forward-cxx-to-c.test
@@ -0,0 +1,89 @@
+# Test that we can resolve forward references from types with a unique name (from C++)
+# to types without a unique name (from C).
+
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types %t.pdb | FileCheck %s
+
+# The forward reference from 0x1002 -> 0x1008 is important here.
+
+# CHECK: 0x1002 | LF_STRUCTURE [size = 48] `lua_State`
+# CHECK-NEXT: unique name: `.?AUlua_State@@`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT: options: forward ref (-> 0x1008) | has unique name, sizeof 0
+# CHECK: 0x1004 | LF_STRUCTURE [size = 32] `lua_State`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT: options: forward ref (-> 0x1008), sizeof 0
+# CHECK: 0x1007 | LF_FIELDLIST [size = 20]
+# CHECK-NEXT: - LF_MEMBER [name = `field`, Type = 0x0074 (int), offset = 0, attrs = public]
+# CHECK-NEXT: 0x1008 | LF_STRUCTURE [size = 32] `lua_State`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: 0x1007
+# CHECK-NEXT: options: , sizeof 4
+
+---
+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_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference, HasUniqueName ]
+ FieldList: 0
+ Name: lua_State
+ UniqueName: '.?AUlua_State@@'
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4098
+ Attrs: 65548
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 0
+ Options: [ None, ForwardReference ]
+ FieldList: 0
+ Name: lua_State
+ UniqueName: ''
+ DerivationList: 0
+ VTableShape: 0
+ Size: 0
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4100
+ Attrs: 65548
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 4101
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 0
+ ArgumentList: 4096
+ - Kind: LF_FIELDLIST
+ FieldList:
+ - Kind: LF_MEMBER
+ DataMember:
+ Attrs: 3
+ Type: 116
+ FieldOffset: 0
+ Name: field
+ - Kind: LF_STRUCTURE
+ Class:
+ MemberCount: 1
+ Options: [ None ]
+ FieldList: 4103
+ Name: lua_State
+ UniqueName: ''
+ DerivationList: 0
+ VTableShape: 0
+ Size: 4
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/203781
More information about the llvm-commits
mailing list