Skip to content

Commit 0ccff03

Browse files
committed
[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
1 parent 8b87cb4 commit 0ccff03

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

Diff for: clang/lib/AST/Interp/ByteCodeExprGen.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
343343
const Record *R = getRecord(RD);
344344
const Record::Field *F = R->getField(FD);
345345
// Leave a pointer to the field on the stack.
346+
if (F->Decl->getType()->isReferenceType())
347+
return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
346348
return this->emitGetPtrField(F->Offset, E);
347349
}
348350

@@ -809,7 +811,7 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
809811
if (!this->emitDupPtr(Initializer))
810812
return false;
811813

812-
if (Optional<PrimType> T = classify(Init->getType())) {
814+
if (Optional<PrimType> T = classify(Init)) {
813815
if (!this->visit(Init))
814816
return false;
815817

Diff for: clang/lib/AST/Interp/ByteCodeStmtGen.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
105105
if (const FieldDecl *Member = Init->getMember()) {
106106
const Record::Field *F = R->getField(Member);
107107

108-
if (Optional<PrimType> T = this->classify(InitExpr->getType())) {
108+
if (Optional<PrimType> T = this->classify(InitExpr)) {
109109
if (!this->emitThis(InitExpr))
110110
return false;
111111

Diff for: clang/lib/AST/Interp/Interp.h

+4
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
470470
return true;
471471
}
472472

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

504+
/// 1) Pops a pointer from the stack
505+
/// 2) Pushes the value of the pointer's field on the stack
502506
template <PrimType Name, class T = typename PrimConv<Name>::T>
503507
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
504508
const Pointer &Obj = S.Stk.pop<Pointer>();

Diff for: clang/test/AST/Interp/references.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,29 @@ constexpr int RefToMemberExpr() {
8888
return j;
8989
}
9090
static_assert(RefToMemberExpr() == 11, "");
91+
92+
struct Ref {
93+
int &a;
94+
};
95+
96+
constexpr int RecordWithRef() {
97+
int m = 100;
98+
Ref r{m};
99+
m = 200;
100+
return r.a;
101+
}
102+
static_assert(RecordWithRef() == 200, "");
103+
104+
105+
struct Ref2 {
106+
int &a;
107+
constexpr Ref2(int &a) : a(a) {}
108+
};
109+
110+
constexpr int RecordWithRef2() {
111+
int m = 100;
112+
Ref2 r(m);
113+
m = 200;
114+
return r.a;
115+
}
116+
static_assert(RecordWithRef2() == 200, "");

0 commit comments

Comments
 (0)