diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 6999fee64b655..bc14bd3d1bb99 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1646,8 +1646,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, const auto *StaticDecl = cast(Func->getParentDecl()); const auto *InitialFunction = cast(Callee); - const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( - DynamicDecl, StaticDecl, InitialFunction); + const CXXMethodDecl *Overrider; + + if (StaticDecl != DynamicDecl) { + if (!DynamicDecl->isDerivedFrom(StaticDecl)) + return false; + Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl, + InitialFunction); + + } else { + Overrider = InitialFunction; + } if (Overrider != InitialFunction) { // DR1872: An instantiated virtual constexpr function can't be called in a diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 5c17a14082672..0d3f492f0fcca 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -3201,6 +3201,9 @@ inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) { inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) { const auto &MP = S.Stk.pop(); + if (!MP.isBaseCastPossible()) + return false; + S.Stk.push(MP.getBase()); return true; } diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h index b17ce256e75e2..8dd75cad092c0 100644 --- a/clang/lib/AST/ByteCode/MemberPointer.h +++ b/clang/lib/AST/ByteCode/MemberPointer.h @@ -51,6 +51,12 @@ class MemberPointer final { FunctionPointer toFunctionPointer(const Context &Ctx) const; + bool isBaseCastPossible() const { + if (PtrOffset < 0) + return true; + return static_cast(PtrOffset) <= Base.getByteOffset(); + } + Pointer getBase() const { if (PtrOffset < 0) return Base.atField(-PtrOffset); diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp index 7aecf23b0f149..08caca03b8056 100644 --- a/clang/test/AST/ByteCode/cxx11.cpp +++ b/clang/test/AST/ByteCode/cxx11.cpp @@ -330,3 +330,33 @@ namespace ReadMutableInCopyCtor { // both-note {{read of mutable member 'u'}} \ // both-note {{in call to 'G(g1)'}} } + +namespace GH150709 { + struct C { }; + struct D : C { + constexpr int f() const { return 1; }; + }; + struct E : C { }; + struct F : D { }; + struct G : E { }; + + constexpr C c1, c2[2]; + constexpr D d1, d2[2]; + constexpr E e1, e2[2]; + constexpr F f; + constexpr G g; + + constexpr auto mp = static_cast(&D::f); + + // sanity checks for fix of GH150709 (unchanged behavior) + static_assert((c1.*mp)() == 1, ""); // both-error {{constant expression}} + static_assert((d1.*mp)() == 1, ""); + static_assert((f.*mp)() == 1, ""); + static_assert((c2[0].*mp)() == 1, ""); // ref-error {{constant expression}} + static_assert((d2[0].*mp)() == 1, ""); + + // incorrectly undiagnosed before fix of GH150709 + static_assert((e1.*mp)() == 1, ""); // ref-error {{constant expression}} + static_assert((e2[0].*mp)() == 1, ""); // ref-error {{constant expression}} + static_assert((g.*mp)() == 1, ""); // ref-error {{constant expression}} +} diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp index ac2f9883d49b6..744c99eaa1e68 100644 --- a/clang/test/AST/ByteCode/cxx2a.cpp +++ b/clang/test/AST/ByteCode/cxx2a.cpp @@ -225,3 +225,17 @@ namespace Dtor { static_assert(pseudo(true, false)); // both-error {{constant expression}} both-note {{in call}} static_assert(pseudo(false, true)); } + +namespace GH150705 { + struct A { }; + struct B : A { }; + struct C : A { + constexpr virtual int foo() const { return 0; } + }; + + constexpr auto p = &C::foo; + constexpr auto q = static_cast(p); + constexpr B b; + constexpr const A& a = b; + constexpr auto x = (a.*q)(); // both-error {{constant expression}} +}