[Lldb-commits] [lldb] [LLDB] Fix `GetIndexOfChildMemberWithName` to handle anonymous struct in base classes (PR #158256)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 10 02:49:50 PDT 2025


https://github.com/Michael137 commented:

I have the suspicion that this could be done simpler.

`CXXRecordDecl::lookupInBases` is already perfectly capable of finding field in anonymous structures in bases. That's why the expression evaluator is able to find them just fine.

I think the actual problem lies in our logic that iterates the `CXXBasePaths` after the `lookupInBases` lookup.

The field of the anonymous structure *is found* by `lookupInBases`. It is an `IndirectFieldDecl`. But we fail to extract it in:
```
              for (clang::DeclContext::lookup_iterator I = path->Decls, E;
                   I != E; ++I) {
                child_idx = GetIndexForRecordChild(
                    parent_record_decl, *I, omit_empty_base_classes);
                if (child_idx == UINT32_MAX) {
                  child_indexes.clear();
                  return 0;
```

Here `GetIndexForRecordChild` doesn't correctly get the index of the `IndirectFieldDecl`:

```
   6702   clang::RecordDecl::field_iterator field, field_end;                                             
   6703   for (field = record_decl->field_begin(), field_end = record_decl->field_end();                  
   6704        field != field_end; ++field, ++child_idx) {                                                
-> 6705     if (field->getCanonicalDecl() == canonical_decl)                                              
   6706       return child_idx;                                                                           
   6707   }                                                                                               
   6708                                                                                                   
   6709   return UINT32_MAX;                                                                              
   6710 }                                                                                                 
   6711                                                                                                   
   6712 // Look for a child member (doesn't include base classes, but it does include                     
   6713 // their members) in the type hierarchy. Returns an index path into                               
   6714 // "clang_type" on how to reach the appropriate member.                                           
   6715 //                                                                                                
Target 0: (lldb) stopped.                                                                                 
(lldb) p field->getCanonicalDecl()->dump()                                                                
FieldDecl 0x7e9f01418 <<invalid sloc>> <invalid sloc> implicit 'Base::(anonymous struct)'                 
(lldb) p canonical_decl->dump()                                                                           
IndirectFieldDecl 0x7e9f014c8 <<invalid sloc>> <invalid sloc> implicit x 'int'                            
|-Field 0x7e9f01418 field_index 0 'Base::(anonymous struct)'                                              
`-Field 0x7e9f013c0 'x' 'int'                                                                             
```

I haven't fully thought this through, but could we adjust `GetIndexForRecordChild` to look into unwrap the anonymous union?

We can fish out the underlying `FieldDecl`s in both cases:
```
(lldb) p ((clang::IndirectFieldDecl*)canonical_decl)->getAnonField()
(clang::FieldDecl *) 0x0000000c563293c0
(lldb) p field->getType()->getAsCXXRecordDecl()->field_begin()
(clang::RecordDecl::field_iterator) {
  Current = {
    Current = 0x0000000c563293c0
  }
}
(lldb) p field->getType()->getAsCXXRecordDecl()->field_begin()->dump()
FieldDecl 0xc563293c0 <<invalid sloc>> <invalid sloc> x 'int'
```

So in pseudo-code, maybe the function could look something like:
```
uint32_t TypeSystemClang::GetIndexForRecordChild(
    const clang::RecordDecl *record_decl, clang::NamedDecl *canonical_decl,
    bool omit_empty_base_classes) {
  uint32_t child_idx = TypeSystemClang::GetNumBaseClasses(
      llvm::dyn_cast<clang::CXXRecordDecl>(record_decl),
      omit_empty_base_classes);

  clang::RecordDecl::field_iterator field, field_end;
  for (field = record_decl->field_begin(), field_end = record_decl->field_end();
       field != field_end; ++field, ++child_idx) {
    IndirectFieldDecl * indirect_decl = llvm::dyn_cast<IndirectFieldDecl>(canonical_decl);
    if (field is unnamed && indirect_decl) {
      for (anon_field : fields of anonymous structure)
         if (anon_field == canonical_decl->getAnonField())
            return child_idx;
    } else if (field == canonical_decl)
      return child_idx;
  }

  return UINT32_MAX;
}
```
Might need to adjust the `child_idx` calculation here. But hopefully that conveys the overall idea.

Let me know if you have any questions or if you think this doesn't work

https://github.com/llvm/llvm-project/pull/158256


More information about the lldb-commits mailing list