- Avoid ambiguity by using class template mangling for null data memptrs

Hi majnemer, rsmith,

http://llvm-reviews.chandlerc.com/D2695

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2695?vs=6865&id=6892#toc

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/Mangle.h
  include/clang/Basic/Attr.td
  lib/AST/ASTContext.cpp
  lib/AST/MicrosoftCXXABI.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/CodeGen/CGVTables.cpp
  lib/CodeGen/CGVTables.h
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/mangle-ms-templates-memptrs.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/SemaCXX/nullptr.cpp
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -66,6 +66,7 @@
   class UnresolvedSetIterator;
   class UsingDecl;
   class UsingShadowDecl;
+  class VTableContextBase;
 
   namespace Builtin { class Context; }
 
@@ -1731,6 +1732,8 @@
 
   bool isNearlyEmpty(const CXXRecordDecl *RD) const;
 
+  VTableContextBase *getVTableContext();
+
   MangleContext *createMangleContext();
   
   void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
@@ -2292,6 +2295,8 @@
   void ReleaseDeclContextMaps();
 
   llvm::OwningPtr<ParentMap> AllParents;
+
+  llvm::OwningPtr<VTableContextBase> VTContext;
 };
 
 /// \brief Utility function for constructing a nullary selector.
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -1605,6 +1605,18 @@
   /// \brief Calculate what the inheritance model would be for this class.
   MSInheritanceAttr::Spelling calculateInheritanceModel() const;
 
+  /// In the Microsoft C++ ABI, use zero for the field offset of a null data
+  /// member pointer if we can guarantee that zero is not a valid field offset,
+  /// or if the member pointer has multiple fields.  Polymorphic classes have a
+  /// vfptr at offset zero, so we can use zero for null.  If there are multiple
+  /// fields, we can use zero even if it is a valid field offset because
+  /// null-ness testing will check the other fields.
+  bool nullFieldOffsetIsZero() const {
+    return !MSInheritanceAttr::hasOnlyOneField(/*IsMemberFunction=*/false,
+                                               getMSInheritanceModel()) ||
+           (hasDefinition() && isPolymorphic());
+  }
+
   /// \brief Determine whether this lambda expression was known to be dependent
   /// at the time it was created, even if its context does not appear to be
   /// dependent.
Index: include/clang/AST/Mangle.h
===================================================================
--- include/clang/AST/Mangle.h
+++ include/clang/AST/Mangle.h
@@ -182,7 +182,7 @@
 
 class MicrosoftMangleContext : public MangleContext {
 public:
-  explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D)
+  MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D)
       : MangleContext(C, D, MK_Microsoft) {}
 
   /// \brief Mangle vftable symbols.  Only a subset of the bases along the path
@@ -200,7 +200,6 @@
                                 raw_ostream &Out) = 0;
 
   virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
-                                        uint64_t OffsetInVFTable,
                                         raw_ostream &) = 0;
 
   static bool classof(const MangleContext *C) {
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1401,6 +1401,28 @@
                    Keyword<"__multiple_inheritance">,
                    Keyword<"__virtual_inheritance">,
                    Keyword<"__unspecified_inheritance">];
+  let AdditionalMembers = [{
+  static bool hasVBPtrOffsetField(Spelling Inheritance) {
+    return Inheritance == Keyword_unspecified_inheritance;
+  }
+
+  // Only member pointers to functions need a this adjustment, since it can be
+  // combined with the field offset for data pointers.
+  static bool hasNVOffsetField(bool IsMemberFunction, Spelling Inheritance) {
+    return IsMemberFunction && Inheritance >= Keyword_multiple_inheritance;
+  }
+
+  static bool hasVBTableOffsetField(Spelling Inheritance) {
+    return Inheritance >= Keyword_virtual_inheritance;
+  }
+
+  static bool hasOnlyOneField(bool IsMemberFunction,
+                              Spelling Inheritance) {
+    if (IsMemberFunction)
+      return Inheritance <= Keyword_single_inheritance;
+    return Inheritance <= Keyword_multiple_inheritance;
+  }
+  }];
 }
 
 def Unaligned : IgnoredAttr {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -29,6 +29,7 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/AST/VTableBuilder.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -7952,6 +7953,16 @@
   return ABI->isNearlyEmpty(RD);
 }
 
+VTableContextBase *ASTContext::getVTableContext() {
+  if (!VTContext.get()) {
+    if (Target->getCXXABI().isMicrosoft())
+      VTContext.reset(new MicrosoftVTableContext(*this));
+    else
+      VTContext.reset(new ItaniumVTableContext(*this));
+  }
+  return VTContext.get();
+}
+
 MangleContext *ASTContext::createMangleContext() {
   switch (Target->getCXXABI().getKind()) {
   case TargetCXXABI::GenericAArch64:
Index: lib/AST/MicrosoftCXXABI.cpp
===================================================================
--- lib/AST/MicrosoftCXXABI.cpp
+++ lib/AST/MicrosoftCXXABI.cpp
@@ -136,52 +136,32 @@
 //     // offset.
 //     int NonVirtualBaseAdjustment;
 //
+//     // The offset of the vb-table pointer within the object.  Only needed for
+//     // incomplete types.
+//     int VBPtrOffset;
+//
 //     // An offset within the vb-table that selects the virtual base containing
 //     // the member.  Loading from this offset produces a new offset that is
 //     // added to the address of the vb-table pointer to produce the base.
 //     int VirtualBaseAdjustmentOffset;
-//
-//     // The offset of the vb-table pointer within the object.  Only needed for
-//     // incomplete types.
-//     int VBPtrOffset;
 //   };
 static std::pair<unsigned, unsigned>
 getMSMemberPointerSlots(const MemberPointerType *MPT) {
   const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
   MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
   unsigned Ptrs = 0;
   unsigned Ints = 0;
-  if (MPT->isMemberFunctionPointer()) {
-    // 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.
-    Ptrs = 1; // First slot is always a function pointer.
-    switch (Inheritance) {
-    case MSInheritanceAttr::Keyword_unspecified_inheritance:
-      ++Ints; // VBTableOffset
-    case MSInheritanceAttr::Keyword_virtual_inheritance:
-      ++Ints; // VirtualBaseAdjustmentOffset
-    case MSInheritanceAttr::Keyword_multiple_inheritance:
-      ++Ints; // NonVirtualBaseAdjustment
-    case MSInheritanceAttr::Keyword_single_inheritance:
-      break;  // Nothing
-    }
-  } else {
-    // Data pointers are an aggregate of ints.  The first int is an offset
-    // followed by vbtable-related offsets.
-    Ints = 1; // We always have a field offset.
-    switch (Inheritance) {
-    case MSInheritanceAttr::Keyword_unspecified_inheritance:
-      ++Ints; // VBTableOffset
-    case MSInheritanceAttr::Keyword_virtual_inheritance:
-      ++Ints; // VirtualBaseAdjustmentOffset
-    case MSInheritanceAttr::Keyword_multiple_inheritance:
-    case MSInheritanceAttr::Keyword_single_inheritance:
-      break;  // Nothing
-    }
-  }
+  if (MPT->isMemberFunctionPointer())
+    Ptrs = 1;
+  else
+    Ints = 1;
+  if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+                                          Inheritance))
+    Ints++;
+  if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+    Ints++;
+  if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+    Ints++;
   return std::make_pair(Ptrs, Ints);
 }
 
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/VTableBuilder.h"
 #include "clang/Basic/ABI.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/TargetInfo.h"
@@ -121,6 +122,12 @@
   void mangleDeclaration(const NamedDecl *ND);
   void mangleFunctionEncoding(const FunctionDecl *FD);
   void mangleVariableEncoding(const VarDecl *VD);
+  void mangleMemberDataPointer(const CXXRecordDecl *RD, const FieldDecl *FD);
+  void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
+                                   const CXXMethodDecl *MD);
+  void mangleVirtualMemPtrThunk(
+      const CXXMethodDecl *MD,
+      const MicrosoftVTableContext::MethodVFTableLocation &ML);
   void mangleNumber(int64_t Number);
   void mangleType(QualType T, SourceRange Range,
                   QualifierMangleMode QMM = QMM_Mangle);
@@ -181,7 +188,6 @@
   virtual bool shouldMangleCXXName(const NamedDecl *D);
   virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
   virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
-                                        uint64_t OffsetInVFTable,
                                         raw_ostream &);
   virtual void mangleThunk(const CXXMethodDecl *MD,
                            const ThunkInfo &Thunk,
@@ -371,6 +377,130 @@
   }
 }
 
+void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
+                                                      const FieldDecl *FD) {
+  // <member-data-pointer> ::= <integer-literal>
+  //                       ::= $F <number> <number>
+  //                       ::= $G <number> <number> <number>
+
+  int64_t FO = 0;
+  MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+  if (FD) {
+    FO = getASTContext().getFieldOffset(FD);
+    assert(FO % getASTContext().getCharWidth() == 0 &&
+           "cannot take address of bitfield");
+    FO /= getASTContext().getCharWidth();
+  } else if (!RD->nullFieldOffsetIsZero()) {
+    FO = -1;
+  }
+
+  switch (IM) {
+  case MSInheritanceAttr::Keyword_single_inheritance:
+  case MSInheritanceAttr::Keyword_multiple_inheritance: {
+    // If we only have a single field, it's just an integer literal.
+    llvm::APSInt Val(64, /*isUnsigned=*/false);
+    Val = FO;
+    mangleIntegerLiteral(Val, /*IsBoolean=*/false);
+    break;
+  }
+
+  // Otherwise, we have an aggregate, but all adjusting fields should be zero,
+  // because we don't allow casts (even implicit) in the context of a template
+  // argument.
+  case MSInheritanceAttr::Keyword_virtual_inheritance:
+    Out << "$F";
+    mangleNumber(FO);
+    mangleNumber(0);
+    break;
+
+  case MSInheritanceAttr::Keyword_unspecified_inheritance:
+    Out << "$G";
+    mangleNumber(FO);
+    mangleNumber(0);
+    mangleNumber(0);
+    break;
+  }
+}
+
+void
+MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
+                                                     const CXXMethodDecl *MD) {
+  // <member-function-pointer> ::= $1? <name>
+  //                           ::= $H? <name> <number>
+  //                           ::= $I? <name> <number> <number>
+  //                           ::= $J? <name> <number> <number> <number>
+  //                           ::= $0A@
+
+  MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+
+  // The null member function pointer is $0A@ in function templates and crashes
+  // MSVC when used in class templates, so we don't know what they really look
+  // like.
+  if (!MD) {
+    Out << "$0A@";
+    return;
+  }
+
+  char Code = '\0';
+  switch (IM) {
+  case MSInheritanceAttr::Keyword_single_inheritance:      Code = '1'; break;
+  case MSInheritanceAttr::Keyword_multiple_inheritance:    Code = 'H'; break;
+  case MSInheritanceAttr::Keyword_virtual_inheritance:     Code = 'I'; break;
+  case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
+  }
+
+  Out << '$' << Code << '?';
+
+  // If non-virtual, mangle the name.  If virtual, mangle as a virtual memptr
+  // thunk.
+  uint64_t NVOffset = 0;
+  uint64_t VBTableOffset = 0;
+  if (!MD) {
+    mangleNumber(0);
+  } else if (MD->isVirtual()) {
+    MicrosoftVTableContext *VTContext =
+        cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
+    const MicrosoftVTableContext::MethodVFTableLocation &ML =
+        VTContext->getMethodVFTableLocation(GlobalDecl(MD));
+    mangleVirtualMemPtrThunk(MD, ML);
+    NVOffset = ML.VFPtrOffset.getQuantity();
+    VBTableOffset = ML.VBTableIndex * 4;
+    if (ML.VBase) {
+      DiagnosticsEngine &Diags = Context.getDiags();
+      unsigned DiagID = Diags.getCustomDiagID(
+          DiagnosticsEngine::Error,
+          "cannot mangle pointers to member functions from virtual bases");
+      Diags.Report(MD->getLocation(), DiagID);
+    }
+  } else {
+    mangleName(MD);
+    mangleFunctionEncoding(MD);
+  }
+
+  if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
+    mangleNumber(NVOffset);
+  if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+    mangleNumber(0);
+  if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+    mangleNumber(VBTableOffset);
+}
+
+void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
+    const CXXMethodDecl *MD,
+    const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+  // Get the vftable offset.
+  CharUnits PointerWidth = getASTContext().toCharUnitsFromBits(
+      getASTContext().getTargetInfo().getPointerWidth(0));
+  uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
+
+  Out << "?_9";
+  mangleName(MD->getParent());
+  Out << "$B";
+  mangleNumber(OffsetInVFTable);
+  Out << 'A';
+  Out << (PointersAre64Bit ? 'A' : 'E');
+}
+
 void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
   // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
   const DeclContext *DC = ND->getDeclContext();
@@ -928,7 +1058,7 @@
 void
 MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
                                      const TemplateArgumentList &TemplateArgs) {
-  // <template-args> ::= {<type> | <integer-literal>}+ @
+  // <template-args> ::= <template-arg>+ @
   unsigned NumTemplateArgs = TemplateArgs.size();
   for (unsigned i = 0; i < NumTemplateArgs; ++i) {
     const TemplateArgument &TA = TemplateArgs[i];
@@ -939,6 +1069,15 @@
 
 void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
                                                 const TemplateArgument &TA) {
+  // <template-arg> ::= <type>
+  //                ::= <integer-literal>
+  //                ::= <member-data-pointer>
+  //                ::= <member-function-pointer>
+  //                ::= $E? <name> <type-encoding>
+  //                ::= $1? <name> <type-encoding>
+  //                ::= $0A@
+  //                ::= <template-args>
+
   switch (TA.getKind()) {
   case TemplateArgument::Null:
     llvm_unreachable("Can't mangle null template arguments!");
@@ -951,16 +1090,31 @@
   }
   case TemplateArgument::Declaration: {
     const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
-    mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+    if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+      mangleMemberDataPointer(cast<CXXRecordDecl>(FD->getParent()), FD);
+    else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+      mangleMemberFunctionPointer(MD->getParent(), MD);
+    else
+      mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
     break;
   }
   case TemplateArgument::Integral:
     mangleIntegerLiteral(TA.getAsIntegral(),
                          TA.getIntegralType()->isBooleanType());
     break;
-  case TemplateArgument::NullPtr:
-    Out << "$0A@";
+  case TemplateArgument::NullPtr: {
+    QualType T = TA.getNullPtrType();
+    if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+      const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+      if (MPT->isMemberFunctionPointerType())
+        mangleMemberFunctionPointer(RD, 0);
+      else
+        mangleMemberDataPointer(RD, 0);
+    } else {
+      Out << "$0A@";
+    }
     break;
+  }
   case TemplateArgument::Expression:
     mangleExpression(TA.getAsExpr());
     break;
@@ -1924,17 +2078,17 @@
   }
 }
 
-void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
-    const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) {
-  bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
+void
+MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+                                                     raw_ostream &Out) {
+  MicrosoftVTableContext *VTContext =
+      cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
+  const MicrosoftVTableContext::MethodVFTableLocation &ML =
+      VTContext->getMethodVFTableLocation(GlobalDecl(MD));
 
   MicrosoftCXXNameMangler Mangler(*this, Out);
-  Mangler.getStream() << "\01??_9";
-  Mangler.mangleName(MD->getParent());
-  Mangler.getStream() << "$B";
-  Mangler.mangleNumber(OffsetInVFTable);
-  Mangler.getStream() << "A";
-  Mangler.getStream() << (Is64Bit ? "A" : "E");
+  Mangler.getStream() << "\01?";
+  Mangler.mangleVirtualMemPtrThunk(MD, ML);
 }
 
 void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -29,12 +29,8 @@
 using namespace clang;
 using namespace CodeGen;
 
-CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) : CGM(CGM) {
-  if (CGM.getTarget().getCXXABI().isMicrosoft())
-    VTContext.reset(new MicrosoftVTableContext(CGM.getContext()));
-  else
-    VTContext.reset(new ItaniumVTableContext(CGM.getContext()));
-}
+CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
+    : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {}
 
 llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, 
                                               const ThunkInfo &Thunk) {
Index: lib/CodeGen/CGVTables.h
===================================================================
--- lib/CodeGen/CGVTables.h
+++ lib/CodeGen/CGVTables.h
@@ -31,9 +31,8 @@
 class CodeGenVTables {
   CodeGenModule &CGM;
 
-  // FIXME: Consider moving VTContext into respective CXXABI classes?
-  OwningPtr<VTableContextBase> VTContext;
-  
+  VTableContextBase *VTContext;
+
   /// VTableAddressPointsMapTy - Address points for a single vtable.
   typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
 
@@ -71,11 +70,11 @@
   CodeGenVTables(CodeGenModule &CGM);
 
   ItaniumVTableContext &getItaniumVTableContext() {
-    return *cast<ItaniumVTableContext>(VTContext.get());
+    return *cast<ItaniumVTableContext>(VTContext);
   }
 
   MicrosoftVTableContext &getMicrosoftVTableContext() {
-    return *cast<MicrosoftVTableContext>(VTContext.get());
+    return *cast<MicrosoftVTableContext>(VTContext);
   }
 
   /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1327,44 +1327,6 @@
   CGF.EmitBlock(EndBlock);
 }
 
-// Member pointer helpers.
-static bool hasVBPtrOffsetField(MSInheritanceAttr::Spelling Inheritance) {
-  return Inheritance == MSInheritanceAttr::Keyword_unspecified_inheritance;
-}
-
-static bool hasOnlyOneField(bool IsMemberFunction,
-                            MSInheritanceAttr::Spelling Inheritance) {
-  if (IsMemberFunction)
-    return Inheritance <= MSInheritanceAttr::Keyword_single_inheritance;
-  return Inheritance <= MSInheritanceAttr::Keyword_multiple_inheritance;
-}
-
-// Only member pointers to functions need a this adjustment, since it can be
-// combined with the field offset for data pointers.
-static bool
-hasNonVirtualBaseAdjustmentField(bool IsMemberFunction,
-                                 MSInheritanceAttr::Spelling Inheritance) {
-  return IsMemberFunction &&
-         Inheritance >= MSInheritanceAttr::Keyword_multiple_inheritance;
-}
-
-static bool
-hasVirtualBaseAdjustmentField(MSInheritanceAttr::Spelling Inheritance) {
-  return Inheritance >= MSInheritanceAttr::Keyword_virtual_inheritance;
-}
-
-// Use zero for the field offset of a null data member pointer if we can
-// guarantee that zero is not a valid field offset, or if the member pointer has
-// multiple fields.  Polymorphic classes have a vfptr at offset zero, so we can
-// use zero for null.  If there are multiple fields, we can use zero even if it
-// is a valid field offset because null-ness testing will check the other
-// fields.
-static bool nullFieldOffsetIsZero(const CXXRecordDecl *RD) {
-  return RD->getMSInheritanceModel() >=
-             MSInheritanceAttr::Keyword_virtual_inheritance ||
-         (RD->hasDefinition() && 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.
@@ -1376,8 +1338,8 @@
   // valid field offset.
   const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
   MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
-  return (!hasVirtualBaseAdjustmentField(Inheritance) &&
-          nullFieldOffsetIsZero(RD));
+  return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) &&
+          RD->nullFieldOffsetIsZero());
 }
 
 llvm::Type *
@@ -1390,12 +1352,12 @@
   else
     fields.push_back(CGM.IntTy);  // FieldOffset
 
-  if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
-                                       Inheritance))
+  if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+                                          Inheritance))
     fields.push_back(CGM.IntTy);
-  if (hasVBPtrOffsetField(Inheritance))
+  if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
     fields.push_back(CGM.IntTy);
-  if (hasVirtualBaseAdjustmentField(Inheritance))
+  if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
     fields.push_back(CGM.IntTy);  // VirtualBaseAdjustmentOffset
 
   if (fields.size() == 1)
@@ -1413,18 +1375,18 @@
     // FunctionPointerOrVirtualThunk
     fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
   } else {
-    if (nullFieldOffsetIsZero(RD))
+    if (RD->nullFieldOffsetIsZero())
       fields.push_back(getZeroInt());  // FieldOffset
     else
       fields.push_back(getAllOnesInt());  // FieldOffset
   }
 
-  if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
-                                       Inheritance))
+  if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+                                          Inheritance))
     fields.push_back(getZeroInt());
-  if (hasVBPtrOffsetField(Inheritance))
+  if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
     fields.push_back(getZeroInt());
-  if (hasVirtualBaseAdjustmentField(Inheritance))
+  if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
     fields.push_back(getAllOnesInt());
 }
 
@@ -1449,25 +1411,25 @@
 
   // Single inheritance class member pointer are represented as scalars instead
   // of aggregates.
-  if (hasOnlyOneField(IsMemberFunction, Inheritance))
+  if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance))
     return FirstField;
 
   llvm::SmallVector<llvm::Constant *, 4> fields;
   fields.push_back(FirstField);
 
-  if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
+  if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance))
     fields.push_back(llvm::ConstantInt::get(
       CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
 
-  if (hasVBPtrOffsetField(Inheritance)) {
+  if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) {
     CharUnits Offs = CharUnits::Zero();
     if (RD->getNumVBases())
       Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
     fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Offs.getQuantity()));
   }
 
   // The rest of the fields are adjusted by conversions to a more derived class.
-  if (hasVirtualBaseAdjustmentField(Inheritance))
+  if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
     fields.push_back(getZeroInt());
 
   return llvm::ConstantStruct::getAnon(fields);
@@ -1552,7 +1514,7 @@
           getContext().getTargetInfo().getPointerWidth(0));
       uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
       llvm::raw_svector_ostream Out(ThunkName);
-      getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out);
+      getMangleContext().mangleVirtualMemPtrThunk(MD, Out);
       Out.flush();
 
       llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str());
@@ -1593,7 +1555,8 @@
   // single icmp.
   const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
   MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
-  if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance))
+  if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(),
+                                         Inheritance))
     return Builder.CreateICmp(Eq, L, R);
 
   // Compare the first field.
@@ -1785,9 +1748,9 @@
     // We need to extract values.
     unsigned I = 0;
     FieldOffset = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasVBPtrOffsetField(Inheritance))
+    if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
       VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasVirtualBaseAdjustmentField(Inheritance))
+    if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
       VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
   }
 
@@ -1840,7 +1803,7 @@
   CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
   CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
   if (IsReinterpret &&
-      nullFieldOffsetIsZero(SrcRD) == nullFieldOffsetIsZero(DstRD))
+      SrcRD->nullFieldOffsetIsZero() == DstRD->nullFieldOffsetIsZero())
     return Src;
 
   CGBuilderTy &Builder = CGF.Builder;
@@ -1870,15 +1833,15 @@
   llvm::Value *VirtualBaseAdjustmentOffset = 0;
   llvm::Value *VBPtrOffset = 0;
   MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel();
-  if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+  if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
     // We need to extract values.
     unsigned I = 0;
     FirstField = Builder.CreateExtractValue(Src, I++);
-    if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+    if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
       NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
-    if (hasVBPtrOffsetField(SrcInheritance))
+    if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
       VBPtrOffset = Builder.CreateExtractValue(Src, I++);
-    if (hasVirtualBaseAdjustmentField(SrcInheritance))
+    if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
       VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
   }
 
@@ -1902,19 +1865,19 @@
   // Recompose dst from the null struct and the adjusted fields from src.
   MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel();
   llvm::Value *Dst;
-  if (hasOnlyOneField(IsFunc, DstInheritance)) {
+  if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) {
     Dst = FirstField;
   } else {
     Dst = llvm::UndefValue::get(DstNull->getType());
     unsigned Idx = 0;
     Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
-    if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+    if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
       Dst = Builder.CreateInsertValue(
         Dst, getValueOrZeroInt(NonVirtualBaseAdjustment), Idx++);
-    if (hasVBPtrOffsetField(DstInheritance))
+    if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
       Dst = Builder.CreateInsertValue(
         Dst, getValueOrZeroInt(VBPtrOffset), Idx++);
-    if (hasVirtualBaseAdjustmentField(DstInheritance))
+    if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
       Dst = Builder.CreateInsertValue(
         Dst, getValueOrZeroInt(VirtualBaseAdjustmentOffset), Idx++);
   }
@@ -1955,15 +1918,15 @@
   llvm::Constant *VirtualBaseAdjustmentOffset = 0;
   llvm::Constant *VBPtrOffset = 0;
   bool IsFunc = SrcTy->isMemberFunctionPointer();
-  if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+  if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
     // We need to extract values.
     unsigned I = 0;
     FirstField = Src->getAggregateElement(I++);
-    if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+    if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
       NonVirtualBaseAdjustment = Src->getAggregateElement(I++);
-    if (hasVBPtrOffsetField(SrcInheritance))
+    if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
       VBPtrOffset = Src->getAggregateElement(I++);
-    if (hasVirtualBaseAdjustmentField(SrcInheritance))
+    if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
       VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++);
   }
 
@@ -1986,16 +1949,16 @@
   // FIXME PR15713: Support conversions through virtually derived classes.
 
   // Recompose dst from the null struct and the adjusted fields from src.
-  if (hasOnlyOneField(IsFunc, DstInheritance))
+  if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance))
     return FirstField;
 
   llvm::SmallVector<llvm::Constant *, 4> Fields;
   Fields.push_back(FirstField);
-  if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+  if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
     Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment));
-  if (hasVBPtrOffsetField(DstInheritance))
+  if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
     Fields.push_back(getConstantOrZeroInt(VBPtrOffset));
-  if (hasVirtualBaseAdjustmentField(DstInheritance))
+  if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
     Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset));
   return llvm::ConstantStruct::getAnon(Fields);
 }
@@ -2026,11 +1989,11 @@
     // We need to extract values.
     unsigned I = 0;
     FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
+    if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance))
       NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasVBPtrOffsetField(Inheritance))
+    if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
       VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasVirtualBaseAdjustmentField(Inheritance))
+    if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
       VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
   }
 
Index: test/CodeGenCXX/mangle-ms-templates-memptrs.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/mangle-ms-templates-memptrs.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -Wno-microsoft -fno-rtti -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
+
+struct U;
+static_assert(sizeof(void (U::*)()) == 2 * sizeof(void*) + 2 * sizeof(int), "");
+
+struct A { int a; };
+struct B { int b; };
+
+struct S             { int a, b; void f(); virtual void g(); };
+struct M : A, B      { int a, b; void f(); virtual void g(); };
+struct V : virtual A { int a, b; void f(); virtual void g(); };
+struct U             { int a, b; void f(); virtual void g(); };
+
+struct C        { virtual void f(); };
+struct D        { virtual void g(); };
+struct O : C, D { virtual void g(); }; // override of non-primary
+
+// Test data member pointers.
+template <typename T, int T::*F>
+int ReadField(T &o) {
+  return F ? o.*F : 0;
+}
+
+void ReadFields() {
+  A a;
+  S s;
+  M m;
+  V v;
+  U u;
+  ReadField<S, &S::a>(s);
+  ReadField<M, &M::a>(m);
+  ReadField<V, &V::a>(v);
+  ReadField<U, &U::a>(u);
+  ReadField<S, &S::b>(s);
+  ReadField<M, &M::b>(m);
+  ReadField<V, &V::b>(v);
+  ReadField<U, &U::b>(u);
+  ReadField<S, nullptr>(s);
+  ReadField<M, nullptr>(m);
+  ReadField<V, nullptr>(v);
+  ReadField<U, nullptr>(u);
+
+  // Non-polymorphic null data memptr vs first field memptr.
+  ReadField<A, &A::a>(a);
+  ReadField<A, nullptr>(a);
+}
+
+// CHECK-LABEL: define {{.*}}ReadFields
+// CHECK: call {{.*}} @"\01??$ReadField@US@@$03@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0M@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@US@@$07@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z"
+
+// MSVC mangles null member pointers in function templates wrong, but it gets
+// them right in class templates.
+// CHECK: call {{.*}} @"\01??$ReadField@US@@$0A@@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0A@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UV@@$FA@A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UU@@$GA@A@A@@@YAHAAUU@@@Z"
+
+// Non-polymorphic null data memptr vs first field memptr.  MSVC mangles these
+// the same.
+// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0A@@@YAHAAUA@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0?0@@YAHAAUA@@@Z"
+
+// Test member function pointers.
+template <typename T, void (T::*MFP)()>
+void CallMethod(T &o) {
+  (o.*MFP)();
+}
+
+void CallMethods() {
+  S s;
+  M m;
+  V v;
+  U u;
+  O o;
+
+  // Non-virtual methods.
+  CallMethod<S, &S::f>(s);
+  CallMethod<M, &M::f>(m);
+  CallMethod<V, &V::f>(v);
+  CallMethod<U, &U::f>(u);
+
+  // Virtual methods requiring thunk mangling.
+  CallMethod<S, &S::g>(s);
+  CallMethod<M, &M::g>(m);
+  CallMethod<V, &V::g>(v);
+  CallMethod<U, &U::g>(u);
+
+  // A member pointer for a non-primary vbase will have a non-zero this
+  // adjustment.
+  CallMethod<O, &O::g>(o);
+
+  // Null member pointers.
+  CallMethod<S, nullptr>(s);
+  CallMethod<M, nullptr>(m);
+  CallMethod<V, nullptr>(v);
+  CallMethod<U, nullptr>(u);
+}
+
+// CHECK-LABEL: define {{.*}}CallMethods
+// CHECK: call {{.*}} @"\01??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z"
+
+// PR17034: MSVC reuses the same thunk for every virtual g method because they
+// are all at vftable offset zero.  They then mangle the name of the first thunk
+// created into the name of the template instantiation, which is definitely a
+// bug.  We don't follow them here.  Instead of ?_91@ backref below, they would
+// get ?_9S@@ in every instantiation after the first.
+
+// CHECK: call {{.*}} @"\01??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z"
+
+// CHECK: call {{.*}} @"\01??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z"
+
+// CHECK: call {{.*}} @"\01??$CallMethod@US@@$0A@@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z"
Index: test/SemaCXX/cxx98-compat.cpp
===================================================================
--- test/SemaCXX/cxx98-compat.cpp
+++ test/SemaCXX/cxx98-compat.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT
+// RUN: %clang_cc1 -Wno-microsoft -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
+// RUN: %clang_cc1 -Wno-microsoft -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT
 
 namespace std {
   struct type_info;
Index: test/SemaCXX/nullptr.cpp
===================================================================
--- test/SemaCXX/nullptr.cpp
+++ test/SemaCXX/nullptr.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s
+// RUN: %clang_cc1 -triple %ms_abi_triple -DMS_ABI -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s
+
 #include <stdint.h>
 
 typedef decltype(nullptr) nullptr_t;
@@ -75,10 +77,22 @@
 }
 
 // Template arguments can be nullptr.
-template <int *PI, void (*PF)(), int A::*PM, void (A::*PMF)()>
+template <int *PI,
+         void (*PF)(),
+#ifdef MS_ABI
+  // expected-note@+2 {{template parameter is declared here}}
+#endif
+          int A::*PM,
+          void (A::*PMF)()>
 struct T {};
 
-typedef T<nullptr, nullptr, nullptr, nullptr> NT;
+typedef T<nullptr,
+          nullptr,
+#ifdef MS_ABI
+  // expected-warning@+2 {{template instantiation with a null pointer to data member is unstable in the Microsoft C++ ABI}}
+#endif
+          nullptr,
+          nullptr> NT;
 
 namespace test1 { 
 template<typename T, typename U> struct is_same {
@@ -171,11 +185,18 @@
   
   X<int, nullptr> x;
 
-
-  template<int (*fp)(int), int* p, int A::* pmd, int (A::*pmf)(int)>
+  template <int (*fp)(int), int *p,
+#ifdef MS_ABI
+  // expected-note@+2 {{template parameter is declared here}}
+#endif
+            int A::*pmd, int (A::*pmf)(int)>
   struct X2 {};
-  
-  X2<nullptr, nullptr, nullptr, nullptr> x2;
+
+  X2<nullptr, nullptr,
+#ifdef MS_ABI
+  // expected-warning@+2 {{template instantiation with a null pointer to data member is unstable in the Microsoft C++ ABI}}
+#endif
+     nullptr, nullptr> x2;
 }
 
 namespace null_pointer_constant {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to