diff options
Diffstat (limited to 'lib/CodeGen/CGExprCXX.cpp')
| -rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 108 | 
1 files changed, 80 insertions, 28 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index ab170245284c..41bb199ffde7 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -16,6 +16,7 @@  #include "CGCXXABI.h"  #include "CGDebugInfo.h"  #include "CGObjCRuntime.h" +#include "ConstantEmitter.h"  #include "clang/CodeGen/CGFunctionInfo.h"  #include "clang/Frontend/CodeGenOptions.h"  #include "llvm/IR/CallSite.h" @@ -367,9 +368,11 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(    } else {      if (SanOpts.has(SanitizerKind::CFINVCall) &&          MD->getParent()->isDynamicClass()) { -      llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy, MD->getParent()); -      EmitVTablePtrCheckForCall(MD->getParent(), VTable, CFITCK_NVCall, -                                CE->getLocStart()); +      llvm::Value *VTable; +      const CXXRecordDecl *RD; +      std::tie(VTable, RD) = +          CGM.getCXXABI().LoadVTablePtr(*this, This, MD->getParent()); +      EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getLocStart());      }      if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier) @@ -681,8 +684,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,    // Emit the array size expression.    // We multiply the size of all dimensions for NumElements.    // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6. -  numElements = CGF.CGM.EmitConstantExpr(e->getArraySize(), -                                         CGF.getContext().getSizeType(), &CGF); +  numElements = +    ConstantEmitter(CGF).tryEmitAbstract(e->getArraySize(), e->getType());    if (!numElements)      numElements = CGF.EmitScalarExpr(e->getArraySize());    assert(isa<llvm::IntegerType>(numElements->getType())); @@ -1310,29 +1313,44 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,    llvm_unreachable("predeclared global operator new/delete is missing");  } -static std::pair<bool, bool> -shouldPassSizeAndAlignToUsualDelete(const FunctionProtoType *FPT) { +namespace { +/// The parameters to pass to a usual operator delete. +struct UsualDeleteParams { +  bool DestroyingDelete = false; +  bool Size = false; +  bool Alignment = false; +}; +} + +static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) { +  UsualDeleteParams Params; + +  const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();    auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();    // The first argument is always a void*.    ++AI; -  // Figure out what other parameters we should be implicitly passing. -  bool PassSize = false; -  bool PassAlignment = false; +  // The next parameter may be a std::destroying_delete_t. +  if (FD->isDestroyingOperatorDelete()) { +    Params.DestroyingDelete = true; +    assert(AI != AE); +    ++AI; +  } +  // Figure out what other parameters we should be implicitly passing.    if (AI != AE && (*AI)->isIntegerType()) { -    PassSize = true; +    Params.Size = true;      ++AI;    }    if (AI != AE && (*AI)->isAlignValT()) { -    PassAlignment = true; +    Params.Alignment = true;      ++AI;    }    assert(AI == AE && "unexpected usual deallocation function parameter"); -  return {PassSize, PassAlignment}; +  return Params;  }  namespace { @@ -1385,25 +1403,27 @@ namespace {            OperatorDelete->getType()->getAs<FunctionProtoType>();        CallArgList DeleteArgs; -      // The first argument is always a void*. +      // The first argument is always a void* (or C* for a destroying operator +      // delete for class type C).        DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(0));        // Figure out what other parameters we should be implicitly passing. -      bool PassSize = false; -      bool PassAlignment = false; +      UsualDeleteParams Params;        if (NumPlacementArgs) {          // A placement deallocation function is implicitly passed an alignment          // if the placement allocation function was, but is never passed a size. -        PassAlignment = PassAlignmentToPlacementDelete; +        Params.Alignment = PassAlignmentToPlacementDelete;        } else {          // For a non-placement new-expression, 'operator delete' can take a          // size and/or an alignment if it has the right parameters. -        std::tie(PassSize, PassAlignment) = -            shouldPassSizeAndAlignToUsualDelete(FPT); +        Params = getUsualDeleteParams(OperatorDelete);        } +      assert(!Params.DestroyingDelete && +             "should not call destroying delete in a new-expression"); +        // The second argument can be a std::size_t (for non-placement delete). -      if (PassSize) +      if (Params.Size)          DeleteArgs.add(Traits::get(CGF, AllocSize),                         CGF.getContext().getSizeType()); @@ -1411,7 +1431,7 @@ namespace {        // is an enum whose underlying type is std::size_t.        // FIXME: Use the right type as the parameter type. Note that in a call        // to operator delete(size_t, ...), we may not have it available. -      if (PassAlignment) +      if (Params.Alignment)          DeleteArgs.add(RValue::get(llvm::ConstantInt::get(                             CGF.SizeTy, AllocAlign.getQuantity())),                         CGF.getContext().getSizeType()); @@ -1714,9 +1734,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,    CallArgList DeleteArgs; -  std::pair<bool, bool> PassSizeAndAlign = -      shouldPassSizeAndAlignToUsualDelete(DeleteFTy); - +  auto Params = getUsualDeleteParams(DeleteFD);    auto ParamTypeIt = DeleteFTy->param_type_begin();    // Pass the pointer itself. @@ -1724,8 +1742,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,    llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));    DeleteArgs.add(RValue::get(DeletePtr), ArgTy); +  // Pass the std::destroying_delete tag if present. +  if (Params.DestroyingDelete) { +    QualType DDTag = *ParamTypeIt++; +    // Just pass an 'undef'. We expect the tag type to be an empty struct. +    auto *V = llvm::UndefValue::get(getTypes().ConvertType(DDTag)); +    DeleteArgs.add(RValue::get(V), DDTag); +  } +    // Pass the size if the delete function has a size_t parameter. -  if (PassSizeAndAlign.first) { +  if (Params.Size) {      QualType SizeType = *ParamTypeIt++;      CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);      llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType), @@ -1744,7 +1770,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,    }    // Pass the alignment if the delete function has an align_val_t parameter. -  if (PassSizeAndAlign.second) { +  if (Params.Alignment) {      QualType AlignValType = *ParamTypeIt++;      CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits(          getContext().getTypeAlignIfKnown(DeleteTy)); @@ -1786,6 +1812,21 @@ CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,                                          OperatorDelete, ElementType);  } +/// Emit the code for deleting a single object with a destroying operator +/// delete. If the element type has a non-virtual destructor, Ptr has already +/// been converted to the type of the parameter of 'operator delete'. Otherwise +/// Ptr points to an object of the static type. +static void EmitDestroyingObjectDelete(CodeGenFunction &CGF, +                                       const CXXDeleteExpr *DE, Address Ptr, +                                       QualType ElementType) { +  auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor(); +  if (Dtor && Dtor->isVirtual()) +    CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, +                                                Dtor); +  else +    CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType); +} +  /// Emit the code for deleting a single object.  static void EmitObjectDelete(CodeGenFunction &CGF,                               const CXXDeleteExpr *DE, @@ -1800,6 +1841,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,                      DE->getExprLoc(), Ptr.getPointer(),                      ElementType); +  const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); +  assert(!OperatorDelete->isDestroyingOperatorDelete()); +    // Find the destructor for the type, if applicable.  If the    // destructor is virtual, we'll just emit the vcall and return.    const CXXDestructorDecl *Dtor = nullptr; @@ -1819,7 +1863,6 @@ static void EmitObjectDelete(CodeGenFunction &CGF,    // Make sure that we call delete even if the dtor throws.    // This doesn't have to a conditional cleanup because we're going    // to pop it off in a second. -  const FunctionDecl *OperatorDelete = DE->getOperatorDelete();    CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,                                              Ptr.getPointer(),                                              OperatorDelete, ElementType); @@ -1931,10 +1974,19 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {    Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);    EmitBlock(DeleteNotNull); +  QualType DeleteTy = E->getDestroyedType(); + +  // A destroying operator delete overrides the entire operation of the +  // delete expression. +  if (E->getOperatorDelete()->isDestroyingOperatorDelete()) { +    EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy); +    EmitBlock(DeleteEnd); +    return; +  } +    // We might be deleting a pointer to array.  If so, GEP down to the    // first non-array element.    // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*) -  QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();    if (DeleteTy->isConstantArrayType()) {      llvm::Value *Zero = Builder.getInt32(0);      SmallVector<llvm::Value*,8> GEP;  | 
