[llvm-branch-commits] [clang] 2d75b24 - [MS] Fix constexpr data member pointer conversions

Reid Kleckner via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Oct 30 11:33:31 PDT 2019


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 at pr43803@@3QBUC at 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 {


        


More information about the llvm-branch-commits mailing list