]> granicus.if.org Git - clang/commitdiff
[MS ABI] Form member pointers from virtual funcs overriding vbases
authorDavid Majnemer <david.majnemer@gmail.com>
Sun, 10 May 2015 21:48:08 +0000 (21:48 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sun, 10 May 2015 21:48:08 +0000 (21:48 +0000)
We didn't supporting taking the address of virtual member functions
which overrode a method in a virtual base.  We simply need to encode the
virtual base index in the member pointer.

This fixes PR23452.

N.B.  There is no data member pointer side to this change because taking
the address of a virtual bases' data member gives you a member pointer
whose type is derived from the virtual bases' type, not the most derived
type.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236962 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-vmemptr-vbase.cpp [new file with mode: 0644]

index 35f598337260af4dfce50202cc54dfa0aa287746..de30883c545f2853528d540f385e1dc894602215 100644 (file)
@@ -496,7 +496,8 @@ private:
   llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
                                         bool IsMemberFunction,
                                         const CXXRecordDecl *RD,
-                                        CharUnits NonVirtualBaseAdjustment);
+                                        CharUnits NonVirtualBaseAdjustment,
+                                        unsigned VBTableIndex);
 
   llvm::Constant *BuildMemberPointer(const CXXRecordDecl *RD,
                                      const CXXMethodDecl *MD,
@@ -2332,8 +2333,8 @@ llvm::Constant *
 MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
                                        bool IsMemberFunction,
                                        const CXXRecordDecl *RD,
-                                       CharUnits NonVirtualBaseAdjustment)
-{
+                                       CharUnits NonVirtualBaseAdjustment,
+                                       unsigned VBTableIndex) {
   MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
 
   // Single inheritance class member pointer are represented as scalars instead
@@ -2357,7 +2358,7 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
 
   // The rest of the fields are adjusted by conversions to a more derived class.
   if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
-    fields.push_back(getZeroInt());
+    fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBTableIndex));
 
   return llvm::ConstantStruct::getAnon(fields);
 }
@@ -2369,7 +2370,7 @@ MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
   llvm::Constant *FirstField =
     llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
   return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
-                               CharUnits::Zero());
+                               CharUnits::Zero(), /*VBTableIndex=*/0);
 }
 
 llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
@@ -2405,6 +2406,7 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
   RD = RD->getMostRecentDecl();
   CodeGenTypes &Types = CGM.getTypes();
 
+  unsigned VBTableIndex = 0;
   llvm::Constant *FirstField;
   const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
   if (!MD->isVirtual()) {
@@ -2421,8 +2423,6 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
     FirstField = CGM.GetAddrOfFunction(MD, Ty);
     FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
   } else {
-    MicrosoftVTableContext::MethodVFTableLocation ML =
-        CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
     if (!CGM.getTypes().isFuncTypeConvertible(
             MD->getType()->castAs<FunctionType>())) {
       CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
@@ -2431,21 +2431,22 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
     } else if (FPT->getCallConv() == CC_X86FastCall) {
       CGM.ErrorUnsupported(MD, "pointer to fastcall virtual member function");
       FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
-    } else if (ML.VBase) {
-      CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
-                               "member function in virtual base class");
-      FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
     } else {
+      auto &VTableContext = CGM.getMicrosoftVTableContext();
+      MicrosoftVTableContext::MethodVFTableLocation ML =
+          VTableContext.getMethodVFTableLocation(MD);
       llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ML);
       FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
       // Include the vfptr adjustment if the method is in a non-primary vftable.
       NonVirtualBaseAdjustment += ML.VFPtrOffset;
+      if (ML.VBase)
+        VBTableIndex = VTableContext.getVBTableIndex(RD, ML.VBase) * 4;
     }
   }
 
   // The rest of the fields are common with data member pointers.
   return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD,
-                               NonVirtualBaseAdjustment);
+                               NonVirtualBaseAdjustment, VBTableIndex);
 }
 
 /// Member pointers are the same if they're either bitwise identical *or* both
diff --git a/test/CodeGenCXX/microsoft-abi-vmemptr-vbase.cpp b/test/CodeGenCXX/microsoft-abi-vmemptr-vbase.cpp
new file mode 100644 (file)
index 0000000..85cc84f
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -triple=i386-pc-win32 -fms-extensions -fms-compatibility -std=c++11 %s -o - | FileCheck %s
+
+namespace PR23452 {
+struct A {
+    virtual void f();
+};
+struct B : virtual A {
+    virtual void f();
+};
+void (B::*MemPtr)(void) = &B::f;
+// CHECK-DAG: @"\01?MemPtr@PR23452@@3P8B@1@AEXXZQ21@" = global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01??_9B@PR23452@@$BA@AE" to i8*), i32 0, i32 4 }
+}