[clang][Interp] Fix record members of reference type

When assigning to them, we can't classify the expression type, because
that doesn't contain the right information.

And when reading from them, we need to do the extra deref, just like we
do when reading from a DeclRefExpr.

Differential Revision: https://reviews.llvm.org/D136012
This commit is contained in:
Timm Bäder 2022-10-15 09:22:34 +02:00
parent 8b87cb4853
commit 0ccff030f3
4 changed files with 34 additions and 2 deletions

View File

@ -343,6 +343,8 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
const Record *R = getRecord(RD);
const Record::Field *F = R->getField(FD);
// Leave a pointer to the field on the stack.
if (F->Decl->getType()->isReferenceType())
return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
return this->emitGetPtrField(F->Offset, E);
}
@ -809,7 +811,7 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
if (!this->emitDupPtr(Initializer))
return false;
if (Optional<PrimType> T = classify(Init->getType())) {
if (Optional<PrimType> T = classify(Init)) {
if (!this->visit(Init))
return false;

View File

@ -105,7 +105,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
if (const FieldDecl *Member = Init->getMember()) {
const Record::Field *F = R->getField(Member);
if (Optional<PrimType> T = this->classify(InitExpr->getType())) {
if (Optional<PrimType> T = this->classify(InitExpr)) {
if (!this->emitThis(InitExpr))
return false;

View File

@ -470,6 +470,8 @@ bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
/// 1) Peeks a pointer on the stack
/// 2) Pushes the value of the pointer's field on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Obj = S.Stk.peek<Pointer>();
@ -499,6 +501,8 @@ bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
/// 1) Pops a pointer from the stack
/// 2) Pushes the value of the pointer's field on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Obj = S.Stk.pop<Pointer>();

View File

@ -88,3 +88,29 @@ constexpr int RefToMemberExpr() {
return j;
}
static_assert(RefToMemberExpr() == 11, "");
struct Ref {
int &a;
};
constexpr int RecordWithRef() {
int m = 100;
Ref r{m};
m = 200;
return r.a;
}
static_assert(RecordWithRef() == 200, "");
struct Ref2 {
int &a;
constexpr Ref2(int &a) : a(a) {}
};
constexpr int RecordWithRef2() {
int m = 100;
Ref2 r(m);
m = 200;
return r.a;
}
static_assert(RecordWithRef2() == 200, "");