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.
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index c319c06..80798e7 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -54,11 +54,20 @@
     return CGF.CXXABIThisValue;
   }
 
+  // FIXME: Every place that calls getVTT{Decl,Value} is something
+  // that needs to be abstracted properly.
   ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) {
-    return CGF.CXXVTTDecl;
+    return CGF.CXXStructorImplicitParamDecl;
   }
   llvm::Value *&getVTTValue(CodeGenFunction &CGF) {
-    return CGF.CXXVTTValue;
+    return CGF.CXXStructorImplicitParamValue;
+  }
+
+  ImplicitParamDecl *&getStructorImplicitParamDecl(CodeGenFunction &CGF) {
+    return CGF.CXXStructorImplicitParamDecl;
+  }
+  llvm::Value *&getStructorImplicitParamValue(CodeGenFunction &CGF) {
+    return CGF.CXXStructorImplicitParamValue;
   }
 
   /// Build a parameter variable suitable for 'this'.
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index ce32acd..4e4acc8 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -953,6 +953,32 @@
     }
   };
 
+  struct CallDtorDeleteConditional : EHScopeStack::Cleanup {
+    llvm::Value *ShouldDeleteCondition;
+  public:
+    CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition)
+      : ShouldDeleteCondition(ShouldDeleteCondition) {
+      assert(ShouldDeleteCondition != NULL);
+    }
+
+    void Emit(CodeGenFunction &CGF, Flags flags) {
+      llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
+      llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
+      llvm::Value *ShouldCallDelete
+        = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
+      CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
+
+      CGF.EmitBlock(callDeleteBB);
+      const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
+      const CXXRecordDecl *ClassDecl = Dtor->getParent();
+      CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
+                         CGF.getContext().getTagDeclType(ClassDecl));
+      CGF.Builder.CreateBr(continueBB);
+
+      CGF.EmitBlock(continueBB);
+    }
+  };
+
   class DestroyField  : public EHScopeStack::Cleanup {
     const FieldDecl *field;
     CodeGenFunction::Destroyer *destroyer;
@@ -991,7 +1017,14 @@
   if (DtorType == Dtor_Deleting) {
     assert(DD->getOperatorDelete() && 
            "operator delete missing - EmitDtorEpilogue");
-    EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+    if (CXXStructorImplicitParamValue) {
+      // If there is an implicit param to the deleting dtor, it's a boolean
+      // telling whether we should call delete at the end of the dtor.
+      EHStack.pushCleanup<CallDtorDeleteConditional>(
+          NormalAndEHCleanup, CXXStructorImplicitParamValue);
+    } else {
+      EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+    }
     return;
   }
 
@@ -1243,7 +1276,8 @@
 
   // FIXME: Provide a source location here.
   EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
-                    VTT, ArgBeg, ArgEnd);
+                    VTT, getContext().getPointerType(getContext().VoidPtrTy),
+                    ArgBeg, ArgEnd);
 }
 
 void
@@ -1399,7 +1433,8 @@
   
   // FIXME: Provide a source location here.
   EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
-                    VTT, 0, 0);
+                    VTT, getContext().getPointerType(getContext().VoidPtrTy),
+                    0, 0);
 }
 
 namespace {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index d2db71c..1aaa667 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -28,7 +28,8 @@
                                           llvm::Value *Callee,
                                           ReturnValueSlot ReturnValue,
                                           llvm::Value *This,
-                                          llvm::Value *VTT,
+                                          llvm::Value *ImplicitParam,
+                                          QualType ImplicitParamTy,
                                           CallExpr::const_arg_iterator ArgBeg,
                                           CallExpr::const_arg_iterator ArgEnd) {
   assert(MD->isInstance() &&
@@ -46,10 +47,9 @@
   // Push the this ptr.
   Args.add(RValue::get(This), MD->getThisType(getContext()));
 
-  // If there is a VTT parameter, emit it.
-  if (VTT) {
-    QualType T = getContext().getPointerType(getContext().VoidPtrTy);
-    Args.add(RValue::get(VTT), T);
+  // If there is an implicit parameter (e.g. VTT), emit it.
+  if (ImplicitParam) {
+    Args.add(RValue::get(ImplicitParam), ImplicitParamTy);
   }
 
   const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -316,7 +316,8 @@
   }
 
   return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
-                           /*VTT=*/0, CE->arg_begin(), CE->arg_end());
+                           /*ImplicitParam=*/0, QualType(),
+                           CE->arg_begin(), CE->arg_end());
 }
 
 RValue
@@ -388,7 +389,8 @@
 
   llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
   return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
-                           /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
+                           /*ImplicitParam=*/0, QualType(),
+                           E->arg_begin() + 1, E->arg_end());
 }
 
 RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -1408,7 +1410,7 @@
                                  Ptr, Ty);
         // FIXME: Provide a source location here.
         CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
-                              Ptr, /*VTT=*/0, 0, 0);
+                              Ptr, /*ImplicitParam=*/0, QualType(), 0, 0);
 
         if (UseGlobalDelete) {
           CGF.PopCleanupBlock();
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index ec139df..cba3316 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -43,8 +43,9 @@
     FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
     DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
     IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
-    CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
-    CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
+    CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
+    CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
+    OutermostConditional(0), TerminateLandingPad(0),
     TerminateHandler(0), TrapBB(0) {
   if (!suppressNewContext)
     CGM.getCXXABI().getMangleContext().startNewFunction();
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index d43b588..ea5e873 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1179,11 +1179,10 @@
   llvm::Value *CXXABIThisValue;
   llvm::Value *CXXThisValue;
 
-  /// CXXVTTDecl - When generating code for a base object constructor or
-  /// base object destructor with virtual bases, this will hold the implicit
-  /// VTT parameter.
-  ImplicitParamDecl *CXXVTTDecl;
-  llvm::Value *CXXVTTValue;
+  /// CXXStructorImplicitParamDecl - When generating code for a constructor or
+  /// destructor, this will hold the implicit argument (e.g. VTT).
+  ImplicitParamDecl *CXXStructorImplicitParamDecl;
+  llvm::Value *CXXStructorImplicitParamValue;
 
   /// OutermostConditional - Points to the outermost active
   /// conditional control.  This is used so that we know if a
@@ -1777,9 +1776,19 @@
 
   /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
   /// virtual bases.
+  // FIXME: Every place that calls LoadCXXVTT is something
+  // that needs to be abstracted properly.
   llvm::Value *LoadCXXVTT() {
-    assert(CXXVTTValue && "no VTT value for this function");
-    return CXXVTTValue;
+    assert(CXXStructorImplicitParamValue && "no VTT value for this function");
+    return CXXStructorImplicitParamValue;
+  }
+
+  /// LoadCXXStructorImplicitParam - Load the implicit parameter
+  /// for a constructor/destructor.
+  llvm::Value *LoadCXXStructorImplicitParam() {
+    assert(CXXStructorImplicitParamValue &&
+           "no implicit argument value for this function");
+    return CXXStructorImplicitParamValue;
   }
 
   /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
@@ -2294,7 +2303,8 @@
                            llvm::Value *Callee,
                            ReturnValueSlot ReturnValue,
                            llvm::Value *This,
-                           llvm::Value *VTT,
+                           llvm::Value *ImplicitParam,
+                           QualType ImplicitParamTy,
                            CallExpr::const_arg_iterator ArgBeg,
                            CallExpr::const_arg_iterator ArgEnd);
   RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 477720b..537e457 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -45,10 +45,7 @@
   void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
                                 CXXDtorType Type,
                                 CanQualType &ResTy,
-                                SmallVectorImpl<CanQualType> &ArgTys) {
-    // 'this' is already in place
-    // TODO: 'for base' flag
-  }
+                                SmallVectorImpl<CanQualType> &ArgTys);
 
   void BuildInstanceFunctionParams(CodeGenFunction &CGF,
                                    QualType &ResTy,
@@ -121,6 +118,27 @@
   ResTy = ArgTys[0];
 }
 
+void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
+                                               CXXDtorType Type,
+                                               CanQualType &ResTy,
+                                        SmallVectorImpl<CanQualType> &ArgTys) {
+  // 'this' is already in place
+  // TODO: 'for base' flag
+
+  if (Type == Dtor_Deleting) {
+    // The scalar deleting destructor takes an implicit bool parameter.
+    ArgTys.push_back(CGM.getContext().BoolTy);
+  }
+}
+
+static bool IsDeletingDtor(GlobalDecl GD) {
+  const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
+  if (isa<CXXDestructorDecl>(MD)) {
+    return GD.getDtorType() == Dtor_Deleting;
+  }
+  return false;
+}
+
 void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
                                                   QualType &ResTy,
                                                   FunctionArgList &Params) {
@@ -128,6 +146,17 @@
   if (needThisReturn(CGF.CurGD)) {
     ResTy = Params[0]->getType();
   }
+  if (IsDeletingDtor(CGF.CurGD)) {
+    ASTContext &Context = getContext();
+
+    ImplicitParamDecl *ShouldDelete
+      = ImplicitParamDecl::Create(Context, 0,
+                                  CGF.CurGD.getDecl()->getLocation(),
+                                  &Context.Idents.get("should_call_delete"),
+                                  Context.BoolTy);
+    Params.push_back(ShouldDelete);
+    getStructorImplicitParamDecl(CGF) = ShouldDelete;
+  }
 }
 
 void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
@@ -135,6 +164,14 @@
   if (needThisReturn(CGF.CurGD)) {
     CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
   }
+  if (IsDeletingDtor(CGF.CurGD)) {
+    assert(getStructorImplicitParamDecl(CGF) &&
+           "no implicit parameter for a deleting destructor?");
+    getStructorImplicitParamValue(CGF)
+      = CGF.Builder.CreateLoad(
+          CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+          "should_call_delete");
+  }
 }
 
 bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 12622f1..16763d5 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1
+// RUN: FileCheck %s < %t
+// Using a different check prefix as the inline destructors might be placed
+// anywhere in the output.
+// RUN: FileCheck --check-prefix=DTORS %s < %t
 
 class A {
  public:
@@ -23,13 +27,60 @@
 }
 
 struct B {
-  virtual ~B();
+  virtual ~B() {
+// Complete destructor first:
+// DTORS: define {{.*}} x86_thiscallcc void @"\01??1B@@UAE@XZ"(%struct.B* %this)
+//
+// Then, the scalar deleting destructor (used in the vtable):
+// DTORS:      define {{.*}} x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"(%struct.B* %this, i1 zeroext %should_call_delete)
+// DTORS:        %0 = icmp eq i8 %should_call_delete{{.*}}, 0
+// DTORS-NEXT:   br i1 %0, label %dtor.continue, label %dtor.call_delete
+// DTORS:      dtor.call_delete:
+// DTORS-NEXT:   %1 = bitcast %struct.B* %this1 to i8*
+// DTORS-NEXT:   call void @"\01??3@YAXPAX@Z"(i8* %1) nounwind
+// DTORS-NEXT:   br label %dtor.continue
+// DTORS:      dtor.continue:
+// DTORS-NEXT:   ret void
+  }
   virtual void foo();
 };
 
+// Emits the vftable in the output.
+void B::foo() {}
+
 void check_vftable_offset() {
   B b;
 // The vftable pointer should point at the beginning of the vftable.
 // CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %struct.B* {{.*}} to i8***
 // CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7B@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
 }
+
+// FIXME: Enable the following block and add expectations when calls
+// to virtual complete dtor are supported.
+#if 0
+void call_complete_dtor(B *obj_ptr) {
+  obj_ptr->~B();
+}
+#endif
+
+void call_deleting_dtor(B *obj_ptr) {
+// FIXME: Add CHECKs when calls to virtual deleting dtor are generated properly.
+  delete obj_ptr;
+}
+
+struct C {
+  static int foo();
+
+  C() {
+    static int ctor_static = foo();
+    // CHECK that the static in the ctor gets mangled correctly:
+    // CHECK: @"\01?ctor_static@?1???0C@@QAE@XZ@4HA"
+  }
+  ~C() {
+    static int dtor_static = foo();
+    // CHECK that the static in the dtor gets mangled correctly:
+    // CHECK: @"\01?dtor_static@?1???1C@@QAE@XZ@4HA"
+  }
+};
+
+void use_C() { C c; }
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
index 176ecf1..5d430db 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -37,10 +37,10 @@
 
 struct C {
   // CHECK-C: Vtable for 'C' (2 entries)
-  // CHECK-C-NEXT: 0 | C::~C()
+  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
   // CHECK-C-NEXT: 1 | void C::f()
   // CHECK-C: VTable indices for 'C' (2 entries).
-  // CHECK-C-NEXT: 0 | C::~C()
+  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
   // CHECK-C-NEXT: 1 | void C::f()
   // Never used, so doesn't emit a vtable.
   virtual ~C();
@@ -52,7 +52,7 @@
 struct D {
   // CHECK-D: Vtable for 'D' (2 entries)
   // CHECK-D-NEXT: 0 | void D::f()
-  // CHECK-D-NEXT: 1 | D::~D()
+  // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
   // EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*]
   virtual void f();
 
@@ -65,10 +65,10 @@
   // CHECK-E-NEXT: 0 | void A::f()
   // CHECK-E-NEXT: 1 | void A::g()
   // CHECK-E-NEXT: 2 | void A::h()
-  // CHECK-E-NEXT: 3 | E::~E()
+  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
   // CHECK-E-NEXT: 4 | void E::i()
   // CHECK-E: VTable indices for 'E' (2 entries).
-  // CHECK-E-NEXT: 3 | E::~E()
+  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
   // CHECK-E-NEXT: 4 | void E::i()
 
   // Never used, so doesn't emit a vtable.
@@ -83,10 +83,10 @@
   // CHECK-F-NEXT: 1 | void A::g()
   // CHECK-F-NEXT: 2 | void A::h()
   // CHECK-F-NEXT: 3 | void F::i()
-  // CHECK-F-NEXT: 4 | F::~F()
+  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
   // CHECK-F: VTable indices for 'F' (2 entries).
   // CHECK-F-NEXT: 3 | void F::i()
-  // CHECK-F-NEXT: 4 | F::~F()
+  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
   // EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*]
   virtual void i();
   virtual ~F();
@@ -98,12 +98,12 @@
   // CHECK-G-NEXT: 0 | void G::f()
   // CHECK-G-NEXT: 1 | void A::g()
   // CHECK-G-NEXT: 2 | void A::h()
-  // CHECK-G-NEXT: 3 | G::~G()
+  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
   // CHECK-G-NEXT: 4 | void E::i()
   // CHECK-G-NEXT: 5 | void G::j()
   // CHECK-G: VTable indices for 'G' (3 entries).
   // CHECK-G-NEXT: 0 | void G::f()
-  // CHECK-G-NEXT: 3 | G::~G()
+  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
   // CHECK-G-NEXT: 5 | void G::j()
   // Never used, so doesn't emit a vtable.
   virtual void f();  // overrides A::f()