Author: Reid Kleckner Date: 2019-10-30T11:20:31-07:00 New Revision: 2d75b245668a49815935687b9a70beddbc68f66c
URL: https://github.com/llvm/llvm-project/commit/2d75b245668a49815935687b9a70beddbc68f66c DIFF: https://github.com/llvm/llvm-project/commit/2d75b245668a49815935687b9a70beddbc68f66c.diff LOG: [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 07ee46d613d7c1862878d7c7d1208a7b3e37459d) Added: Modified: clang/lib/CodeGen/MicrosoftCXXABI.cpp clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index ca06ad3f042b..e02c9ae0b8f2 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -617,6 +617,9 @@ class MicrosoftCXXABI : public CGCXXABI { 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; @@ -2700,7 +2703,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); @@ -2724,8 +2731,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 cb3b41bbb4f1..4202f847a034 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 { _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits