r220993 - MS ABI: Properly call global delete when invoking virtual destructors

David Majnemer david.majnemer at gmail.com
Fri Oct 31 13:09:13 PDT 2014


Author: majnemer
Date: Fri Oct 31 15:09:12 2014
New Revision: 220993

URL: http://llvm.org/viewvc/llvm-project?rev=220993&view=rev
Log:
MS ABI: Properly call global delete when invoking virtual destructors

Summary:
The Itanium ABI approach of using offset-to-top isn't possible with the
MS ABI, it doesn't have that kind of information lying around.

Instead, we do the following:
- Call the virtual deleting destructor with the "don't delete the object
  flag" set.  The virtual deleting destructor will return a pointer to
  'this' adjusted to the most derived class.
- Call the global delete using the adjusted 'this' pointer.

Reviewers: rnk

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D5996

Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/dllexport.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Fri Oct 31 15:09:12 2014
@@ -93,6 +93,8 @@ public:
   /// when called virtually, and code generation does not support the case.
   virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
 
+  virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
+
   /// If the C++ ABI requires the given type be returned in a particular way,
   /// this method sets RetAI and returns true.
   virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0;
@@ -207,14 +209,11 @@ protected:
   CharUnits getMemberPointerPathAdjustment(const APValue &MP);
 
 public:
-  /// Adjust the given non-null pointer to an object of polymorphic
-  /// type to point to the complete object.
-  ///
-  /// The IR type of the result should be a pointer but is otherwise
-  /// irrelevant.
-  virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
-                                              llvm::Value *ptr,
-                                              QualType type) = 0;
+  virtual void emitVirtualObjectDelete(CodeGenFunction &CGF,
+                                       const FunctionDecl *OperatorDelete,
+                                       llvm::Value *Ptr, QualType ElementType,
+                                       bool UseGlobalDelete,
+                                       const CXXDestructorDecl *Dtor) = 0;
 
   virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
 
@@ -359,11 +358,10 @@ public:
                                                  llvm::Type *Ty) = 0;
 
   /// Emit the ABI-specific virtual destructor call.
-  virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
-                                         const CXXDestructorDecl *Dtor,
-                                         CXXDtorType DtorType,
-                                         llvm::Value *This,
-                                         const CXXMemberCallExpr *CE) = 0;
+  virtual llvm::Value *
+  EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
+                            CXXDtorType DtorType, llvm::Value *This,
+                            const CXXMemberCallExpr *CE) = 0;
 
   virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
                                                 GlobalDecl GD,

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri Oct 31 15:09:12 2014
@@ -214,8 +214,11 @@ CodeGenTypes::arrangeCXXStructorDeclarat
       (MD->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
 
   FunctionType::ExtInfo extInfo = FTP->getExtInfo();
-  CanQualType resultType =
-      TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
+  CanQualType resultType = TheCXXABI.HasThisReturn(GD)
+                               ? argTypes.front()
+                               : TheCXXABI.hasMostDerivedReturn(GD)
+                                     ? CGM.getContext().VoidPtrTy
+                                     : Context.VoidTy;
   return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required);
 }
 
@@ -233,8 +236,11 @@ CodeGenTypes::arrangeCXXConstructorCall(
   CanQual<FunctionProtoType> FPT = GetFormalType(D);
   RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs);
   GlobalDecl GD(D, CtorKind);
-  CanQualType ResultType =
-      TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() : Context.VoidTy;
+  CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
+                               ? ArgTypes.front()
+                               : TheCXXABI.hasMostDerivedReturn(GD)
+                                     ? CGM.getContext().VoidPtrTy
+                                     : Context.VoidTy;
 
   FunctionType::ExtInfo Info = FPT->getExtInfo();
   return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required);

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Oct 31 15:09:12 2014
@@ -24,10 +24,10 @@
 using namespace clang;
 using namespace CodeGen;
 
-RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
-    const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
-    llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
-    const CallExpr *CE) {
+static RequiredArgs commonEmitCXXMemberOrOperatorCall(
+    CodeGenFunction &CGF, const CXXMethodDecl *MD, llvm::Value *Callee,
+    ReturnValueSlot ReturnValue, llvm::Value *This, llvm::Value *ImplicitParam,
+    QualType ImplicitParamTy, const CallExpr *CE, CallArgList &Args) {
   assert(CE == nullptr || isa<CXXMemberCallExpr>(CE) ||
          isa<CXXOperatorCallExpr>(CE));
   assert(MD->isInstance() &&
@@ -39,14 +39,13 @@ RValue CodeGenFunction::EmitCXXMemberOrO
   SourceLocation CallLoc;
   if (CE)
     CallLoc = CE->getExprLoc();
-  EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
-                                            : TCK_MemberCall,
-                CallLoc, This, getContext().getRecordType(MD->getParent()));
-
-  CallArgList Args;
+  CGF.EmitTypeCheck(
+      isa<CXXConstructorDecl>(MD) ? CodeGenFunction::TCK_ConstructorCall
+                                  : CodeGenFunction::TCK_MemberCall,
+      CallLoc, This, CGF.getContext().getRecordType(MD->getParent()));
 
   // Push the this ptr.
-  Args.add(RValue::get(This), MD->getThisType(getContext()));
+  Args.add(RValue::get(This), MD->getThisType(CGF.getContext()));
 
   // If there is an implicit parameter (e.g. VTT), emit it.
   if (ImplicitParam) {
@@ -60,18 +59,40 @@ RValue CodeGenFunction::EmitCXXMemberOrO
   if (CE) {
     // Special case: skip first argument of CXXOperatorCall (it is "this").
     unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
-    EmitCallArgs(Args, FPT, CE->arg_begin() + ArgsToSkip, CE->arg_end(),
-                 CE->getDirectCallee());
+    CGF.EmitCallArgs(Args, FPT, CE->arg_begin() + ArgsToSkip, CE->arg_end(),
+                     CE->getDirectCallee());
   } else {
     assert(
         FPT->getNumParams() == 0 &&
         "No CallExpr specified for function with non-zero number of arguments");
   }
+  return required;
+}
 
+RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
+    const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
+    llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
+    const CallExpr *CE) {
+  const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+  CallArgList Args;
+  RequiredArgs required = commonEmitCXXMemberOrOperatorCall(
+      *this, MD, Callee, ReturnValue, This, ImplicitParam, ImplicitParamTy, CE,
+      Args);
   return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
                   Callee, ReturnValue, Args, MD);
 }
 
+RValue CodeGenFunction::EmitCXXStructorCall(
+    const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue,
+    llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy,
+    const CallExpr *CE, StructorType Type) {
+  CallArgList Args;
+  commonEmitCXXMemberOrOperatorCall(*this, MD, Callee, ReturnValue, This,
+                                    ImplicitParam, ImplicitParamTy, CE, Args);
+  return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(MD, Type),
+                  Callee, ReturnValue, Args, MD);
+}
+
 static CXXRecordDecl *getCXXRecord(const Expr *E) {
   QualType T = E->getType();
   if (const PointerType *PTy = T->getAs<PointerType>())
@@ -1389,6 +1410,14 @@ namespace {
   };
 }
 
+void
+CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
+                                             llvm::Value *CompletePtr,
+                                             QualType ElementType) {
+  EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, CompletePtr,
+                                        OperatorDelete, ElementType);
+}
+
 /// Emit the code for deleting a single object.
 static void EmitObjectDelete(CodeGenFunction &CGF,
                              const FunctionDecl *OperatorDelete,
@@ -1404,30 +1433,8 @@ static void EmitObjectDelete(CodeGenFunc
       Dtor = RD->getDestructor();
 
       if (Dtor->isVirtual()) {
-        if (UseGlobalDelete) {
-          // If we're supposed to call the global delete, make sure we do so
-          // even if the destructor throws.
-
-          // Derive the complete-object pointer, which is what we need
-          // to pass to the deallocation function.
-          llvm::Value *completePtr =
-            CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType);
-
-          CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
-                                                    completePtr, OperatorDelete,
-                                                    ElementType);
-        }
-
-        // FIXME: Provide a source location here even though there's no
-        // CXXMemberCallExpr for dtor call.
-        CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
-        CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr,
-                                                      nullptr);
-
-        if (UseGlobalDelete) {
-          CGF.PopCleanupBlock();
-        }
-
+        CGF.CGM.getCXXABI().emitVirtualObjectDelete(
+            CGF, OperatorDelete, Ptr, ElementType, UseGlobalDelete, Dtor);
         return;
       }
     }

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Oct 31 15:09:12 2014
@@ -200,8 +200,11 @@ void CodeGenFunction::StartThunk(llvm::F
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
   QualType ThisType = MD->getThisType(getContext());
   const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-  QualType ResultType =
-      CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getReturnType();
+  QualType ResultType = CGM.getCXXABI().HasThisReturn(GD)
+                            ? ThisType
+                            : CGM.getCXXABI().hasMostDerivedReturn(GD)
+                                  ? CGM.getContext().VoidPtrTy
+                                  : FPT->getReturnType();
   FunctionArgList FunctionArgs;
 
   // Create the implicit 'this' parameter declaration.
@@ -278,8 +281,11 @@ void CodeGenFunction::EmitCallAndReturnF
 #endif
 
   // Determine whether we have a return value slot to use.
-  QualType ResultType =
-      CGM.getCXXABI().HasThisReturn(CurGD) ? ThisType : FPT->getReturnType();
+  QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD)
+                            ? ThisType
+                            : CGM.getCXXABI().hasMostDerivedReturn(CurGD)
+                                  ? CGM.getContext().VoidPtrTy
+                                  : FPT->getReturnType();
   ReturnValueSlot Slot;
   if (!ResultType->isVoidType() &&
       CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Oct 31 15:09:12 2014
@@ -822,6 +822,8 @@ void CodeGenFunction::GenerateCode(Globa
   if (MD && MD->isInstance()) {
     if (CGM.getCXXABI().HasThisReturn(GD))
       ResTy = MD->getThisType(getContext());
+    else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
+      ResTy = CGM.getContext().VoidPtrTy;
     CGM.getCXXABI().buildThisParam(*this, Args);
   }
   

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Oct 31 15:09:12 2014
@@ -1136,6 +1136,9 @@ public:
   void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
                                    QualType type, Destroyer *destroyer,
                                    bool useEHCleanupForArray);
+  void pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
+                                   llvm::Value *CompletePtr,
+                                   QualType ElementType);
   void pushStackRestore(CleanupKind kind, llvm::Value *SPMem);
   void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
                    bool useEHCleanupForArray);
@@ -2319,6 +2322,11 @@ public:
                               ReturnValueSlot ReturnValue, llvm::Value *This,
                               llvm::Value *ImplicitParam,
                               QualType ImplicitParamTy, const CallExpr *E);
+  RValue EmitCXXStructorCall(const CXXMethodDecl *MD, llvm::Value *Callee,
+                             ReturnValueSlot ReturnValue, llvm::Value *This,
+                             llvm::Value *ImplicitParam,
+                             QualType ImplicitParamTy, const CallExpr *E,
+                             StructorType Type);
   RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
                                ReturnValueSlot ReturnValue);
   RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Oct 31 15:09:12 2014
@@ -106,8 +106,11 @@ public:
                                          llvm::Value *Addr,
                                          const MemberPointerType *MPT) override;
 
-  llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
-                                      QualType type) override;
+  void emitVirtualObjectDelete(CodeGenFunction &CGF,
+                               const FunctionDecl *OperatorDelete,
+                               llvm::Value *Ptr, QualType ElementType,
+                               bool UseGlobalDelete,
+                               const CXXDestructorDecl *Dtor) override;
 
   void EmitFundamentalRTTIDescriptor(QualType Type);
   void EmitFundamentalRTTIDescriptors();
@@ -187,10 +190,11 @@ public:
                                          llvm::Value *This,
                                          llvm::Type *Ty) override;
 
-  void EmitVirtualDestructorCall(CodeGenFunction &CGF,
-                                 const CXXDestructorDecl *Dtor,
-                                 CXXDtorType DtorType, llvm::Value *This,
-                                 const CXXMemberCallExpr *CE) override;
+  llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
+                                         const CXXDestructorDecl *Dtor,
+                                         CXXDtorType DtorType,
+                                         llvm::Value *This,
+                                         const CXXMemberCallExpr *CE) override;
 
   void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
 
@@ -847,21 +851,38 @@ bool ItaniumCXXABI::isZeroInitializable(
 
 /// The Itanium ABI always places an offset to the complete object
 /// at entry -2 in the vtable.
-llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
-                                                   llvm::Value *ptr,
-                                                   QualType type) {
-  // Grab the vtable pointer as an intptr_t*.
-  llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
-
-  // Track back to entry -2 and pull out the offset there.
-  llvm::Value *offsetPtr = 
-    CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
-  llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
-  offset->setAlignment(CGF.PointerAlignInBytes);
+void ItaniumCXXABI::emitVirtualObjectDelete(
+    CodeGenFunction &CGF, const FunctionDecl *OperatorDelete, llvm::Value *Ptr,
+    QualType ElementType, bool UseGlobalDelete, const CXXDestructorDecl *Dtor) {
+  if (UseGlobalDelete) {
+    // Derive the complete-object pointer, which is what we need
+    // to pass to the deallocation function.
+
+    // Grab the vtable pointer as an intptr_t*.
+    llvm::Value *VTable = CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo());
+
+    // Track back to entry -2 and pull out the offset there.
+    llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
+        VTable, -2, "complete-offset.ptr");
+    llvm::LoadInst *Offset = CGF.Builder.CreateLoad(OffsetPtr);
+    Offset->setAlignment(CGF.PointerAlignInBytes);
+
+    // Apply the offset.
+    llvm::Value *CompletePtr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy);
+    CompletePtr = CGF.Builder.CreateInBoundsGEP(CompletePtr, Offset);
+
+    // If we're supposed to call the global delete, make sure we do so
+    // even if the destructor throws.
+    CGF.pushCallObjectDeleteCleanup(OperatorDelete, CompletePtr, ElementType);
+  }
+
+  // FIXME: Provide a source location here even though there's no
+  // CXXMemberCallExpr for dtor call.
+  CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+  EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
 
-  // Apply the offset.
-  ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
-  return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+  if (UseGlobalDelete)
+    CGF.PopCleanupBlock();
 }
 
 static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
@@ -1333,11 +1354,9 @@ llvm::Value *ItaniumCXXABI::getVirtualFu
   return CGF.Builder.CreateLoad(VFuncPtr);
 }
 
-void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
-                                              const CXXDestructorDecl *Dtor,
-                                              CXXDtorType DtorType,
-                                              llvm::Value *This,
-                                              const CXXMemberCallExpr *CE) {
+llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
+    CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
+    llvm::Value *This, const CXXMemberCallExpr *CE) {
   assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
   assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
 
@@ -1349,6 +1368,7 @@ void ItaniumCXXABI::EmitVirtualDestructo
 
   CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This,
                                   /*ImplicitParam=*/nullptr, QualType(), CE);
+  return nullptr;
 }
 
 void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Oct 31 15:09:12 2014
@@ -43,6 +43,7 @@ public:
         CompleteObjectLocatorType(nullptr) {}
 
   bool HasThisReturn(GlobalDecl GD) const override;
+  bool hasMostDerivedReturn(GlobalDecl GD) const override;
 
   bool classifyReturnType(CGFunctionInfo &FI) const override;
 
@@ -65,9 +66,11 @@ public:
   StringRef GetPureVirtualCallName() override { return "_purecall"; }
   StringRef GetDeletedVirtualCallName() override { return "_purecall"; }
 
-  llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
-                                      llvm::Value *ptr,
-                                      QualType type) override;
+  void emitVirtualObjectDelete(CodeGenFunction &CGF,
+                               const FunctionDecl *OperatorDelete,
+                               llvm::Value *Ptr, QualType ElementType,
+                               bool UseGlobalDelete,
+                               const CXXDestructorDecl *Dtor) override;
 
   llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
                                                    const VPtrInfo *Info);
@@ -211,10 +214,11 @@ public:
                                          llvm::Value *This,
                                          llvm::Type *Ty) override;
 
-  void EmitVirtualDestructorCall(CodeGenFunction &CGF,
-                                 const CXXDestructorDecl *Dtor,
-                                 CXXDtorType DtorType, llvm::Value *This,
-                                 const CXXMemberCallExpr *CE) override;
+  llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
+                                         const CXXDestructorDecl *Dtor,
+                                         CXXDtorType DtorType,
+                                         llvm::Value *This,
+                                         const CXXMemberCallExpr *CE) override;
 
   void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
                                         CallArgList &CallArgs) override {
@@ -641,11 +645,16 @@ MicrosoftCXXABI::getRecordArgABI(const C
   llvm_unreachable("invalid enum");
 }
 
-llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
-                                                     llvm::Value *ptr,
-                                                     QualType type) {
-  // FIXME: implement
-  return ptr;
+void MicrosoftCXXABI::emitVirtualObjectDelete(
+    CodeGenFunction &CGF, const FunctionDecl *OperatorDelete, llvm::Value *Ptr,
+    QualType ElementType, bool UseGlobalDelete, const CXXDestructorDecl *Dtor) {
+  // FIXME: Provide a source location here even though there's no
+  // CXXMemberCallExpr for dtor call.
+  CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+  llvm::Value *MDThis =
+      EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, /*CE=*/nullptr);
+  if (UseGlobalDelete)
+    CGF.EmitDeleteCall(OperatorDelete, MDThis, ElementType);
 }
 
 /// \brief Gets the offset to the virtual base that contains the vfptr for
@@ -795,6 +804,15 @@ bool MicrosoftCXXABI::HasThisReturn(Glob
   return isa<CXXConstructorDecl>(GD.getDecl());
 }
 
+static bool isDeletingDtor(GlobalDecl GD) {
+  return isa<CXXDestructorDecl>(GD.getDecl()) &&
+         GD.getDtorType() == Dtor_Deleting;
+}
+
+bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const {
+  return isDeletingDtor(GD);
+}
+
 bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
   const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
   if (!RD)
@@ -1059,14 +1077,6 @@ llvm::Value *MicrosoftCXXABI::adjustThis
   return This;
 }
 
-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::addImplicitStructorParams(CodeGenFunction &CGF,
                                                 QualType &ResTy,
                                                 FunctionArgList &Params) {
@@ -1087,7 +1097,7 @@ void MicrosoftCXXABI::addImplicitStructo
     else
       Params.push_back(IsMostDerived);
     getStructorImplicitParamDecl(CGF) = IsMostDerived;
-  } else if (IsDeletingDtor(CGF.CurGD)) {
+  } else if (isDeletingDtor(CGF.CurGD)) {
     ImplicitParamDecl *ShouldDelete
       = ImplicitParamDecl::Create(Context, nullptr,
                                   CGF.CurGD.getDecl()->getLocation(),
@@ -1133,6 +1143,9 @@ void MicrosoftCXXABI::EmitInstanceFuncti
   ///    HasThisReturn only specifies a contract, not the implementation    
   if (HasThisReturn(CGF.CurGD))
     CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
+  else if (hasMostDerivedReturn(CGF.CurGD))
+    CGF.Builder.CreateStore(CGF.EmitCastToVoidPtr(getThisValue(CGF)),
+                            CGF.ReturnValue);
 
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
   if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
@@ -1144,7 +1157,7 @@ void MicrosoftCXXABI::EmitInstanceFuncti
           "is_most_derived");
   }
 
-  if (IsDeletingDtor(CGF.CurGD)) {
+  if (isDeletingDtor(CGF.CurGD)) {
     assert(getStructorImplicitParamDecl(CGF) &&
            "no implicit parameter for a deleting destructor?");
     getStructorImplicitParamValue(CGF)
@@ -1192,9 +1205,10 @@ void MicrosoftCXXABI::EmitDestructorCall
                                                     This, false);
   }
 
-  CGF.EmitCXXMemberOrOperatorCall(DD, Callee, ReturnValueSlot(), This,
-                                  /*ImplicitParam=*/nullptr,
-                                  /*ImplicitParamTy=*/QualType(), nullptr);
+  CGF.EmitCXXStructorCall(DD, Callee, ReturnValueSlot(), This,
+                          /*ImplicitParam=*/nullptr,
+                          /*ImplicitParamTy=*/QualType(), nullptr,
+                          getFromDtorType(Type));
 }
 
 void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -1402,11 +1416,9 @@ llvm::Value *MicrosoftCXXABI::getVirtual
   return Builder.CreateLoad(VFuncPtr);
 }
 
-void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
-                                                const CXXDestructorDecl *Dtor,
-                                                CXXDtorType DtorType,
-                                                llvm::Value *This,
-                                                const CXXMemberCallExpr *CE) {
+llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
+    CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType,
+    llvm::Value *This, const CXXMemberCallExpr *CE) {
   assert(CE == nullptr || CE->arg_begin() == CE->arg_end());
   assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
 
@@ -1424,8 +1436,10 @@ void MicrosoftCXXABI::EmitVirtualDestruc
                              DtorType == Dtor_Deleting);
 
   This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
-  CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This,
-                                  ImplicitParam, Context.IntTy, CE);
+  RValue RV = CGF.EmitCXXStructorCall(Dtor, Callee, ReturnValueSlot(), This,
+                                      ImplicitParam, Context.IntTy, CE,
+                                      StructorType::Deleting);
+  return RV.getScalarVal();
 }
 
 const VBTableGlobals &

Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Fri Oct 31 15:09:12 2014
@@ -534,7 +534,7 @@ struct __declspec(dllexport) Y {
 
 struct __declspec(dllexport) Z { virtual ~Z() {} };
 // The scalar deleting dtor does not get exported:
-// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_GZ@@UAEPAXI at Z"
+// M32-DAG: define linkonce_odr x86_thiscallcc i8* @"\01??_GZ@@UAEPAXI at Z"
 
 
 // The user-defined dtor does get exported:

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp Fri Oct 31 15:09:12 2014
@@ -46,8 +46,9 @@ B::B() {
 
 struct C {
   virtual ~C() {
-// DTORS:      define linkonce_odr x86_thiscallcc void @"\01??_GC at basic@@UAEPAXI at Z"(%"struct.basic::C"* %this, i32 %should_call_delete)
+// DTORS:      define linkonce_odr x86_thiscallcc i8* @"\01??_GC at basic@@UAEPAXI at Z"(%"struct.basic::C"* %this, i32 %should_call_delete)
 // DTORS:        store i32 %should_call_delete, i32* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4
+// DTORS:        store i8* %{{.*}}, i8** %[[RETVAL:[0-9a-z._]+]]
 // DTORS:        %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32* %[[SHOULD_DELETE_VAR]]
 // DTORS:        call x86_thiscallcc void @"\01??1C at basic@@UAE at XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]])
 // DTORS-NEXT:   %[[CONDITION:[0-9]+]] = icmp eq i32 %[[SHOULD_DELETE_VALUE]], 0
@@ -59,7 +60,8 @@ struct C {
 // DTORS-NEXT:   br label %[[CONTINUE_LABEL]]
 //
 // DTORS:      [[CONTINUE_LABEL]]
-// DTORS-NEXT:   ret void
+// DTORS-NEXT:   %[[RET:.*]] = load i8** %[[RETVAL]]
+// DTORS-NEXT:   ret i8* %[[RET]]
 
 // Check that we do the mangling correctly on x64.
 // DTORS-X64:  @"\01??_GC at basic@@UEAAPEAXI at Z"
@@ -81,11 +83,11 @@ void call_complete_dtor(C *obj_ptr) {
 // CHECK: define void @"\01?call_complete_dtor at basic@@YAXPAUC at 1@@Z"(%"struct.basic::C"* %obj_ptr)
   obj_ptr->~C();
 // CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
 // CHECK-NEXT: ret void
 }
 
@@ -96,11 +98,27 @@ void call_deleting_dtor(C *obj_ptr) {
 // CHECK:      br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
 
 // CHECK:      [[DELETE_NOTNULL]]
-// CHECK-NEXT:   %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i32)***
-// CHECK-NEXT:   %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
-// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
-// CHECK-NEXT:   %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i32)** %[[PVDTOR]]
-// CHECK-NEXT:   call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1)
+// CHECK-NEXT:   %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT:   %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT:   %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT:   call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 1)
+// CHECK:      ret void
+}
+
+void call_deleting_dtor_and_global_delete(C *obj_ptr) {
+// CHECK: define void @"\01?call_deleting_dtor_and_global_delete at basic@@YAXPAUC at 1@@Z"(%"struct.basic::C"* %obj_ptr)
+  ::delete obj_ptr;
+// CHECK:      %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK:      br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
+
+// CHECK:      [[DELETE_NOTNULL]]
+// CHECK-NEXT:   %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to i8* (%"struct.basic::C"*, i32)***
+// CHECK-NEXT:   %[[VTABLE:.*]] = load i8* (%"struct.basic::C"*, i32)*** %[[PVTABLE]]
+// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds i8* (%"struct.basic::C"*, i32)** %[[VTABLE]], i64 0
+// CHECK-NEXT:   %[[VDTOR:.*]] = load i8* (%"struct.basic::C"*, i32)** %[[PVDTOR]]
+// CHECK-NEXT:   %[[CALL:.*]] = call x86_thiscallcc i8* %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i32 0)
+// CHECK-NEXT:   call void @"\01??3 at YAXPAX@Z"(i8* %[[CALL]])
 // CHECK:      ret void
 }
 
@@ -153,13 +171,13 @@ C::~C() {
 void foo() {
   C c;
 }
-// DTORS2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC at dtor_in_second_nvbase@@W3AEPAXI at Z"
+// DTORS2-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_EC at dtor_in_second_nvbase@@W3AEPAXI at Z"
 // DTORS2:       (%"struct.dtor_in_second_nvbase::C"* %this, i32 %should_call_delete)
 //      Do an adjustment from B* to C*.
 // DTORS2:   getelementptr i8* %{{.*}}, i32 -4
 // DTORS2:   bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::C"*
-// DTORS2:   call x86_thiscallcc void @"\01??_GC at dtor_in_second_nvbase@@UAEPAXI at Z"
-// DTORS2:   ret void
+// DTORS2:   %[[CALL:.*]] = call x86_thiscallcc i8* @"\01??_GC at dtor_in_second_nvbase@@UAEPAXI at Z"
+// DTORS2:   ret i8* %[[CALL]]
 
 }
 
@@ -436,7 +454,7 @@ struct A {
 void *getA() {
   return (void*)new A();
 }
-// CHECK: define internal x86_thiscallcc void @"\01??_GA@?A@@UAEPAXI at Z"
+// CHECK: define internal x86_thiscallcc i8* @"\01??_GA@?A@@UAEPAXI at Z"
 // CHECK:               (%"struct.(anonymous namespace)::A"* %this, i32 %should_call_delete)
 // CHECK: define internal x86_thiscallcc void @"\01??1A@?A@@UAE at XZ"
 // CHECK:               (%"struct.(anonymous namespace)::A"* %this)

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-thunks.cpp Fri Oct 31 15:09:12 2014
@@ -61,10 +61,10 @@ struct C : A, B {
 
 C::C() {}  // Emits vftable and forces thunk generation.
 
-// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC@@W3AEPAXI at Z"(%struct.C* %this, i32 %should_call_delete)
+// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_EC@@W3AEPAXI at Z"(%struct.C* %this, i32 %should_call_delete)
 // CODEGEN:   getelementptr i8* {{.*}}, i32 -4
 // FIXME: should actually call _EC, not _GC.
-// CODEGEN:   call x86_thiscallcc void @"\01??_GC@@UAEPAXI at Z"
+// CODEGEN:   call x86_thiscallcc i8* @"\01??_GC@@UAEPAXI at Z"
 // CODEGEN: ret
 
 // CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01?public_f at C@@W3AEXXZ"(%struct.C*

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp?rev=220993&r1=220992&r2=220993&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp Fri Oct 31 15:09:12 2014
@@ -96,7 +96,7 @@ B::~B() {
   // CHECK2: call x86_thiscallcc void @"\01??1VBase@@UAE at XZ"(%struct.VBase* %[[VBASE]])
   // CHECK2: ret
 
-  // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI at Z"
+  // CHECK2-LABEL: define linkonce_odr x86_thiscallcc i8* @"\01??_GB@@UAEPAXI at Z"
   // CHECK2:   %[[THIS_PARAM_i8:.*]] = bitcast %struct.B* {{.*}} to i8*
   // CHECK2:   %[[THIS_i8:.*]] = getelementptr inbounds i8* %[[THIS_PARAM_i8:.*]], i32 -8
   // CHECK2:   %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
@@ -184,10 +184,10 @@ void delete_B(B *obj) {
 // CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
 // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
-// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (%struct.B*, i32)***
-// CHECK: %[[VFTABLE:.*]] = load void (%struct.B*, i32)*** %[[VFPTR]]
-// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.B*, i32)** %[[VFTABLE]], i64 0
-// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.B*, i32)** %[[VFUN]]
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to i8* (%struct.B*, i32)***
+// CHECK: %[[VFTABLE:.*]] = load i8* (%struct.B*, i32)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds i8* (%struct.B*, i32)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load i8* (%struct.B*, i32)** %[[VFUN]]
 //
 // CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
 // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
@@ -199,7 +199,7 @@ void delete_B(B *obj) {
 // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
 // CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B*
 //
-// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1)
+// CHECK: call x86_thiscallcc i8* %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1)
 // CHECK: ret void
 }
 
@@ -407,11 +407,11 @@ void destroy(C *obj) {
   // CHECK-LABEL: define void @"\01?destroy at test4@@YAXPAUC at 1@@Z"(%"struct.test4::C"* %obj)
 
   delete obj;
-  // CHECK: %[[VPTR:.*]] = bitcast %"struct.test4::C"* %[[OBJ:.*]] to void (%"struct.test4::C"*, i32)***
-  // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::C"*, i32)*** %[[VPTR]]
-  // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::C"*, i32)** %[[VFTABLE]], i64 0
-  // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::C"*, i32)** %[[VFTENTRY]]
-  // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::C"* %[[OBJ]], i32 1)
+  // CHECK: %[[VPTR:.*]] = bitcast %"struct.test4::C"* %[[OBJ:.*]] to i8* (%"struct.test4::C"*, i32)***
+  // CHECK: %[[VFTABLE:.*]] = load i8* (%"struct.test4::C"*, i32)*** %[[VPTR]]
+  // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds i8* (%"struct.test4::C"*, i32)** %[[VFTABLE]], i64 0
+  // CHECK: %[[VFUN:.*]] = load i8* (%"struct.test4::C"*, i32)** %[[VFTENTRY]]
+  // CHECK: call x86_thiscallcc i8* %[[VFUN]](%"struct.test4::C"* %[[OBJ]], i32 1)
   // CHECK: ret
 }
 
@@ -442,15 +442,15 @@ void destroy(E *obj) {
   // CHECK-NOT: getelementptr
   // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ:.*]] to i8*
   // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4
-  // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to void (%"struct.test4::E"*, i32)***
-  // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::E"*, i32)*** %[[VPTR]]
-  // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0
-  // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::E"*, i32)** %[[VFTENTRY]]
+  // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to i8* (%"struct.test4::E"*, i32)***
+  // CHECK: %[[VFTABLE:.*]] = load i8* (%"struct.test4::E"*, i32)*** %[[VPTR]]
+  // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds i8* (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0
+  // CHECK: %[[VFUN:.*]] = load i8* (%"struct.test4::E"*, i32)** %[[VFTENTRY]]
   // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ]] to i8*
   // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4
   // FIXME: in fact, the call should take i8* and the bitcast is redundant.
   // CHECK: %[[B_as_E:.*]] = bitcast i8* %[[B_i8]] to %"struct.test4::E"*
-  // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1)
+  // CHECK: call x86_thiscallcc i8* %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1)
   delete obj;
 }
 





More information about the cfe-commits mailing list