Skip to content

Commit 16b4c18

Browse files
committed
[clang] Fix constant evaluation of member pointer access to member of sibling class.
HandleMemberPointerAccess considered whether the lvalue path in a member pointer access matched the bases of the containing class of the member, but neglected to check the same for the containing class of the member itself, thereby ignoring access attempts to members in direct sibling classes. Fixes #150705. Fixes #150709.
1 parent 0954cf1 commit 16b4c18

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5051,6 +5051,16 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
50515051
return nullptr;
50525052
}
50535053
}
5054+
// Consider member in a sibling.
5055+
const CXXRecordDecl *LastLVDecl =
5056+
(PathLengthToMember > LV.Designator.MostDerivedPathLength)
5057+
? getAsBaseClass(LV.Designator.Entries[PathLengthToMember - 1])
5058+
: LV.Designator.MostDerivedType->getAsCXXRecordDecl();
5059+
const CXXRecordDecl *LastMPDecl = MemPtr.getContainingRecord();
5060+
if (LastLVDecl->getCanonicalDecl() != LastMPDecl->getCanonicalDecl()) {
5061+
Info.FFDiag(RHS);
5062+
return nullptr;
5063+
}
50545064

50555065
// Truncate the lvalue to the appropriate derived class.
50565066
if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(),

clang/test/SemaCXX/constant-expression-cxx11.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,24 @@ namespace MemberPointer {
12101210
return (a.*f)();
12111211
}
12121212
static_assert(apply(A(2), &A::f) == 5, "");
1213+
1214+
struct C { };
1215+
struct D : C {
1216+
constexpr int f() const { return 1; };
1217+
};
1218+
struct E : C { };
1219+
struct F : D { };
1220+
constexpr C c1, c2[2];
1221+
constexpr D d1, d2[2];
1222+
constexpr E e1, e2[2];
1223+
constexpr F f;
1224+
static_assert((c1.*(static_cast<int (C::*)() const>(&D::f)))() == 1, ""); // expected-error {{constant expression}}
1225+
static_assert((d1.*(static_cast<int (C::*)() const>(&D::f)))() == 1, "");
1226+
static_assert((e1.*(static_cast<int (C::*)() const>(&D::f)))() == 1, ""); // expected-error {{constant expression}}
1227+
static_assert((f.*(static_cast<int (C::*)() const>(&D::f)))() == 1, "");
1228+
static_assert((c2[0].*(static_cast<int (C::*)() const>(&D::f)))() == 1, ""); // expected-error {{constant expression}}
1229+
static_assert((d2[0].*(static_cast<int (C::*)() const>(&D::f)))() == 1, "");
1230+
static_assert((e2[0].*(static_cast<int (C::*)() const>(&D::f)))() == 1, ""); // expected-error {{constant expression}}
12131231
}
12141232

12151233
namespace ArrayBaseDerived {

clang/test/SemaCXX/constant-expression-cxx2a.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,3 +1497,16 @@ namespace GH67317 {
14971497
// expected-note {{subobject of type 'const unsigned char' is not initialized}}
14981498
__builtin_bit_cast(unsigned char, *new char[3][1]);
14991499
};
1500+
1501+
namespace GH150705 {
1502+
struct A { };
1503+
struct B : A { };
1504+
struct C : A {
1505+
constexpr virtual int foo() const { return 0; }
1506+
};
1507+
constexpr auto p = &C::foo;
1508+
constexpr auto q = static_cast<int (A::*)() const>(p);
1509+
constexpr B b;
1510+
constexpr const A& a = b;
1511+
constexpr auto x = (a.*q)(); // expected-error {{constant expression}}
1512+
}

0 commit comments

Comments
 (0)