[clang] [clang][bytecode] Handle more invalid member pointer casts (PR #152546)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 7 09:28:55 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/152546.diff
5 Files Affected:
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+11-2)
- (modified) clang/lib/AST/ByteCode/Interp.h (+3)
- (modified) clang/lib/AST/ByteCode/MemberPointer.h (+6)
- (modified) clang/test/AST/ByteCode/cxx11.cpp (+30)
- (modified) clang/test/AST/ByteCode/cxx2a.cpp (+14)
``````````diff
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<CXXRecordDecl>(Func->getParentDecl());
const auto *InitialFunction = cast<CXXMethodDecl>(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<MemberPointer>();
+ if (!MP.isBaseCastPossible())
+ return false;
+
S.Stk.push<Pointer>(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<uint64_t>(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<int (C::*)() const>(&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<int (A::*)() const>(p);
+ constexpr B b;
+ constexpr const A& a = b;
+ constexpr auto x = (a.*q)(); // both-error {{constant expression}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/152546
More information about the cfe-commits
mailing list