[clang] 8cb6e47 - [clang][Interp] Handle PtrMemOps
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 25 22:05:55 PDT 2023
Author: Timm Bäder
Date: 2023-07-26T07:04:21+02:00
New Revision: 8cb6e476ccaa62b2621a5f68689a6070592f221d
URL: https://github.com/llvm/llvm-project/commit/8cb6e476ccaa62b2621a5f68689a6070592f221d
DIFF: https://github.com/llvm/llvm-project/commit/8cb6e476ccaa62b2621a5f68689a6070592f221d.diff
LOG: [clang][Interp] Handle PtrMemOps
Differential Revision: https://reviews.llvm.org/D144164
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Context.cpp
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/literals.cpp
clang/test/AST/Interp/records.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 9f3eb158576fd8..d2995fb57d8bef 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -207,13 +207,13 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
const Expr *LHS = BO->getLHS();
const Expr *RHS = BO->getRHS();
+ if (BO->isPtrMemOp())
+ return this->visit(RHS);
+
// Typecheck the args.
std::optional<PrimType> LT = classify(LHS->getType());
std::optional<PrimType> RT = classify(RHS->getType());
std::optional<PrimType> T = classify(BO->getType());
- if (!LT || !RT || !T) {
- return this->bail(BO);
- }
auto Discard = [this, T, BO](bool Result) {
if (!Result)
@@ -228,6 +228,9 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
return Discard(this->visit(RHS));
}
+ if (!LT || !RT || !T)
+ return this->bail(BO);
+
// Pointer arithmetic special case.
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr))
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index eeb7fa9379f5cc..2e5d721590edc6 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -88,12 +88,6 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
std::optional<PrimType> Context::classify(QualType T) const {
- if (T->isFunctionPointerType() || T->isFunctionReferenceType())
- return PT_FnPtr;
-
- if (T->isReferenceType() || T->isPointerType())
- return PT_Ptr;
-
if (T->isBooleanType())
return PT_Bool;
@@ -133,9 +127,22 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isFloatingType())
return PT_Float;
+ if (T->isFunctionPointerType() || T->isFunctionReferenceType() ||
+ T->isFunctionType())
+ return PT_FnPtr;
+
+ if (T->isReferenceType() || T->isPointerType())
+ return PT_Ptr;
+
if (auto *AT = dyn_cast<AtomicType>(T))
return classify(AT->getValueType());
+ if (auto *DT = dyn_cast<DecltypeType>(T))
+ return classify(DT->getUnderlyingType());
+
+ if (auto *DT = dyn_cast<MemberPointerType>(T))
+ return classify(DT->getPointeeType());
+
return {};
}
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index ff67e873a08445..0acaf764353215 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1716,6 +1716,9 @@ inline bool CallPtr(InterpState &S, CodePtr OpPC) {
if (!F || !F->isConstexpr())
return false;
+ if (F->isVirtual())
+ return CallVirt(S, OpPC, F);
+
return Call(S, OpPC, F);
}
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index b9d1d2d59d11a3..5df7b7e5e6e8b0 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -149,13 +149,10 @@ namespace SizeOf {
// ref-error{{to a function type}}
-
- /// FIXME: The following code should be accepted.
struct S {
void func();
};
- constexpr void (S::*Func)() = &S::func; // expected-error {{must be initialized by a constant expression}} \
- // expected-error {{interpreter failed to evaluate an expression}}
+ constexpr void (S::*Func)() = &S::func;
static_assert(sizeof(Func) == sizeof(&S::func), "");
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 5fd423eff025be..fcdf75cfa9502b 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -689,5 +689,52 @@ namespace CtorDtor {
// ref-note {{initializer of 'D2' is not a constant expression}}
}
+
+namespace VirtualFunctionPointers {
+ struct S {
+ virtual constexpr int func() const { return 1; }
+ };
+
+ struct Middle : S {
+ constexpr Middle(int i) : i(i) {}
+ int i;
+ };
+
+ struct Other {
+ constexpr Other(int k) : k(k) {}
+ int k;
+ };
+
+ struct S2 : Middle, Other {
+ int j;
+ constexpr S2(int i, int j, int k) : Middle(i), Other(k), j(j) {}
+ virtual constexpr int func() const { return i + j + k + S::func(); }
+ };
+
+ constexpr S s;
+ constexpr decltype(&S::func) foo = &S::func;
+ constexpr int value = (s.*foo)();
+ static_assert(value == 1);
+
+
+ constexpr S2 s2(1, 2, 3);
+ static_assert(s2.i == 1);
+ static_assert(s2.j == 2);
+ static_assert(s2.k == 3);
+
+ constexpr int value2 = s2.func();
+ constexpr int value3 = (s2.*foo)();
+ static_assert(value3 == 7);
+
+ constexpr int dynamicDispatch(const S &s) {
+ constexpr decltype(&S::func) SFunc = &S::func;
+
+ return (s.*SFunc)();
+ }
+
+ static_assert(dynamicDispatch(s) == 1);
+ static_assert(dynamicDispatch(s2) == 7);
+};
+
};
#endif
More information about the cfe-commits
mailing list