Skip to content

Commit 0b8acc0

Browse files
committed
[clang][Interp] Improve APValue machinery
Handle lvalues pointing to declarations, unions and member pointers.
1 parent ec94e7a commit 0b8acc0

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3218,9 +3218,18 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
32183218
return this->emitConst(Val.getInt(), ValType, E);
32193219

32203220
if (Val.isLValue()) {
3221+
if (Val.isNullPointer())
3222+
return this->emitNull(ValType, nullptr, E);
32213223
APValue::LValueBase Base = Val.getLValueBase();
32223224
if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
32233225
return this->visit(BaseExpr);
3226+
else if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) {
3227+
return this->visitDeclRef(VD, E);
3228+
}
3229+
} else if (Val.isMemberPointer()) {
3230+
if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl())
3231+
return this->emitGetMemberPtr(MemberDecl, E);
3232+
return this->emitNullMemberPtr(nullptr, E);
32243233
}
32253234

32263235
return false;
@@ -3229,15 +3238,15 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
32293238
template <class Emitter>
32303239
bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
32313240
const Expr *E) {
3241+
32323242
if (Val.isStruct()) {
32333243
const Record *R = this->getRecord(E->getType());
32343244
assert(R);
3235-
32363245
for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
32373246
const APValue &F = Val.getStructField(I);
32383247
const Record::Field *RF = R->getField(I);
32393248

3240-
if (F.isInt() || F.isLValue()) {
3249+
if (F.isInt() || F.isLValue() || F.isMemberPointer()) {
32413250
PrimType T = classifyPrim(RF->Decl->getType());
32423251
if (!this->visitAPValue(F, T, E))
32433252
return false;
@@ -3263,11 +3272,30 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
32633272

32643273
if (!this->emitPopPtr(E))
32653274
return false;
3275+
} else if (F.isStruct() || F.isUnion()) {
3276+
if (!this->emitDupPtr(E))
3277+
return false;
3278+
if (!this->emitGetPtrField(RF->Offset, E))
3279+
return false;
3280+
if (!this->visitAPValueInitializer(F, E))
3281+
return false;
3282+
if (!this->emitPopPtr(E))
3283+
return false;
32663284
} else {
32673285
assert(false && "I don't think this should be possible");
32683286
}
32693287
}
32703288
return true;
3289+
} else if (Val.isUnion()) {
3290+
const FieldDecl *UnionField = Val.getUnionField();
3291+
const Record *R = this->getRecord(UnionField->getParent());
3292+
assert(R);
3293+
const APValue &F = Val.getUnionValue();
3294+
const Record::Field *RF = R->getField(UnionField);
3295+
PrimType T = classifyPrim(RF->Decl->getType());
3296+
if (!this->visitAPValue(F, T, E))
3297+
return false;
3298+
return this->emitInitElem(T, 0, E);
32713299
}
32723300
// TODO: Other types.
32733301

@@ -3827,12 +3855,10 @@ bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator(
38273855
}
38283856

38293857
template <class Emitter>
3830-
bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
3858+
bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
38313859
if (DiscardResult)
38323860
return true;
38333861

3834-
const auto *D = E->getDecl();
3835-
38363862
if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
38373863
return this->emitConst(ECD->getInitVal(), E);
38383864
} else if (const auto *BD = dyn_cast<BindingDecl>(D)) {
@@ -3900,7 +3926,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
39003926
if (!this->visitVarDecl(VD))
39013927
return false;
39023928
// Retry.
3903-
return this->VisitDeclRefExpr(E);
3929+
return this->visitDeclRef(VD, E);
39043930
}
39053931
}
39063932
} else {
@@ -3910,7 +3936,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
39103936
if (!this->visitVarDecl(VD))
39113937
return false;
39123938
// Retry.
3913-
return this->VisitDeclRefExpr(E);
3939+
return this->visitDeclRef(VD, E);
39143940
}
39153941
}
39163942

@@ -3927,7 +3953,15 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
39273953
return true;
39283954
}
39293955

3930-
return this->emitInvalidDeclRef(E, E);
3956+
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
3957+
return this->emitInvalidDeclRef(DRE, E);
3958+
return false;
3959+
}
3960+
3961+
template <class Emitter>
3962+
bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
3963+
const auto *D = E->getDecl();
3964+
return this->visitDeclRef(D, E);
39313965
}
39323966

39333967
template <class Emitter>

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
189189
/// Visit an APValue.
190190
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
191191
bool visitAPValueInitializer(const APValue &Val, const Expr *E);
192+
/// Visit the given decl as if we have a reference to it.
193+
bool visitDeclRef(const ValueDecl *D, const Expr *E);
192194

193195
/// Visits an expression and converts it to a boolean.
194196
bool visitBool(const Expr *E);

clang/test/AST/Interp/cxx20.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,3 +774,11 @@ void overflowInSwitchCase(int n) {
774774
break;
775775
}
776776
}
777+
778+
namespace APValues {
779+
int g;
780+
struct A { union { int n, m; }; int *p; int A::*q; char buffer[32]; };
781+
template<A a> constexpr const A &get = a;
782+
constexpr const A &v = get<A{}>;
783+
constexpr const A &w = get<A{1, &g, &A::n, "hello"}>;
784+
}

0 commit comments

Comments
 (0)