summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp20
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp27
2 files changed, 45 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 2d8b538bc2e..7ec3950bc6f 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -619,6 +619,9 @@ private:
llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
const MethodVFTableLocation &ML);
+ llvm::Constant *EmitMemberDataPointer(const CXXRecordDecl *RD,
+ CharUnits offset);
+
public:
llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
@@ -2702,7 +2705,11 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
llvm::Constant *
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset) {
- const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ return EmitMemberDataPointer(MPT->getMostRecentCXXRecordDecl(), offset);
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberDataPointer(const CXXRecordDecl *RD,
+ CharUnits offset) {
if (RD->getMSInheritanceModel() ==
MSInheritanceAttr::Keyword_virtual_inheritance)
offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
@@ -2726,8 +2733,17 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
C = EmitMemberFunctionPointer(MD);
} else {
+ // For a pointer to data member, start off with the offset of the field in
+ // the class in which it was declared, and convert from there if necessary.
+ // For indirect field decls, get the outermost anonymous field and use the
+ // parent class.
CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD));
- C = EmitMemberDataPointer(DstTy, FieldOffset);
+ const FieldDecl *FD = dyn_cast<FieldDecl>(MPD);
+ if (!FD)
+ FD = cast<FieldDecl>(*cast<IndirectFieldDecl>(MPD)->chain_begin());
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent());
+ RD = RD->getMostRecentNonInjectedDecl();
+ C = EmitMemberDataPointer(RD, FieldOffset);
}
if (!MemberPointerPath.empty()) {
diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 51dd889338a..bfe620df5ce 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -121,6 +121,33 @@ void VirtualInheritanceFnPtrCall() {
}
} // namespace pr37399
+namespace pr43803 {
+// This case is interesting because it exercises conversion between member
+// pointer types when emitting constants.
+
+struct B;
+struct C { int B::*option; };
+extern const C table[3];
+struct A {
+ int x, y;
+ // Test the indirect case.
+ struct {
+ int z;
+ };
+};
+struct B : A {};
+const C table[] = {
+ {&B::x},
+ {&B::y},
+ {&B::z},
+};
+
+// CHECK: @"?table@pr43803@@3QBUC@1@B" = dso_local constant [3 x %"struct.pr43803::C"]
+// CHECK-SAME: [%"struct.pr43803::C" { { i32, i32, i32 } zeroinitializer, [4 x i8] undef },
+// CHECK-SAME: %"struct.pr43803::C" { { i32, i32, i32 } { i32 4, i32 0, i32 0 }, [4 x i8] undef },
+// CHECK-SAME: %"struct.pr43803::C" { { i32, i32, i32 } { i32 8, i32 0, i32 0 }, [4 x i8] undef }]
+}
+
struct PR26313_Y;
typedef void (PR26313_Y::*PR26313_FUNC)();
struct PR26313_X {
OpenPOWER on IntegriCloud