Skip to content

Commit 07ee46d

Browse files
committed
[MS] Fix constexpr data member pointer conversions
Constexpr data member conversions work by starting with the class that originally introduced the field, and converting from there to the type that the user desires. Before this change, Clang was using the inheritance model from the final destination class type instead of the model from the class that originally introduced the field. To fix this, find the relevant FieldDecl and take its parent class instead of using the member pointer type the user provided. Indirect field decls require some special handling to find the parent class. Fixes PR43803
1 parent 44bac3e commit 07ee46d

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,9 @@ class MicrosoftCXXABI : public CGCXXABI {
619619
llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
620620
const MethodVFTableLocation &ML);
621621

622+
llvm::Constant *EmitMemberDataPointer(const CXXRecordDecl *RD,
623+
CharUnits offset);
624+
622625
public:
623626
llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
624627

@@ -2702,7 +2705,11 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
27022705
llvm::Constant *
27032706
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
27042707
CharUnits offset) {
2705-
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
2708+
return EmitMemberDataPointer(MPT->getMostRecentCXXRecordDecl(), offset);
2709+
}
2710+
2711+
llvm::Constant *MicrosoftCXXABI::EmitMemberDataPointer(const CXXRecordDecl *RD,
2712+
CharUnits offset) {
27062713
if (RD->getMSInheritanceModel() ==
27072714
MSInheritanceAttr::Keyword_virtual_inheritance)
27082715
offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
@@ -2726,8 +2733,17 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
27262733
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
27272734
C = EmitMemberFunctionPointer(MD);
27282735
} else {
2736+
// For a pointer to data member, start off with the offset of the field in
2737+
// the class in which it was declared, and convert from there if necessary.
2738+
// For indirect field decls, get the outermost anonymous field and use the
2739+
// parent class.
27292740
CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD));
2730-
C = EmitMemberDataPointer(DstTy, FieldOffset);
2741+
const FieldDecl *FD = dyn_cast<FieldDecl>(MPD);
2742+
if (!FD)
2743+
FD = cast<FieldDecl>(*cast<IndirectFieldDecl>(MPD)->chain_begin());
2744+
const CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent());
2745+
RD = RD->getMostRecentNonInjectedDecl();
2746+
C = EmitMemberDataPointer(RD, FieldOffset);
27312747
}
27322748

27332749
if (!MemberPointerPath.empty()) {

clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,33 @@ void VirtualInheritanceFnPtrCall() {
121121
}
122122
} // namespace pr37399
123123

124+
namespace pr43803 {
125+
// This case is interesting because it exercises conversion between member
126+
// pointer types when emitting constants.
127+
128+
struct B;
129+
struct C { int B::*option; };
130+
extern const C table[3];
131+
struct A {
132+
int x, y;
133+
// Test the indirect case.
134+
struct {
135+
int z;
136+
};
137+
};
138+
struct B : A {};
139+
const C table[] = {
140+
{&B::x},
141+
{&B::y},
142+
{&B::z},
143+
};
144+
145+
// CHECK: @"?table@pr43803@@3QBUC@1@B" = dso_local constant [3 x %"struct.pr43803::C"]
146+
// CHECK-SAME: [%"struct.pr43803::C" { { i32, i32, i32 } zeroinitializer, [4 x i8] undef },
147+
// CHECK-SAME: %"struct.pr43803::C" { { i32, i32, i32 } { i32 4, i32 0, i32 0 }, [4 x i8] undef },
148+
// CHECK-SAME: %"struct.pr43803::C" { { i32, i32, i32 } { i32 8, i32 0, i32 0 }, [4 x i8] undef }]
149+
}
150+
124151
struct PR26313_Y;
125152
typedef void (PR26313_Y::*PR26313_FUNC)();
126153
struct PR26313_X {

0 commit comments

Comments
 (0)