Skip to content

Commit 2d75b24

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 (cherry picked from commit 07ee46d)
1 parent a4b77f5 commit 2d75b24

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
@@ -617,6 +617,9 @@ class MicrosoftCXXABI : public CGCXXABI {
617617
llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
618618
const MethodVFTableLocation &ML);
619619

620+
llvm::Constant *EmitMemberDataPointer(const CXXRecordDecl *RD,
621+
CharUnits offset);
622+
620623
public:
621624
llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
622625

@@ -2700,7 +2703,11 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
27002703
llvm::Constant *
27012704
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
27022705
CharUnits offset) {
2703-
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
2706+
return EmitMemberDataPointer(MPT->getMostRecentCXXRecordDecl(), offset);
2707+
}
2708+
2709+
llvm::Constant *MicrosoftCXXABI::EmitMemberDataPointer(const CXXRecordDecl *RD,
2710+
CharUnits offset) {
27042711
if (RD->getMSInheritanceModel() ==
27052712
MSInheritanceAttr::Keyword_virtual_inheritance)
27062713
offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
@@ -2724,8 +2731,17 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
27242731
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
27252732
C = EmitMemberFunctionPointer(MD);
27262733
} else {
2734+
// For a pointer to data member, start off with the offset of the field in
2735+
// the class in which it was declared, and convert from there if necessary.
2736+
// For indirect field decls, get the outermost anonymous field and use the
2737+
// parent class.
27272738
CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD));
2728-
C = EmitMemberDataPointer(DstTy, FieldOffset);
2739+
const FieldDecl *FD = dyn_cast<FieldDecl>(MPD);
2740+
if (!FD)
2741+
FD = cast<FieldDecl>(*cast<IndirectFieldDecl>(MPD)->chain_begin());
2742+
const CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent());
2743+
RD = RD->getMostRecentNonInjectedDecl();
2744+
C = EmitMemberDataPointer(RD, FieldOffset);
27292745
}
27302746

27312747
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)