[ms-cxxabi] Correctly compute the size of member pointers

Summary:
This also relaxes the requirement on Windows that the member pointer
class type be a complete type (http://llvm.org/PR12070).  We still ask
for a complete type to instantiate any templates (MSVC does this), but
if that fails we continue as normal, relying on any inheritance
attributes on the declaration.

Reviewers: rjmccall

CC: triton, timurrrr, cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D568

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178283 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 51308ea..2f41cec 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CXXABI.h"
+#include "clang/AST/Attr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecordLayout.h"
@@ -27,7 +28,8 @@
 public:
   MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
 
-  unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
+  std::pair<uint64_t, unsigned>
+  getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
 
   CallingConv getDefaultMethodCallConv(bool isVariadic) const {
     if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
@@ -52,17 +54,77 @@
 };
 }
 
-unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const {
-  QualType Pointee = MPT->getPointeeType();
-  CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
-  if (RD->getNumVBases() > 0) {
-    if (Pointee->isFunctionType())
-      return 3;
-    else
-      return 2;
-  } else if (RD->getNumBases() > 1 && Pointee->isFunctionType())
-    return 2;
-  return 1;
+// getNumBases() seems to only give us the number of direct bases, and not the
+// total.  This function tells us if we inherit from anybody that uses MI, or if
+// we have a non-primary base class, which uses the multiple inheritance model.
+static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
+  while (RD->getNumBases() > 0) {
+    if (RD->getNumBases() > 1)
+      return true;
+    assert(RD->getNumBases() == 1);
+    const CXXRecordDecl *Base = RD->bases_begin()->getType()->getAsCXXRecordDecl();
+    if (RD->isPolymorphic() && !Base->isPolymorphic())
+      return true;
+    RD = Base;
+  }
+  return false;
+}
+
+std::pair<uint64_t, unsigned>
+MicrosoftCXXABI::getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  const TargetInfo &Target = Context.getTargetInfo();
+
+  assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
+         Target.getTriple().getArch() == llvm::Triple::x86_64);
+
+  Attr *IA = RD->getAttr<MSInheritanceAttr>();
+  attr::Kind Inheritance;
+  if (IA) {
+    Inheritance = IA->getKind();
+  } else if (RD->getNumVBases() > 0) {
+    Inheritance = attr::VirtualInheritance;
+  } else if (MPT->getPointeeType()->isFunctionType() &&
+             usesMultipleInheritanceModel(RD)) {
+    Inheritance = attr::MultipleInheritance;
+  } else {
+    Inheritance = attr::SingleInheritance;
+  }
+
+  unsigned PtrSize = Target.getPointerWidth(0);
+  unsigned IntSize = Target.getIntWidth();
+  uint64_t Width;
+  unsigned Align;
+  if (MPT->getPointeeType()->isFunctionType()) {
+    // Member function pointers are a struct of a function pointer followed by a
+    // variable number of ints depending on the inheritance model used.  The
+    // function pointer is a real function if it is non-virtual and a vftable
+    // slot thunk if it is virtual.  The ints select the object base passed for
+    // the 'this' pointer.
+    Align = Target.getPointerAlign(0);
+    switch (Inheritance) {
+    case attr::SingleInheritance:      Width = PtrSize;               break;
+    case attr::MultipleInheritance:    Width = PtrSize + 1 * IntSize; break;
+    case attr::VirtualInheritance:     Width = PtrSize + 2 * IntSize; break;
+    case attr::UnspecifiedInheritance: Width = PtrSize + 3 * IntSize; break;
+    default: llvm_unreachable("unknown inheritance model");
+    }
+  } else {
+    // Data pointers are an aggregate of ints.  The first int is an offset
+    // followed by vbtable-related offsets.
+    Align = Target.getIntAlign();
+    switch (Inheritance) {
+    case attr::SingleInheritance:       // Same as multiple inheritance.
+    case attr::MultipleInheritance:     Width = 1 * IntSize; break;
+    case attr::VirtualInheritance:      Width = 2 * IntSize; break;
+    case attr::UnspecifiedInheritance:  Width = 3 * IntSize; break;
+    default: llvm_unreachable("unknown inheritance model");
+    }
+  }
+  Width = llvm::RoundUpToAlignment(Width, Align);
+
+  // FIXME: Verify that our alignment matches MSVC.
+  return std::make_pair(Width, Align);
 }
 
 CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {