================
@@ -479,24 +479,109 @@ til::SExpr *SExprBuilder::translateDeclRefExpr(const 
DeclRefExpr *DRE,
   if (const auto *VarD = dyn_cast<VarDecl>(VD))
     return translateVariable(VarD, Ctx);
 
+  // A member named through anonymous structs/unions is an IndirectFieldDecl;
+  // name it by its field.
+  const auto *IFD = dyn_cast<IndirectFieldDecl>(VD);
+  if (IFD)
+    VD = IFD->getAnonField();
+
   // FIXME: A FieldDecl reached via a DeclRefExpr should ideally be modelled as
   // a MemberExpr with an artificial self in the AST (e.g. ImplicitThisExpr as 
a
   // C equivalent of CXXThisExpr). Until such AST support is available, project
   // the field on the current SelfArg, so implicit member references in C and 
in
-  // parameter attributes are not lost.
-  if (const auto *FD = dyn_cast<FieldDecl>(VD); FD && Ctx && Ctx->SelfArg) {
-    til::SExpr *BE = translateCXXThisExpr(nullptr, Ctx);
-    til::SExpr *E = new (Arena) til::SApply(BE);
-    til::Project *P = new (Arena) til::Project(E, FD);
-    if (hasAnyPointerType(BE))
-      P->setArrow(true);
-    return P;
+  // parameter attributes are not lost. (A chain rooted in a VarDecl, from a
+  // namespace-scope anonymous union, is a named object instead.)
+  if (const auto *FD = dyn_cast<FieldDecl>(VD);
+      FD && Ctx && Ctx->SelfArg && !(IFD && IFD->getVarDecl())) {
+    // Project each anonymous member of the chain in turn.
+    SmallVector<const FieldDecl *> Chain;
+    if (IFD)
+      for (const NamedDecl *ND : IFD->chain())
+        Chain.push_back(cast<FieldDecl>(ND));
+    else
+      Chain.push_back(FD);
+    bool Found;
+    til::SExpr *E = translateFieldOwner(Chain.front()->getParent(), Ctx, 
Found);
+    til::Project *P = nullptr;
+    for (const FieldDecl *Member : Chain)
+      E = P = translateProject(E, Member);
+    assert(P && "a field or a non-empty chain");
+    // Say whose field this is when self does not have it.
+    P->setQualified(!Found);
+    return E;
   }
 
   // For non-local variables, treat it as a reference to a named object.
   return new (Arena) til::LiteralPtr(VD);
 }
 
+/// Translate the object owning \p Owner's field that an attribute names 
without
+/// a base expression. Normally that is the self argument, the object whose
+/// member carries the attribute. But a field of an enclosing record may be
+/// named from a nested one, anonymous or named, so walk out of the subobject
+/// accesses reaching self (members, array elements, `*`, and `&` back from a
+/// pointer to the object it points to) to the nearest object of type \p Owner,
+/// or derived from it. A pointer member's pointee is not part of the object, 
so
+/// the walk stops at one. Keep self if there is none, and clear \p Found.
+til::SExpr *SExprBuilder::translateFieldOwner(const RecordDecl *Owner,
+                                              CallingContext *Ctx,
+                                              bool &Found) {
+  // An already translated self has no type to check; take it as the owner.
+  Found = true;
+  const auto *SelfArg = dyn_cast_if_present<const Expr *>(Ctx->SelfArg);
+  if (!SelfArg)
+    return translateCXXThisExpr(nullptr, Ctx);
+  Found = false;
+  for (const Expr *E = SelfArg;;) {
+    // Up to casts, E is either the object or a pointer to it.
+    const Expr *Inner = E->IgnoreParenImpCasts();
+    QualType T = Inner->getType();
+    bool Pointer = T->isAnyPointerType();
+    if (Pointer)
----------------
melver wrote:

E->IgnoreParenImpCasts() strips CK_ArrayToPointerDecay, so when an array of 
records is accessed via -> (e.g., m->narr->nx or narr->nx), Inner->getType() is 
the ArrayType (struct Named[2]) rather than struct Named *. Because Pointer is 
false and T->getAsRecordDecl() returns nullptr on an ArrayType, 
translateFieldOwner fails to match Owner when Owner is struct Named itself:

* For m->narr->nx where nx is guarded by Named::nmu (a field of the same struct 
Named), Found becomes false, regressing the diagnostic from 'm->narr->nmu' to 
'm->narr->Named::nmu'.
* For m->narr->in.nx where in is a nested struct inside struct Named and nx is 
guarded by Named::nmu, translateFieldOwner walks past m->narr without matching 
struct Named and leaves SelfArg at m->narr->in, causing a false positive 
('m->narr->in.Named::nmu') even when m->narr->nmu is held.

Unwrapping the array element type when !Pointer fixes both cases (for 
m->narr[1].nx, iteration 1 already checks m->narr[1] of type struct Named 
before stepping into ASE->getBase()):

```
         const Expr *Inner = E->IgnoreParenImpCasts();
         QualType T = Inner->getType();
         bool Pointer = T->isAnyPointerType();
         if (Pointer)
           T = T->getPointeeType();
    +    else if (const auto *AT = T->getAsArrayTypeUnsafe())
    +      T = AT->getElementType();
         if (const auto *RD = T->getAsRecordDecl()) {
```

Add test case for this, too.

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

Reply via email to