diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-06-21 12:45:15 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-06-21 12:45:15 +0000 |
commit | 23f4c4b64f1a35be406c66ab4e0113a8522b4905 (patch) | |
tree | 32d612ab8a5015a669c0c918d0843099be1cf479 /clang/lib/CodeGen/CGCall.cpp | |
parent | ae4e1ec4e6c616e50794d895555f8ebb49dd05f5 (diff) | |
download | bcm5719-llvm-23f4c4b64f1a35be406c66ab4e0113a8522b4905.tar.gz bcm5719-llvm-23f4c4b64f1a35be406c66ab4e0113a8522b4905.zip |
[ms-cxxabi] Destroy temporary record arguments in the callee
Itanium destroys them in the caller at the end of the full expression,
but MSVC destroys them in the callee. This is further complicated by
the need to emit EH-only destructor cleanups in the caller.
This should help clang compile MSVC's debug iterators more correctly.
There is still an outstanding issue in PR5064 of a memcpy emitted by the
LLVM backend, which is not correct for C++ records.
Fixes PR16226.
Reviewers: rjmccall
Differential Revision: http://llvm-reviews.chandlerc.com/D929
llvm-svn: 184543
Diffstat (limited to 'clang/lib/CodeGen/CGCall.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 80446393d5b..cb5c78a6d59 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1865,6 +1865,19 @@ static void emitWritebacks(CodeGenFunction &CGF, emitWriteback(CGF, *i); } +static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, + const CallArgList &CallArgs) { + assert(CGF.getTarget().getCXXABI().isArgumentDestroyedByCallee()); + ArrayRef<CallArgList::CallArgCleanup> Cleanups = + CallArgs.getCleanupsToDeactivate(); + // Iterate in reverse to increase the likelihood of popping the cleanup. + for (ArrayRef<CallArgList::CallArgCleanup>::reverse_iterator + I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) { + CGF.DeactivateCleanupBlock(I->Cleanup, I->IsActiveIP); + I->IsActiveIP->eraseFromParent(); + } +} + static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) { if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens())) if (uop->getOpcode() == UO_AddrOf) @@ -2016,8 +2029,31 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return args.add(EmitReferenceBindingToExpr(E), type); } - if (hasAggregateEvaluationKind(type) && - isa<ImplicitCastExpr>(E) && + bool HasAggregateEvalKind = hasAggregateEvaluationKind(type); + + // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee. + // However, we still have to push an EH-only cleanup in case we unwind before + // we make it to the call. + if (HasAggregateEvalKind && + CGM.getTarget().getCXXABI().isArgumentDestroyedByCallee()) { + const CXXRecordDecl *RD = type->getAsCXXRecordDecl(); + if (RD && RD->hasNonTrivialDestructor()) { + AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp"); + Slot.setExternallyDestructed(); + EmitAggExpr(E, Slot); + RValue RV = Slot.asRValue(); + args.add(RV, type); + + pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject, + /*useEHCleanupForArray*/ true); + // This unreachable is a temporary marker which will be removed later. + llvm::Instruction *IsActive = Builder.CreateUnreachable(); + args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive); + return; + } + } + + if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) && cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) { LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr()); assert(L.isSimple()); @@ -2428,6 +2464,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } } + if (!CallArgs.getCleanupsToDeactivate().empty()) + deactivateArgCleanupsBeforeCall(*this, CallArgs); + // If the callee is a bitcast of a function to a varargs pointer to function // type, check to see if we can remove the bitcast. This handles some cases // with unprototyped functions. |