diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 00b15c9..797e7ad 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -111,17 +111,30 @@ public:
   static bool needThisReturn(GlobalDecl GD);
 
 private:
-  llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT);
-
-  llvm::Constant *getZeroPtrDiff() {
-    return llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
+  llvm::Constant *getZeroInt() {
+    return llvm::ConstantInt::get(CGM.IntTy, 0);
   }
 
-  llvm::Constant *getAllOnesPtrDiff() {
-    return  llvm::Constant::getAllOnesValue(CGM.PtrDiffTy);
+  llvm::Constant *getAllOnesInt() {
+    return  llvm::Constant::getAllOnesValue(CGM.IntTy);
   }
 
+  bool NullFieldOffsetIsAllOnes(const CXXRecordDecl *RD,
+                                MSInheritanceModel Inheritance);
+
+  llvm::SmallVector<llvm::Constant *, 4>
+  GetNullMemberPointerFields(const MemberPointerType *MPT);
+
+  llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
+                                 llvm::Value *Base,
+                                 llvm::Value *VirtualBaseAdjustmentOffset,
+                                 llvm::Value *VBTableOffset /* optional */);
+
 public:
+  virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
+
+  virtual bool isZeroInitializable(const MemberPointerType *MPT);
+
   virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
 
   virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
@@ -136,6 +149,12 @@ public:
                                                     llvm::Value *MemPtr,
                                                   const MemberPointerType *MPT);
 
+  virtual llvm::Value *
+  EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+                                  llvm::Value *&This,
+                                  llvm::Value *MemPtr,
+                                  const MemberPointerType *MPT);
+
 };
 
 }
@@ -379,45 +398,133 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
   CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
 }
 
-// Returns true for member pointer types that we know how to represent with a
-// simple ptrdiff_t.  Currently we only know how to emit, test, and load member
-// data pointers for complete single inheritance classes.
-static bool isSimpleMemberPointer(const MemberPointerType *MPT) {
+bool
+MicrosoftCXXABI::NullFieldOffsetIsAllOnes(const CXXRecordDecl *RD,
+                                          MSInheritanceModel Inheritance) {
+  // Classes with unspecified or virtual inheritance use zero for data member
+  // pointer field offsets.
+  if (Inheritance > MSIM_Multiple)
+    return false;
+  // If the class has an explicit inheritance model attribute, we conservatively
+  // use -1.  This requires different TUs to see the same attribute or they have
+  // an ODR problem.
+  if (RD->hasAttr<MSInheritanceAttr>())
+    return true;
+  // Any class without an inheritance attr must have a definition, or we would
+  // be using the unspecified model for it.
+  assert(RD->hasDefinition());
+  // Since zero is a valid offset for classes without vtables, they use -1.  For
+  // some reason, classes with vtables use 0 in this ABI.  In this inheritance
+  // model, only polymorphic classes have vtables.
+  return !RD->isPolymorphic();
+}
+
+bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
+  // Null-ness for function memptrs only depends on the first field, which is
+  // the function pointer.  The rest don't matter, so we can zero initialize.
+  if (MPT->isMemberFunctionPointer())
+    return true;
+
+  // There is only one kind of class with data member pointers that can be zero
+  // initialized: single or multiple inheritance classes with a vfptr.
   const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
-  return (MPT->isMemberDataPointer() &&
-          !MPT->getClass()->isIncompleteType() &&
-          RD->getNumVBases() == 0);
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+  return (Inheritance <= MSIM_Multiple &&
+          !NullFieldOffsetIsAllOnes(RD, Inheritance));
 }
 
-llvm::Constant *
-MicrosoftCXXABI::getSimpleNullMemberPointer(const MemberPointerType *MPT) {
-  if (isSimpleMemberPointer(MPT)) {
-    const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
-    // A null member data pointer is represented as -1 if the class is not
-    // polymorphic, and 0 otherwise.
-    if (RD->isPolymorphic())
-      return getZeroPtrDiff();
-    return getAllOnesPtrDiff();
+llvm::Type *
+MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+  llvm::SmallVector<llvm::Type *, 4> fields;
+  if (MPT->isMemberFunctionPointer())
+    fields.push_back(CGM.VoidPtrTy);  // FunctionPointerOrVirtualThunk
+  else
+    fields.push_back(CGM.IntTy);  // FieldOffset
+
+  if (Inheritance == MSIM_Unspecified)
+    fields.push_back(CGM.IntTy);  // VBTableOffset
+  // Only function pointers need a this adjustment, since it can be combined
+  // with the field offset for data pointers.
+  if (MPT->isMemberFunctionPointer() && Inheritance >= MSIM_Multiple)
+    fields.push_back(CGM.IntTy);  // NonVirtualBaseAdjustment
+  if (Inheritance >= MSIM_Virtual)
+    fields.push_back(CGM.IntTy);  // VirtualBaseAdjustmentOffset
+
+  if (fields.size() == 1)
+    return fields[0];
+  return llvm::StructType::get(CGM.getLLVMContext(), fields);
+}
+
+llvm::SmallVector<llvm::Constant *, 4>
+MicrosoftCXXABI::GetNullMemberPointerFields(const MemberPointerType *MPT) {
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+  llvm::SmallVector<llvm::Constant *, 4> fields;
+  if (MPT->isMemberFunctionPointer()) {
+    // FunctionPointerOrVirtualThunk
+    fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
+  } else {
+    if (NullFieldOffsetIsAllOnes(RD, Inheritance))
+      fields.push_back(getAllOnesInt());  // FieldOffset
+    else
+      fields.push_back(getZeroInt());  // FieldOffset
   }
-  return GetBogusMemberPointer(QualType(MPT, 0));
+
+  if (Inheritance == MSIM_Unspecified)
+    fields.push_back(getZeroInt());  // VBTableOffset
+  if (MPT->isMemberFunctionPointer() && Inheritance >= MSIM_Multiple)
+    fields.push_back(getZeroInt());  // NonVirtualBaseAdjustment
+  if (Inheritance >= MSIM_Virtual)
+    fields.push_back(getAllOnesInt());  // VirtualBaseAdjustmentOffset
+  return fields;
 }
 
 llvm::Constant *
 MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
-  if (isSimpleMemberPointer(MPT))
-    return getSimpleNullMemberPointer(MPT);
-  // FIXME: Implement function member pointers.
-  return GetBogusMemberPointer(QualType(MPT, 0));
+  llvm::SmallVector<llvm::Constant *, 4> fields = GetNullMemberPointerFields(MPT);
+  if (fields.size() == 1)
+    return fields[0];
+  llvm::Constant *Res = llvm::ConstantStruct::getAnon(fields);
+  assert(Res->getType() == ConvertMemberPointerType(MPT));
+  return Res;
 }
 
 llvm::Constant *
 MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
                                        CharUnits offset) {
-  // Member data pointers are plain offsets when no virtual bases are involved.
-  if (isSimpleMemberPointer(MPT))
-    return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
-  // FIXME: Implement member pointers other inheritance models.
-  return GetBogusMemberPointer(QualType(MPT, 0));
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+  llvm::Constant *FieldOffset =
+    llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
+  switch (Inheritance) {
+  case MSIM_Unspecified: {
+    CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
+    llvm::Constant *VBTableOffset =
+      llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
+    llvm::Constant *fields[] = {
+      FieldOffset,
+      VBTableOffset,
+      // http://llvm.org/PR15713 : Taking a pointer to a member of a virtual
+      // base is not standard C++.  Clang will reject this in SemaCast, so we
+      // don't have to handle it here.
+      getZeroInt()    // VirtualBaseAdjustmentOffset
+    };
+    return llvm::ConstantStruct::getAnon(fields);
+  }
+  case MSIM_Virtual: {
+    llvm::Constant *fields[] = {
+      FieldOffset,
+      // Always zero.  See PR15713 mentioned above.
+      getZeroInt()   // VirtualBaseAdjustmentOffset
+    };
+    return llvm::ConstantStruct::getAnon(fields);
+  }
+  case MSIM_Multiple:
+  case MSIM_Single:
+    return FieldOffset;
+  }
 }
 
 llvm::Value *
@@ -425,16 +532,91 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
                                             llvm::Value *MemPtr,
                                             const MemberPointerType *MPT) {
   CGBuilderTy &Builder = CGF.Builder;
+  llvm::SmallVector<llvm::Constant *, 4> fields;
+  // We only need one field for member functions.
+  if (MPT->isMemberFunctionPointer())
+    fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
+  else
+    fields = GetNullMemberPointerFields(MPT);
+  assert(!fields.empty());
+  llvm::Value *FirstField = MemPtr;
+  if (MemPtr->getType()->isStructTy())
+    FirstField = Builder.CreateExtractValue(MemPtr, 0);
+  llvm::Value *Res = Builder.CreateICmpNE(FirstField, fields[0], "memptr.cmp0");
+
+  // For function member pointers, we only need to test the function pointer
+  // field.  The other fields if any can be garbage.
+  if (MPT->isMemberFunctionPointer())
+    return Res;
+
+  // Otherwise, emit a series of compares and combine the results.
+  for (int I = 1, E = fields.size(); I < E; ++I) {
+    llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I);
+    llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp");
+    Res = Builder.CreateAnd(Res, Next, "memptr.tobool");
+  }
+  return Res;
+}
 
-  // For member data pointers, this is just a check against -1 or 0.
-  if (isSimpleMemberPointer(MPT)) {
-    llvm::Constant *Val = getSimpleNullMemberPointer(MPT);
-    return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool");
+// Returns an adjusted base cast to i8*, since we do more address arithmetic on
+// it.
+llvm::Value *
+MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
+                                   const CXXRecordDecl *RD, llvm::Value *Base,
+                                   llvm::Value *VirtualBaseAdjustmentOffset,
+                                   llvm::Value *VBTableOffset) {
+  CGBuilderTy &Builder = CGF.Builder;
+  Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy);
+  llvm::BasicBlock *OriginalBB;
+  llvm::BasicBlock *SkipAdjustBB;
+  llvm::BasicBlock *VBaseAdjustBB = 0;
+
+  // In the unspecified inheritance model, there might not be a vbtable at all,
+  // in which case we need to skip the virtual base lookup.  If there were a
+  // vbtable, the first entry is a no-op entry that gives back the original
+  // base, so look for a virtual base adjustment offset of zero.
+  if (VBTableOffset) {
+    OriginalBB = Builder.GetInsertBlock();
+    VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust");
+    SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust");
+    llvm::Value *IsVirtual =
+      Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(),
+                           "memptr.is_vbase");
+    Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB);
+    CGF.EmitBlock(VBaseAdjustBB);
   }
 
-  // FIXME: Implement member pointers other inheritance models.
-  ErrorUnsupportedABI(CGF, "function member pointer tests");
-  return GetBogusMemberPointer(QualType(MPT, 0));
+  // If we weren't given a dynamic vbptr offset, RD should be complete and we'll
+  // know the vbptr offset.
+  if (!VBTableOffset) {
+    CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
+    VBTableOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
+  }
+  // Load the vbtable pointer from the vbtable offset in the instance.
+  llvm::Value *VBPtr =
+    Builder.CreateInBoundsGEP(Base, VBTableOffset, "memptr.vbptr");
+  llvm::Value *VBTable =
+    Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0));
+  VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable");
+  // Load an i32 offset from the vb-table.
+  llvm::Value *VBaseOffs =
+    Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset);
+  VBaseOffs =
+    Builder.CreateBitCast(VBaseOffs, Builder.getInt32Ty()->getPointerTo(0));
+  VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs");
+  // Add it to VBPtr.
+  llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
+
+  // Merge control flow with the case where we didn't have to adjust.
+  if (VBaseAdjustBB) {
+    Builder.CreateBr(SkipAdjustBB);
+    CGF.EmitBlock(SkipAdjustBB);
+    llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base");
+    Phi->addIncoming(Base, OriginalBB);
+    Phi->addIncoming(AdjustedBase, VBaseAdjustBB);
+    return Phi;
+  }
+  return AdjustedBase;
 }
 
 llvm::Value *
@@ -442,32 +624,107 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
                                               llvm::Value *Base,
                                               llvm::Value *MemPtr,
                                               const MemberPointerType *MPT) {
+  assert(MPT->isMemberDataPointer());
   unsigned AS = Base->getType()->getPointerAddressSpace();
   llvm::Type *PType =
       CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
   CGBuilderTy &Builder = CGF.Builder;
-
-  if (MPT->isMemberFunctionPointer()) {
-    ErrorUnsupportedABI(CGF, "function member pointer address");
-    return llvm::Constant::getNullValue(PType);
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+
+  // Extract the fields we need, regardless of model.  We'll apply them if we
+  // have them.
+  llvm::Value *FieldOffset;
+  llvm::Value *VirtualBaseAdjustmentOffset = NULL;
+  llvm::Value *VBTableOffset = NULL;
+  switch (Inheritance) {
+  case MSIM_Unspecified:
+    FieldOffset = Builder.CreateExtractValue(MemPtr, 0);
+    VBTableOffset = Builder.CreateExtractValue(MemPtr, 1);
+    VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, 2);
+    break;
+  case MSIM_Virtual:
+    FieldOffset = Builder.CreateExtractValue(MemPtr, 0);
+    VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, 1);
+    break;
+  case MSIM_Single:
+  case MSIM_Multiple:
+    assert(MemPtr->getType() == CGM.IntTy);
+    FieldOffset = MemPtr;
+    break;
   }
 
-  llvm::Value *Addr;
-  if (isSimpleMemberPointer(MPT)) {
-    // Add the offset with GEP and i8*.
-    assert(MemPtr->getType() == CGM.PtrDiffTy);
-    Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
-    Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset");
-  } else {
-    ErrorUnsupportedABI(CGF, "non-scalar member pointers");
-    return llvm::Constant::getNullValue(PType);
+  if (VirtualBaseAdjustmentOffset) {
+    Base = AdjustVirtualBase(CGF, RD, Base, VirtualBaseAdjustmentOffset,
+                             VBTableOffset);
   }
+  llvm::Value *Addr =
+    Builder.CreateInBoundsGEP(Base, FieldOffset, "memptr.offset");
 
   // Cast the address to the appropriate pointer type, adopting the address
   // space of the base pointer.
   return Builder.CreateBitCast(Addr, PType);
 }
 
+llvm::Value *
+MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+                                                 llvm::Value *&This,
+                                                 llvm::Value *MemPtr,
+                                                 const MemberPointerType *MPT) {
+  assert(MPT->isMemberFunctionPointer());
+  const FunctionProtoType *FPT =
+    MPT->getPointeeType()->getAs<FunctionProtoType>();
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  llvm::FunctionType *FTy =
+    CGM.getTypes().GetFunctionType(
+      CGM.getTypes().arrangeCXXMethodType(RD, FPT));
+  CGBuilderTy &Builder = CGF.Builder;
+
+  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+
+  // Extract the fields we need, regardless of model.  We'll apply them if we
+  // have them.
+  llvm::Value *FunctionPointer;
+  llvm::Value *NonVirtualBaseAdjustment = NULL;
+  llvm::Value *VirtualBaseAdjustmentOffset = NULL;
+  llvm::Value *VBTableOffset = NULL;
+  switch (Inheritance) {
+  case MSIM_Unspecified:
+    FunctionPointer = Builder.CreateExtractValue(MemPtr, 0);
+    VBTableOffset = Builder.CreateExtractValue(MemPtr, 1);
+    NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, 2);
+    VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, 3);
+    break;
+  case MSIM_Virtual:
+    FunctionPointer = Builder.CreateExtractValue(MemPtr, 0);
+    NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, 1);
+    VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, 2);
+    break;
+  case MSIM_Multiple:
+    FunctionPointer = Builder.CreateExtractValue(MemPtr, 0);
+    NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, 1);
+    break;
+  case MSIM_Single:
+    assert(MemPtr->getType()->isPointerTy());
+    FunctionPointer = MemPtr;
+    break;
+  }
+
+  if (VirtualBaseAdjustmentOffset) {
+    This = AdjustVirtualBase(CGF, RD, This, VirtualBaseAdjustmentOffset,
+                             VBTableOffset);
+  }
+
+  if (NonVirtualBaseAdjustment) {
+    // Apply the adjustment and cast back to the original struct type.
+    llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy());
+    Ptr = Builder.CreateInBoundsGEP(Ptr, NonVirtualBaseAdjustment);
+    This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted");
+  }
+
+  return Builder.CreateBitCast(FunctionPointer, FTy->getPointerTo());
+}
+
 CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
   return new MicrosoftCXXABI(CGM);
 }
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 997e007..62bc364 100755
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -1,10 +1,49 @@
 // RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
 
+struct B1 {
+  int b;
+};
+struct B2 { };
+struct Single : B1 { };
+struct Multiple : B1, B2 { };
+struct Virtual : virtual B1 {
+  int v;
+};
+
 struct POD {
   int a;
   int b;
 };
 
+struct Polymorphic {
+  virtual void myVirtual();
+  int a;
+  int b;
+};
+
+struct Unspecified;
+
+// Check that we can lower the LLVM types and get the initializers right.
+int Single     ::*s_d_memptr;
+int Polymorphic::*p_d_memptr;
+int Multiple   ::*m_d_memptr;
+int Virtual    ::*v_d_memptr;
+int Unspecified::*u_d_memptr;
+// CHECK: @"\01?s_d_memptr@@3PQSingle@@HA" = global i32 -1, align 4
+// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HA" = global i32 0, align 4
+// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HA" = global i32 -1, align 4
+// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HA" = global { i32, i32 }
+// CHECK:   { i32 0, i32 -1 }, align 4
+// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HA" = global { i32, i32, i32 }
+// CHECK:   { i32 0, i32 0, i32 -1 }, align 4
+
+void (Single  ::*s_f_memptr)();
+void (Multiple::*m_f_memptr)();
+void (Virtual ::*v_f_memptr)();
+// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZA" = global i8* null, align 4
+// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4
+// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4
+
 void podMemPtrs() {
   int POD::*memptr;
   memptr = &POD::a;
@@ -24,12 +63,6 @@ void podMemPtrs() {
 // CHECK:      }
 }
 
-struct Polymorphic {
-  virtual void myVirtual();
-  int a;
-  int b;
-};
-
 void polymorphicMemPtrs() {
   int Polymorphic::*memptr;
   memptr = &Polymorphic::a;
@@ -49,3 +82,133 @@ void polymorphicMemPtrs() {
 // CHECK:        ret void
 // CHECK:      }
 }
+
+bool nullTestDataUnspecified(int Unspecified::*mp) {
+  return mp;
+// CHECK: define zeroext i1 @"\01?nullTestDataUnspecified@@YA_NPQUnspecified@@H@Z"{{.*}} {
+// CHECK:   %{{.*}} = load { i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i32, i32, i32 } {{.*}} align 4
+// CHECK:   %[[mp:.*]] = load { i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   %[[mp0:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 0
+// CHECK:   %[[cmp0:.*]] = icmp ne i32 %[[mp0]], 0
+// CHECK:   %[[mp1:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 1
+// CHECK:   %[[cmp1:.*]] = icmp ne i32 %[[mp1]], 0
+// CHECK:   %[[and0:.*]] = and i1 %[[cmp0]], %[[cmp1]]
+// CHECK:   %[[mp2:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 2
+// CHECK:   %[[cmp2:.*]] = icmp ne i32 %[[mp2]], -1
+// CHECK:   %[[and1:.*]] = and i1 %[[and0]], %[[cmp2]]
+// CHECK:   ret i1 %[[and1]]
+// CHECK: }
+}
+
+bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) {
+  return mp;
+// CHECK: define zeroext i1 @"\01?nullTestFunctionUnspecified@@YA_NP8Unspecified@@AEXXZ@Z"{{.*}} {
+// CHECK:   %{{.*}} = load { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i8*, i32, i32, i32 } {{.*}} align 4
+// CHECK:   %[[mp:.*]] = load { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   %[[mp0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[mp]], 0
+// CHECK:   %[[cmp0:.*]] = icmp ne i8* %[[mp0]], null
+// CHECK:   ret i1 %[[cmp0]]
+// CHECK: }
+}
+
+int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) {
+  return o->*memptr;
+// Test that we can unpack this aggregate member pointer and load the member
+// data pointer.
+// CHECK: define i32 @"\01?loadDataMemberPointerVirtual@@YAHPAUVirtual@@PQ1@H@Z"{{.*}} {
+// CHECK:   %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4
+// CHECK:   %[[memptr:.*]] = load { i32, i32 }* %memptr.addr, align 4
+// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1
+// CHECK:   %[[v6:.*]] = bitcast %{{.*}}* %[[o]] to i8*
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %[[v6]], i32 0
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr1]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+// CHECK:   %[[offset:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr0]]
+// CHECK:   %[[v11:.*]] = bitcast i8* %[[offset]] to i32*
+// CHECK:   %[[v12:.*]] = load i32* %[[v11]]
+// CHECK:   ret i32 %[[v12]]
+// CHECK: }
+}
+
+int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
+  return o->*memptr;
+// Test that we can unpack this aggregate member pointer and load the member
+// data pointer.
+// CHECK: define i32 @"\01?loadDataMemberPointerUnspecified@@YAHPAUUnspecified@@PQ1@H@Z"{{.*}} {
+// CHECK:   %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4
+// CHECK:   %[[memptr:.*]] = load { i32, i32, i32 }* %memptr.addr, align 4
+// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 1
+// CHECK:   %[[memptr2:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 2
+// CHECK:   %[[base:.*]] = bitcast %{{.*}}* %[[o]] to i8*
+// CHECK:   %[[is_vbase:.*]] = icmp ne i32 %[[memptr2]], 0
+// CHECK:   br i1 %[[is_vbase]], label %[[vadjust:.*]], label %[[skip:.*]]
+//
+// CHECK: [[vadjust]]:
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %[[base]], i32 %[[memptr1]]
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[base_adj:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+//
+// CHECK: [[skip]]:
+// CHECK:   %[[new_base:.*]] = phi i8* [ %[[base]], %entry ], [ %[[base_adj]], %[[vadjust]] ]
+// CHECK:   %[[offset:.*]] = getelementptr inbounds i8* %[[new_base]], i32 %[[memptr0]]
+// CHECK:   %[[v11:.*]] = bitcast i8* %[[offset]] to i32*
+// CHECK:   %[[v12:.*]] = load i32* %[[v11]]
+// CHECK:   ret i32 %[[v12]]
+// CHECK: }
+}
+
+void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {
+  (o->*memptr)();
+// Just look for an indirect thiscall.
+// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 {
+// CHECK:   call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}})
+// CHECK:   ret void
+// CHECK: }
+}
+
+void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) {
+  (o->*memptr)();
+// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} #0 {
+// CHECK:   %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1
+// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]]
+// CHECK:   %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}}
+// CHECK:   %[[fptr:.*]] = bitcast i8* %[[memptr0]] to {{.*}}
+// CHECK:   call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]])
+// CHECK:   ret void
+// CHECK: }
+}
+
+void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) {
+  (o->*memptr)();
+// This shares a lot with virtual data member pointers.
+// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} #0 {
+// CHECK:   %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1
+// CHECK:   %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %{{.*}}, i32 0
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr1]]
+// CHECK:   %[[fptr:.*]] = bitcast i8* %[[memptr0]] to void ({{.*}})
+// CHECK:   %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}}
+// CHECK:   call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]])
+// CHECK:   ret void
+// CHECK: }
+}
