imkiva wrote:

@Michael137 Thanks for the explanation, you’re right. 
I first updated `GetIndexForRecordChild` following the your pseudo-code like:

```c++

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) {
    if (auto *indirect_decl = 
llvm::dyn_cast<clang::IndirectFieldDecl>(canonical_decl)) {
      // Only meaningful when iterating over the anonymous aggregate slot.
      if (field->isAnonymousStructOrUnion()) {
        const clang::FieldDecl *anon_aggregate = nullptr;
        for (clang::NamedDecl *ND : indirect_decl->chain()) {
          if (auto *FD = llvm::dyn_cast<clang::FieldDecl>(ND)) {
            if (FD->isAnonymousStructOrUnion() && FD->getDeclContext() == 
record_decl) {
              anon_aggregate = FD;
              break;
            }
          }
        }
        if (anon_aggregate && field->getCanonicalDecl() == 
anon_aggregate->getCanonicalDecl())
          return child_idx;
      }
    } else if (field->getCanonicalDecl() == canonical_decl)
      return child_idx;
  }

  return UINT32_MAX;
}
```

However, I later realized the returned child_idx points to the anonymous 
aggregate in the base, not to the member within that aggregate. That’s why:
```
>>> d = lldb.frame.EvaluateExpression("d")
>>> d.GetChildMemberWithName("b")
(int) b = 1
>>> d.GetChildMemberWithName("x")
(Base::(anonymous struct)) = (x = 2)   <<- expected to be (int) x = 2
```

To address this, I added an overload of `GetIndexForRecordChild` that accepts:
- a `check_anonymous_bases` flag to decide whether to look inside anonymous 
aggregates, and
- an output pair `(outer_idx, inner_idx)` in the `IndirectFieldDecl` case so we 
can return the inner slot for the actual member.

Regarding the concern about breaking existing scripts: the original 
`GetIndexForRecordChild` remains and now forwards to the new overload with 
`check_anonymous_bases = false`, always returning `outer_idx`. This preserves 
the previous behavior by default, while callers that want to land on the 
concrete field (e.g., x) can opt into the new semantics and push both indices.



https://github.com/llvm/llvm-project/pull/158256
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to