tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This is a result of the discussions in https://reviews.llvm.org/D141472 and https://reviews.llvm.org/D142630. We need to consider virtual functions when calling function pointers as well. Repository: rG LLVM Github Monorepo 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 @@ -488,6 +488,55 @@ constexpr SS ss; static_assert(ss.a == 1); } + +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 @@ -135,13 +135,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 @@ -1586,6 +1586,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 @@ -78,12 +78,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; @@ -123,9 +117,23 @@ if (T->isFloatingType()) return PT_Float; + if (T->isFunctionPointerType() || T->isFunctionReferenceType() || + T->isFunctionProtoType() || + T->isSpecificBuiltinType(BuiltinType::BoundMember)) + 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 @@ -211,6 +211,10 @@ std::optional<PrimType> LT = classify(LHS->getType()); std::optional<PrimType> RT = classify(RHS->getType()); std::optional<PrimType> T = classify(BO->getType()); + + if (BO->isPtrMemOp()) + return this->visit(RHS); + if (!LT || !RT || !T) { return this->bail(BO); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits