This is an archive of the discontinued LLVM Phabricator instance.

[LLDB][NativePDB] Don't complete static members' types when completing a record type.
ClosedPublic

Authored by zequanwu on Mar 4 2022, 4:14 PM.

Details

Summary

UdtRecordCompleter shouldn't complete static members' types. static members' types are going to be completed when the types are called in SymbolFile::CompleteType.

Diff Detail

Event Timeline

zequanwu created this revision.Mar 4 2022, 4:14 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 4 2022, 4:14 PM
zequanwu requested review of this revision.Mar 4 2022, 4:14 PM
rnk added a comment.Mar 4 2022, 4:30 PM

A similar loop exists between a class and class methods, the type of the this parameter usually references the class, and the same is true for any parameters. Is there some existing code to handle this for methods?

zequanwu added a comment.EditedMar 7 2022, 3:30 PM

A similar loop exists between a class and class methods, the type of the this parameter usually references the class, and the same is true for any parameters. Is there some existing code to handle this for methods?

For function parameter type and return type, it will not try to complete their types. It just create a skeleton record type. And the skeleton record type is created and cached before it's trying to complete the type.

This defers the completion of static data members by caching them and complete them later

Are you sure that we need to complete static members at all? They have no impact on the layout of the class, so ideally they would only be completed when they are actually used.

This defers the completion of static data members by caching them and complete them later

Are you sure that we need to complete static members at all?

Do you mean when completing class type, ignore those static members?

so ideally they would only be completed when they are actually used.

When will they be actually used?

This is what happens now: When TypeSystemClang::DeclContextFindDeclByName is used to find out a decl by name. It parses decls inside each TU until find a decl with the name. Then PdbAstBuilder will try to complete all types and cache them in that PDB file, because we can't filter types by TU.
D82160 also requires constant static member's type width to be known, but this happens when we try to complete the constant static member.

This defers the completion of static data members by caching them and complete them later

Are you sure that we need to complete static members at all?

Do you mean when completing class type, ignore those static members?

Yes.

so ideally they would only be completed when they are actually used.

When will they be actually used?

In the expression evaluator, for one. I'm not sure if there are any other cases.

This is what happens now: When TypeSystemClang::DeclContextFindDeclByName is used to find out a decl by name. It parses decls inside each TU until find a decl with the name. Then PdbAstBuilder will try to complete all types and cache them in that PDB file, because we can't filter types by TU.

I'm not very familiar with this stuff, but have you checked what dwarf would do under the same circumstances. I would be surprised if the answer is "it completes all static member types".

zequanwu added a comment.EditedMar 9 2022, 3:29 PM

In the expression evaluator, for one. I'm not sure if there are any other cases.

If we ignore static members when completing class types, we don't know if CompleteType is called for completing a static member whose type is the class or other cases. For example, when we want to complete the type of static members whose type is the class (e.g. A) itself during expression evaluation, we are trying to complete the class A, but we don't know if we should ignore its static members.

I'm not very familiar with this stuff, but have you checked what dwarf would do under the same circumstances. I would be surprised if the answer is "it completes all static member types".

I checked dwarf but still don't understand how it evaluates static members without going into the loop.

In the expression evaluator, for one. I'm not sure if there are any other cases.

If we ignore static members when completing class types, we don't know if CompleteType is called for completing a static member whose type is the class or other cases. For example, when we want to complete the type of static members whose type is the class (e.g. A) itself during expression evaluation, we are trying to complete the class A, but we don't know if we should ignore its static members.

I was imagining you would create the static member type as a forward decl -- create some ast like class Member { ... }; class StaticMember; class A { Member m; static StaticMember sm; };. And then you'd get a completion request for StaticMember when the type of A::sm is required.

I'm not very familiar with this stuff, but have you checked what dwarf would do under the same circumstances. I would be surprised if the answer is "it completes all static member types".

I checked dwarf but still don't understand how it evaluates static members without going into the loop.

I think that's because it creates them as forward declarations -- as I outlined above. DWARFASTParserClang::ParseTypeFromDWARF creates a forward-declared type, and ::CompleteTypeFromDwarf completes it. When parsing a class, the dwarf parser calls DWARFDIE::ResolveTypeUID (line 2673 of DWARFASTParserClang.cpp), which (after going through too many layers) ends up in DWARFASTParserClang::ParseTypeFromDWARF.

Also, note that the DWARF parser also has code which should prevent loops in regular members (which should only be possible for malformed inputs).

zequanwu updated this revision to Diff 414529.EditedMar 10 2022, 4:58 PM

We simply shouldn't complete the types of static members at all, which is how dwarf does it.
Their types are eventually completed when called by SymbolFile::CompleteType.

Herald added a project: Restricted Project. · View Herald TranscriptMar 10 2022, 4:58 PM
zequanwu retitled this revision from [LLDB][NativePDB] Fix infinite recursion when a class has static member with the class type. to [LLDB][NativePDB] Don't complete static members' types when completing a record type..Mar 10 2022, 5:03 PM
zequanwu edited the summary of this revision. (Show Details)

This is cool, just one question about the test.

lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp
8–26 ↗(On Diff #414529)

Would it be possible to put this into a new test case, one that does not require running the binary? If we're able to read global variables without a running process (we can do it with elf+dwarf, but I don't know what's the state with coff+pdb), then we could run this test on non-windows hosts as well (which is great for test coverage).

zequanwu updated this revision to Diff 415213.Mar 14 2022, 1:54 PM

Testing with image lookup -type

lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp
8–26 ↗(On Diff #414529)

Printing doesn't work with any expression involves :: in NativePDB. So, I changed the test to image lookup -type which also tries to complete given type.

labath added inline comments.Mar 15 2022, 1:56 AM
lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp
8–26 ↗(On Diff #414529)

That's cool, but I see the new test still has a REQUIRES: system-windows. Would it be possible to drop that requirement (if not, then why)?

zequanwu updated this revision to Diff 415501.Mar 15 2022, 10:48 AM
zequanwu marked an inline comment as done.

Remove REQUIRES: system-windows.

lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp
8–26 ↗(On Diff #414529)

This is not necessary. Removed.

labath accepted this revision.Mar 15 2022, 12:27 PM

awesome

This revision is now accepted and ready to land.Mar 15 2022, 12:27 PM