diff options
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 20 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp | 27 |
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 { |