r200857 - MS ABI: Mangle member pointer template arguments

Reid Kleckner reid at kleckner.net
Wed Feb 5 09:27:09 PST 2014


Author: rnk
Date: Wed Feb  5 11:27:08 2014
New Revision: 200857

URL: http://llvm.org/viewvc/llvm-project?rev=200857&view=rev
Log:
MS ABI: Mangle member pointer template arguments

Member pointers are mangled as they would be represented at runtime.
They can be a single integer literal, single decl, or a tuple with some
more numbers tossed in.  With Clang today, most of those numbers will be
zero because we reject pointers to members of virtual bases.

This change required moving VTableContextBase ownership from
CodeGenVTables to ASTContext, because mangling now depends on vtable
layout.

I also hoisted the inheritance model helpers up to be inline static
methods of MSInheritanceAttr.  This makes the AST code that deals with
member pointers much more readable.

MSVC doesn't appear to have stable manglings of null member pointers:
- Null data memptrs in function templates have a mangling collision with
  the first field of a non-polymorphic single inheritance class.
- The mangling of null data memptrs changes if you add casts.
- Large null function memptrs in class templates crash MSVC.

Clang uses the class template mangling for null data memptrs and the
function template mangling for null function memptrs to deal with this.

Reviewers: majnemer

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

Added:
    cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/MicrosoftCXXABI.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CGVTables.h
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Feb  5 11:27:08 2014
@@ -66,6 +66,7 @@ namespace clang {
   class UnresolvedSetIterator;
   class UsingDecl;
   class UsingShadowDecl;
+  class VTableContextBase;
 
   namespace Builtin { class Context; }
 
@@ -1731,6 +1732,8 @@ public:
 
   bool isNearlyEmpty(const CXXRecordDecl *RD) const;
 
+  VTableContextBase *getVTableContext();
+
   MangleContext *createMangleContext();
   
   void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
@@ -2292,6 +2295,8 @@ private:
   void ReleaseDeclContextMaps();
 
   llvm::OwningPtr<ParentMap> AllParents;
+
+  llvm::OwningPtr<VTableContextBase> VTContext;
 };
 
 /// \brief Utility function for constructing a nullary selector.

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Feb  5 11:27:08 2014
@@ -1605,6 +1605,18 @@ public:
   /// \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.

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Wed Feb  5 11:27:08 2014
@@ -200,7 +200,6 @@ public:
                                 raw_ostream &Out) = 0;
 
   virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
-                                        uint64_t OffsetInVFTable,
                                         raw_ostream &) = 0;
 
   static bool classof(const MangleContext *C) {

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed Feb  5 11:27:08 2014
@@ -1401,6 +1401,28 @@ def MSInheritance : InheritableAttr {
                    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 {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Feb  5 11:27:08 2014
@@ -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 @@ bool ASTContext::isNearlyEmpty(const CXX
   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:

Modified: cfe/trunk/lib/AST/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftCXXABI.cpp?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftCXXABI.cpp Wed Feb  5 11:27:08 2014
@@ -136,14 +136,14 @@ void CXXRecordDecl::setMSInheritanceMode
 //     // 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) {
@@ -151,37 +151,17 @@ getMSMemberPointerSlots(const MemberPoin
   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);
 }
 

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Wed Feb  5 11:27:08 2014
@@ -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 @@ public:
   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 @@ public:
   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::mangleVari
   }
 }
 
+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 @@ MicrosoftCXXNameMangler::mangleExpressio
 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 @@ MicrosoftCXXNameMangler::mangleTemplateA
 
 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 @@ void MicrosoftCXXNameMangler::mangleTemp
   }
   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 @@ static void mangleThunkThisAdjustment(co
   }
 }
 
-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,

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Wed Feb  5 11:27:08 2014
@@ -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) {

Modified: cfe/trunk/lib/CodeGen/CGVTables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.h (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.h Wed Feb  5 11:27:08 2014
@@ -31,9 +31,8 @@ namespace CodeGen {
 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 @@ public:
   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

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=200857&r1=200856&r2=200857&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Feb  5 11:27:08 2014
@@ -1327,44 +1327,6 @@ void MicrosoftCXXABI::EmitGuardedInit(Co
   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 @@ bool MicrosoftCXXABI::isZeroInitializabl
   // 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 @@ MicrosoftCXXABI::ConvertMemberPointerTyp
   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 @@ GetNullMemberPointerFields(const MemberP
     // 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,17 +1411,17 @@ MicrosoftCXXABI::EmitFullMemberPointer(l
 
   // 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();
@@ -1467,7 +1429,7 @@ MicrosoftCXXABI::EmitFullMemberPointer(l
   }
 
   // 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 @@ MicrosoftCXXABI::BuildMemberPointer(cons
           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 @@ MicrosoftCXXABI::EmitMemberPointerCompar
   // 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 @@ MicrosoftCXXABI::EmitMemberDataPointerAd
     // 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 @@ MicrosoftCXXABI::EmitMemberPointerConver
   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 @@ MicrosoftCXXABI::EmitMemberPointerConver
   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 @@ MicrosoftCXXABI::EmitMemberPointerConver
   // 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 @@ MicrosoftCXXABI::EmitMemberPointerConver
   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 @@ MicrosoftCXXABI::EmitMemberPointerConver
   // 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 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctio
     // 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++);
   }
 

Added: cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp?rev=200857&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp Wed Feb  5 11:27:08 2014
@@ -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 at US@@$03@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UM@@$0M@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UV@@$F7A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UU@@$G3A at A@@@YAHAAUU@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at US@@$07@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UM@@$0BA@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UV@@$FM at A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UU@@$G7A at A@@@YAHAAUU@@@Z"
+
+// MSVC mangles null member pointers in function templates wrong, but it gets
+// them right in class templates.
+// CHECK: call {{.*}} @"\01??$ReadField at US@@$0A@@@YAHAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UM@@$0A@@@YAHAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UV@@$FA at A@@@YAHAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at UU@@$GA at A@A@@@YAHAAUU@@@Z"
+
+// Non-polymorphic null data memptr vs first field memptr.  MSVC mangles these
+// the same.
+// CHECK: call {{.*}} @"\01??$ReadField at UA@@$0A@@@YAHAAUA@@@Z"
+// CHECK: call {{.*}} @"\01??$ReadField at 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 at US@@$1?f at 1@QAEXXZ@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UM@@$H?f at 1@QAEXXZA@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UV@@$I?f at 1@QAEXXZA at A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UU@@$J?f at 1@QAEXXZA at 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 at US@@$1??_91@$BA at AE@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UM@@$H??_91@$BA at AEA@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UV@@$I??_91@$BA at AEA@A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UU@@$J??_91@$BA at AEA@A at A@@@YAXAAUU@@@Z"
+
+// CHECK: call {{.*}} @"\01??$CallMethod at UO@@$H??_91@$BA at AE3@@YAXAAUO@@@Z"
+
+// CHECK: call {{.*}} @"\01??$CallMethod at US@@$0A@@@YAXAAUS@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UM@@$0A@@@YAXAAUM@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UV@@$0A@@@YAXAAUV@@@Z"
+// CHECK: call {{.*}} @"\01??$CallMethod at UU@@$0A@@@YAXAAUU@@@Z"





More information about the cfe-commits mailing list