summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimm Bäder <tbaeder@redhat.com>2024-04-15 15:41:33 +0200
committerTimm Bäder <tbaeder@redhat.com>2024-04-16 13:04:28 +0200
commit32b74ca6e41768c91eee8b8ca26235b110a65deb (patch)
tree0f5001c99e1fe480c7ee8adc0cb9cef9f57b0a8d
parent36b3c26451bf9a42f0b6b415993d3942bb73abdd (diff)
[clang][Interp] Load value from MemberExpr if required
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp17
-rw-r--r--clang/test/AST/Interp/cxx03.cpp14
2 files changed, 28 insertions, 3 deletions
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index a069f3ec27e7..00c4a9f16130 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1272,12 +1272,23 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
if (DiscardResult)
return this->discard(Base);
+ // MemberExprs are almost always lvalues, in which case we don't need to
+ // do the load. But sometimes they aren't.
+ const auto maybeLoadValue = [&]() -> bool {
+ if (E->isGLValue())
+ return true;
+ if (std::optional<PrimType> T = classify(E))
+ return this->emitLoadPop(*T, E);
+ return false;
+ };
+
if (const auto *VD = dyn_cast<VarDecl>(Member)) {
// I am almost confident in saying that a var decl must be static
// and therefore registered as a global variable. But this will probably
// turn out to be wrong some time in the future, as always.
if (auto GlobalIndex = P.getGlobal(VD))
- return this->emitGetPtrGlobal(*GlobalIndex, E);
+ return this->emitGetPtrGlobal(*GlobalIndex, E) && maybeLoadValue();
+ return false;
}
if (Initializing) {
@@ -1295,8 +1306,8 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
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);
+ return this->emitGetFieldPop(PT_Ptr, F->Offset, E) && maybeLoadValue();
+ return this->emitGetPtrField(F->Offset, E) && maybeLoadValue();
}
return false;
diff --git a/clang/test/AST/Interp/cxx03.cpp b/clang/test/AST/Interp/cxx03.cpp
index d30cbb2fd7a2..b6aaf0840cfb 100644
--- a/clang/test/AST/Interp/cxx03.cpp
+++ b/clang/test/AST/Interp/cxx03.cpp
@@ -10,3 +10,17 @@ namespace NonInitializingMemberExpr {
// both-note {{required by}} \
// both-note {{subexpression not valid}}
}
+
+
+namespace NonLValueMemberExpr {
+ struct PODType {
+ int value;
+ };
+
+#define ATTR __attribute__((require_constant_initialization))
+ struct TT1 {
+ ATTR static const int &subobj_init;
+ };
+
+ const int &TT1::subobj_init = PODType().value;
+}