================
@@ -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