Emit virtual/deleting destructors properly with -cxx-abi microsoft, PR15058

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175045 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 326b0d3..baa16b0 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -28,12 +28,25 @@
 
 namespace {
 
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+  if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+    return ftd->getTemplatedDecl();
+
+  return fn;
+}
+
 /// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
 /// Microsoft Visual C++ ABI.
 class MicrosoftCXXNameMangler {
   MangleContext &Context;
   raw_ostream &Out;
 
+  /// The "structor" is the top-level declaration being mangled, if
+  /// that's not a template specialization; otherwise it's the pattern
+  /// for that specialization.
+  const NamedDecl *Structor;
+  unsigned StructorType;
+
   // FIXME: audit the performance of BackRefMap as it might do way too many
   // copying of strings.
   typedef std::map<std::string, unsigned> BackRefMap;
@@ -47,7 +60,15 @@
 
 public:
   MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
-  : Context(C), Out(Out_), UseNameBackReferences(true) { }
+    : Context(C), Out(Out_),
+      Structor(0), StructorType(-1),
+      UseNameBackReferences(true) { }
+
+  MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
+                          const CXXDestructorDecl *D, CXXDtorType Type)
+    : Context(C), Out(Out_),
+      Structor(getStructor(D)), StructorType(Type),
+      UseNameBackReferences(true) { }
 
   raw_ostream &getStream() const { return Out; }
 
@@ -68,6 +89,7 @@
   void mangleSourceName(const IdentifierInfo *II);
   void manglePostfix(const DeclContext *DC, bool NoFunction=false);
   void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
+  void mangleCXXDtorType(CXXDtorType T);
   void mangleQualifiers(Qualifiers Quals, bool IsMember);
   void manglePointerQualifiers(Qualifiers Quals);
 
@@ -485,7 +507,14 @@
       break;
       
     case DeclarationName::CXXDestructorName:
-      Out << "?1";
+      if (ND == Structor)
+        // If the named decl is the C++ destructor we're mangling,
+        // use the type we were given.
+        mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+      else
+        // Otherwise, use the complete destructor name. This is relevant if a
+        // class with a destructor is declared within a destructor.
+        mangleCXXDtorType(Dtor_Complete);
       break;
       
     case DeclarationName::CXXConversionFunctionName:
@@ -543,6 +572,23 @@
   }
 }
 
+void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+  switch (T) {
+  case Dtor_Deleting:
+    Out << "?_G";
+    return;
+  case Dtor_Base:
+    // FIXME: We should be asked to mangle base dtors.
+    // However, fixing this would require larger changes to the CodeGenModule.
+    // Please put llvm_unreachable here when CGM is changed.
+    // For now, just mangle a base dtor the same way as a complete dtor...
+  case Dtor_Complete:
+    Out << "?1";
+    return;
+  }
+  llvm_unreachable("Unsupported dtor type?");
+}
+
 void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
                                                  SourceLocation Loc) {
   switch (OO) {
@@ -1110,9 +1156,18 @@
 
   // <return-type> ::= <type>
   //               ::= @ # structors (they have no declared return type)
-  if (IsStructor)
+  if (IsStructor) {
+    if (isa<CXXDestructorDecl>(D) && D == Structor &&
+        StructorType == Dtor_Deleting) {
+      // The scalar deleting destructor takes an extra int argument.
+      // However, the FunctionType generated has 0 arguments.
+      // FIXME: This is a temporary hack.
+      // Maybe should fix the FunctionType creation instead?
+      Out << "PAXI@Z";
+      return;
+    }
     Out << '@';
-  else {
+  } else {
     QualType Result = Proto->getResultType();
     const Type* RT = Result.getTypePtr();
     if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
@@ -1711,7 +1766,7 @@
 void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
                                            CXXDtorType Type,
                                            raw_ostream & Out) {
-  MicrosoftCXXNameMangler mangler(*this, Out);
+  MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
   mangler.mangle(D);
 }
 void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 9a03faa..f80232f 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -1160,6 +1160,8 @@
       break;
     case VTableComponent::CK_DeletingDtorPointer:
       // We've already added the thunk when we saw the complete dtor pointer.
+      // FIXME: check how this works in the Microsoft ABI
+      // while working on the multiple inheritance patch.
       continue;
     }
 
@@ -1302,11 +1304,8 @@
       Components.push_back(VTableComponent::MakeCompleteDtor(DD));
       Components.push_back(VTableComponent::MakeDeletingDtor(DD));
     } else {
-      // Add only one destructor in MS mode.
-      // FIXME: The virtual destructors are handled differently in MS ABI,
-      // we should add such a support later. For now, put the complete
-      // destructor into the vftable just to make its layout right.
-      Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+      // Add the scalar deleting destructor.
+      Components.push_back(VTableComponent::MakeDeletingDtor(DD));
     }
   } else {
     // Add the return adjustment if necessary.
@@ -1951,6 +1950,8 @@
       Out << DD->getQualifiedNameAsString();
       if (IsComplete)
         Out << "() [complete]";
+      else if (isMicrosoftABI())
+        Out << "() [scalar deleting]";
       else
         Out << "() [deleting]";
 
@@ -2142,8 +2143,8 @@
         IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
           = MethodName + " [deleting]";
       } else {
-        IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
-          = MethodName;
+        IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+          = MethodName + " [scalar deleting]";
       }
     } else {
       IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
@@ -2275,8 +2276,9 @@
             MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
               getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
           } else {
-            MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
-              getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+            // Add the scalar deleting destructor.
+            MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+              getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
           }
         } else {
           MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
@@ -2302,11 +2304,8 @@
         // Add the deleting dtor.
         MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
       } else {
-        // Add only the deleting dtor.
-        // FIXME: The virtual destructors are handled differently in MS ABI,
-        // we should add such a support later. For now, put the complete
-        // destructor into the vftable indices.
-        MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+        // Add the scalar deleting dtor.
+        MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
       }
     } else {
       // Add the entry.