[clang] 0b8acc0 - [clang][Interp] Improve APValue machinery
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 6 23:17:08 PDT 2024
Author: Timm Bäder
Date: 2024-06-07T08:16:39+02:00
New Revision: 0b8acc06c42df9d444f669fff312fffffcacdfb9
URL: https://github.com/llvm/llvm-project/commit/0b8acc06c42df9d444f669fff312fffffcacdfb9
DIFF: https://github.com/llvm/llvm-project/commit/0b8acc06c42df9d444f669fff312fffffcacdfb9.diff
LOG: [clang][Interp] Improve APValue machinery
Handle lvalues pointing to declarations, unions and member pointers.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/test/AST/Interp/cxx20.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d124248a3605f..9073175263645 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -3218,9 +3218,18 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
return this->emitConst(Val.getInt(), ValType, E);
if (Val.isLValue()) {
+ if (Val.isNullPointer())
+ return this->emitNull(ValType, nullptr, E);
APValue::LValueBase Base = Val.getLValueBase();
if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
return this->visit(BaseExpr);
+ else if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) {
+ return this->visitDeclRef(VD, E);
+ }
+ } else if (Val.isMemberPointer()) {
+ if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl())
+ return this->emitGetMemberPtr(MemberDecl, E);
+ return this->emitNullMemberPtr(nullptr, E);
}
return false;
@@ -3229,15 +3238,15 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
const Expr *E) {
+
if (Val.isStruct()) {
const Record *R = this->getRecord(E->getType());
assert(R);
-
for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
const APValue &F = Val.getStructField(I);
const Record::Field *RF = R->getField(I);
- if (F.isInt() || F.isLValue()) {
+ if (F.isInt() || F.isLValue() || F.isMemberPointer()) {
PrimType T = classifyPrim(RF->Decl->getType());
if (!this->visitAPValue(F, T, E))
return false;
@@ -3263,11 +3272,30 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
if (!this->emitPopPtr(E))
return false;
+ } else if (F.isStruct() || F.isUnion()) {
+ if (!this->emitDupPtr(E))
+ return false;
+ if (!this->emitGetPtrField(RF->Offset, E))
+ return false;
+ if (!this->visitAPValueInitializer(F, E))
+ return false;
+ if (!this->emitPopPtr(E))
+ return false;
} else {
assert(false && "I don't think this should be possible");
}
}
return true;
+ } else if (Val.isUnion()) {
+ const FieldDecl *UnionField = Val.getUnionField();
+ const Record *R = this->getRecord(UnionField->getParent());
+ assert(R);
+ const APValue &F = Val.getUnionValue();
+ const Record::Field *RF = R->getField(UnionField);
+ PrimType T = classifyPrim(RF->Decl->getType());
+ if (!this->visitAPValue(F, T, E))
+ return false;
+ return this->emitInitElem(T, 0, E);
}
// TODO: Other types.
@@ -3827,12 +3855,10 @@ bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator(
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
if (DiscardResult)
return true;
- const auto *D = E->getDecl();
-
if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
return this->emitConst(ECD->getInitVal(), E);
} else if (const auto *BD = dyn_cast<BindingDecl>(D)) {
@@ -3900,7 +3926,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
if (!this->visitVarDecl(VD))
return false;
// Retry.
- return this->VisitDeclRefExpr(E);
+ return this->visitDeclRef(VD, E);
}
}
} else {
@@ -3910,7 +3936,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
if (!this->visitVarDecl(VD))
return false;
// Retry.
- return this->VisitDeclRefExpr(E);
+ return this->visitDeclRef(VD, E);
}
}
@@ -3927,7 +3953,15 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
return true;
}
- return this->emitInvalidDeclRef(E, E);
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return this->emitInvalidDeclRef(DRE, E);
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+ const auto *D = E->getDecl();
+ return this->visitDeclRef(D, E);
}
template <class Emitter>
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 44c495240289f..7ab14b6ab383e 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -189,6 +189,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
/// Visit an APValue.
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
bool visitAPValueInitializer(const APValue &Val, const Expr *E);
+ /// Visit the given decl as if we have a reference to it.
+ bool visitDeclRef(const ValueDecl *D, const Expr *E);
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index 000ffe39eb94a..49ee040be392e 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -774,3 +774,11 @@ void overflowInSwitchCase(int n) {
break;
}
}
+
+namespace APValues {
+ int g;
+ struct A { union { int n, m; }; int *p; int A::*q; char buffer[32]; };
+ template<A a> constexpr const A &get = a;
+ constexpr const A &v = get<A{}>;
+ constexpr const A &w = get<A{1, &g, &A::n, "hello"}>;
+}
More information about the cfe-commits
mailing list