Author: Reid Kleckner Date: 2019-10-29T16:58:00-07:00 New Revision: 07ee46d613d7c1862878d7c7d1208a7b3e37459d
URL: https://github.com/llvm/llvm-project/commit/07ee46d613d7c1862878d7c7d1208a7b3e37459d DIFF: https://github.com/llvm/llvm-project/commit/07ee46d613d7c1862878d7c7d1208a7b3e37459d.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 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 2d8b538bc2ee..7ec3950bc6f9 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -619,6 +619,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; @@ -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 51dd889338a7..bfe620df5ce3 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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits