[clang] 07ee46d - [MS] Fix constexpr data member pointer conversions

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 29 16:58:05 PDT 2019


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 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 cfe-commits mailing list