[PATCH] D54667: [CodeView] Emit proper debug info for ref-qualified member functions
Zachary Turner via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 17 08:57:34 PST 2018
zturner created this revision.
zturner added a reviewer: rnk.
Herald added subscribers: JDevlieghere, hiraditya, aprantl.
When you have a member function with a ref-qualifier, for example:
struct Foo {
void Func() &;
void Func2() &&;
};
clang-cl was not emitting this information. Doing so is a bit awkward, because it's not a property of the `LF_MFUNCTION` type, which is what you'd expect. Instead, it's a property of the `this` pointer which is actually an `LF_POINTER`. This record has an attributes bitmask on it, and our handling of this bitmask was all wrong. We had some parts of the bitmask defined incorrectly, but importantly for this bug, we didn't know about these extra 2 bits that represent the ref qualifier at all. We can see this in the reference implementation here:
https://github.com/Microsoft/microsoft-pdb/blob/master/include/cvinfo.h#L1524-L1525
And we can also observe that clang-cl and cl emit different records by compiling a simple program and using `llvm-pdbutil` to dump the results of each one.
// cat foo.cpp
struct A {
int NoRefQual();
int RefQual() &;
int RefQual() &&;
int LValueRef() &;
int RValueRef() &&;
};
int main(int argc, char **argv) {
A *GenericPtr = nullptr;
A a;
return 0;
}
With clang:
$ clang-cl.exe /Z7 /GS- /GR- foo.cpp /o foo-clang.exe
$ llvm-pdbutil.exe dump -types -type-index=0x1009 -dependents -type-data foo-clang.pdb
Types (TPI Stream)
============================================================
Showing 1 records and their dependents (7 records total)
0x1003 | LF_STRUCTURE [size = 32] `A`
unique name: `.?AUA@@`
vtable: <no type>, base list: <no type>, field list: <no type>
options: forward ref (-> 0x1009) | has unique name, sizeof 0
Bytes (
0000: 1E000515 00008002 00000000 00000000 00000000 00004100 2E3F4155 41404000 |......................A..?AUA@@.|
)
0x1004 | LF_POINTER [size = 12]
referent = 0x1003, mode = pointer, opts = None, kind = ptr64
Bytes (
0000: 0A000210 03100000 0C000100 |............|
)
0x1005 | LF_ARGLIST [size = 8]
Bytes (
0000: 06000112 00000000 |........|
)
0x1006 | LF_MFUNCTION [size = 28]
return type = 0x0074 (int), # args = 0, param list = 0x1005
class type = 0x1003, this type = 0x1004, this adjust = 0
calling conv = cdecl, options = None
Bytes (
0000: 1A000910 74000000 03100000 04100000 00000000 05100000 00000000 |....t.......................|
)
0x1007 | LF_METHODLIST [size = 20]
- Method [type = 0x1006, vftable offset = -1, attrs = public]
- Method [type = 0x1006, vftable offset = -1, attrs = public]
Bytes (
0000: 12000612 03000000 06100000 03000000 06100000 |....................|
)
0x1008 | LF_FIELDLIST [size = 80]
- LF_ONEMETHOD [name = `NoRefQual`]
type = 0x1006, vftable offset = -1, attrs = public
Bytes (
0000: 03000610 00004E6F 52656651 75616C00 |......NoRefQual.|
)
- LF_METHOD [name = `RefQual`, # overloads = 2, overload list = 0x1007]
Bytes (
0000: 02000710 00005265 66517561 6C00 |......RefQual.|
)
- LF_ONEMETHOD [name = `LValueRef`]
type = 0x1006, vftable offset = -1, attrs = public
Bytes (
0000: 03000610 00004C56 616C7565 52656600 |......LValueRef.|
)
- LF_ONEMETHOD [name = `RValueRef`]
type = 0x1006, vftable offset = -1, attrs = public
Bytes (
0000: 03000610 00005256 616C7565 52656600 |......RValueRef.|
)
Bytes (
0000: 4E000312 11150300 06100000 4E6F5265 66517561 6C00F2F1 0F150200 07100000 |N...........NoRefQual...........|
0020: 52656651 75616C00 11150300 06100000 4C56616C 75655265 6600F2F1 11150300 |RefQual.........LValueRef.......|
0040: 06100000 5256616C 75655265 6600F2F1 |....RValueRef...|
)
0x1009 | LF_STRUCTURE [size = 32] `A`
unique name: `.?AUA@@`
vtable: <no type>, base list: <no type>, field list: 0x1008
options: has unique name, sizeof 1
Bytes (
0000: 1E000515 05000002 08100000 00000000 00000000 01004100 2E3F4155 41404000 |......................A..?AUA@@.|
)
If we follow the type indices here, we can see that `RValueRef`, `LValueRef`, both overloads of `RefQual` and also `NoRefQual` all have the same `LF_MFUNCTION` type, which is 0x1006. Since they have the same `LF_MFUNCTION`, they also have the same `LF_POINTER` for the this pointer since it is part of that record. For the sake of comparison later, the dump of this pointer record is:
referent = 0x1003, mode = pointer, opts = None, kind = ptr64 0000: 0A000210 03100000 0C000100
With MSVC
$ cl.exe /Z7 /GS- /GR- foo.cpp /o foo-cl.exe
$ llvm-pdbutil.exe dump -types -type-index=0x100E -dependents -type-data foo-cl.pdb
Types (TPI Stream)
============================================================
Showing 1 records and their dependents (11 records total)
0x1003 | LF_STRUCTURE [size = 32] `A`
unique name: `.?AUA@@`
vtable: <no type>, base list: <no type>, field list: <no type>
options: forward ref (-> 0x100E) | has unique name, sizeof 0
Bytes (
0000: 1E000515 00008002 00000000 00000000 00000000 00004100 2E3F4155 41404000 |......................A..?AUA@@.|
)
0x1005 | LF_POINTER [size = 12]
referent = 0x1003, mode = pointer, opts = const, kind = ptr64
Bytes (
0000: 0A000210 03100000 0C040100 |............|
)
0x1006 | LF_ARGLIST [size = 8]
Bytes (
0000: 06000112 00000000 |........|
)
0x1007 | LF_MFUNCTION [size = 28]
return type = 0x0074 (int), # args = 0, param list = 0x1006
class type = 0x1003, this type = 0x1005, this adjust = 0
calling conv = cdecl, options = None
Bytes (
0000: 1A000910 74000000 03100000 05100000 00000000 06100000 00000000 |....t.......................|
)
0x1008 | LF_POINTER [size = 12]
referent = 0x1003, mode = pointer, opts = const, kind = ptr64
Bytes (
0000: 0A000210 03100000 0C042100 |..........!.|
)
0x1009 | LF_MFUNCTION [size = 28]
return type = 0x0074 (int), # args = 0, param list = 0x1006
class type = 0x1003, this type = 0x1008, this adjust = 0
calling conv = cdecl, options = None
Bytes (
0000: 1A000910 74000000 03100000 08100000 00000000 06100000 00000000 |....t.......................|
)
0x100A | LF_POINTER [size = 12]
referent = 0x1003, mode = pointer, opts = const, kind = ptr64
Bytes (
0000: 0A000210 03100000 0C041100 |............|
)
0x100B | LF_MFUNCTION [size = 28]
return type = 0x0074 (int), # args = 0, param list = 0x1006
class type = 0x1003, this type = 0x100A, this adjust = 0
calling conv = cdecl, options = None
Bytes (
0000: 1A000910 74000000 03100000 0A100000 00000000 06100000 00000000 |....t.......................|
)
0x100C | LF_METHODLIST [size = 20]
- Method [type = 0x1009, vftable offset = -1, attrs = public]
- Method [type = 0x100B, vftable offset = -1, attrs = public]
Bytes (
0000: 12000612 03000000 09100000 03000000 0B100000 |....................|
)
0x100D | LF_FIELDLIST [size = 80]
- LF_ONEMETHOD [name = `NoRefQual`]
type = 0x1007, vftable offset = -1, attrs = public
Bytes (
0000: 03000710 00004E6F 52656651 75616C00 |......NoRefQual.|
)
- LF_METHOD [name = `RefQual`, # overloads = 2, overload list = 0x100C]
Bytes (
0000: 02000C10 00005265 66517561 6C00 |......RefQual.|
)
- LF_ONEMETHOD [name = `LValueRef`]
type = 0x100B, vftable offset = -1, attrs = public
Bytes (
0000: 03000B10 00004C56 616C7565 52656600 |......LValueRef.|
)
- LF_ONEMETHOD [name = `RValueRef`]
type = 0x1009, vftable offset = -1, attrs = public
Bytes (
0000: 03000910 00005256 616C7565 52656600 |......RValueRef.|
)
Bytes (
0000: 4E000312 11150300 07100000 4E6F5265 66517561 6C00F2F1 0F150200 0C100000 |N...........NoRefQual...........|
0020: 52656651 75616C00 11150300 0B100000 4C56616C 75655265 6600F2F1 11150300 |RefQual.........LValueRef.......|
0040: 09100000 5256616C 75655265 6600F2F1 |....RValueRef...|
)
0x100E | LF_STRUCTURE [size = 32] `A`
unique name: `.?AUA@@`
vtable: <no type>, base list: <no type>, field list: 0x100D
options: has unique name, sizeof 1
Bytes (
0000: 1E000515 05000002 0D100000 00000000 00000000 01004100 2E3F4155 41404000 |......................A..?AUA@@.|
)
Here we see several different `LF_MFUNCTION` records in use.
0x1009: Used by `Foo::RValueRef` and one overload of `Foo::RefQual`
0x100B: Used by `Foo::LValueRef` and one overload of `Foo::RefQual`
0x1007: Used by `Foo::NoRefQual`
And the only difference between any of them is the "this type" field. So for this pointer types, we have:
0x1008: Used by `Foo::RValueRef` and one overload of `Foo::RefQual`
0x100A: Used by `Foo::LValueRef` and one overload of `Foo::RefQual`
0x1005: Used by `Foo::NoRefQual`
And if we then go look at the record data of each one, we have:
0x1008: referent = 0x1003, mode = pointer, opts = const, kind = ptr64 0000: 0A000210 03100000 0C042100
0x100A: referent = 0x1003, mode = pointer, opts = const, kind = ptr64 0000: 0A000210 03100000 0C041100
0x1005: referent = 0x1003, mode = pointer, opts = const, kind = ptr64 0000: 0A000210 03100000 0C040100
The data that llvm-pdbutil looks identical for each one, but if we look closer at the record bytes we can see that there is 1 bit difference in each of them.
After this patch, clang-cl emits compatible debug info for this case.
0x1009: referent = 0x1003, mode = pointer, opts = None, kind = ptr64 0000: 0A000210 03100000 0C002100
0x1007: referent = 0x1003, mode = pointer, opts = None, kind = ptr64 0000: 0A000210 03100000 0C001100
0x1004: referent = 0x1003, mode = pointer, opts = None, kind = ptr64 0000: 0A000210 03100000 0C000100
https://reviews.llvm.org/D54667
Files:
lldb/lit/SymbolFile/NativePDB/member-function-types.cpp
llvm/include/llvm/DebugInfo/CodeView/CodeView.h
llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
llvm/test/DebugInfo/COFF/defer-complete-type.ll
llvm/test/DebugInfo/COFF/globals.ll
llvm/test/DebugInfo/COFF/type-quals.ll
llvm/test/DebugInfo/COFF/types-array-advanced.ll
llvm/test/DebugInfo/COFF/types-basic.ll
llvm/test/DebugInfo/COFF/types-calling-conv.ll
llvm/test/DebugInfo/COFF/types-data-members.ll
llvm/test/DebugInfo/COFF/types-method-ref-qualifiers.ll
llvm/test/DebugInfo/COFF/types-non-virtual-methods.ll
llvm/test/DebugInfo/COFF/types-ptr-to-member.ll
llvm/test/DebugInfo/COFF/types-recursive-struct.ll
llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D54667.174507.patch
Type: text/x-patch
Size: 33980 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181117/7370eadb/attachment.bin>
More information about the llvm-commits
mailing list