tbaeder updated this revision to Diff 542762.
tbaeder marked 2 inline comments as done.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D144164/new/
https://reviews.llvm.org/D144164
Files:
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
Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -689,5 +689,52 @@
// 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
Index: clang/test/AST/Interp/literals.cpp
===================================================================
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -149,13 +149,10 @@
// 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), "");
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -1716,6 +1716,9 @@
if (!F || !F->isConstexpr())
return false;
+ if (F->isVirtual())
+ return CallVirt(S, OpPC, F);
+
return Call(S, OpPC, F);
}
Index: clang/lib/AST/Interp/Context.cpp
===================================================================
--- clang/lib/AST/Interp/Context.cpp
+++ clang/lib/AST/Interp/Context.cpp
@@ -88,12 +88,6 @@
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 @@
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 {};
}
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -207,13 +207,13 @@
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 @@
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))
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits