llvm::Value *Addr;
CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Should we be passing FIELD_IS_WEAK here?
CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
}
CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual)
: BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const CXXRecordDecl *DerivedClass =
cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();
CallMemberDtor(FieldDecl *Field, CXXDestructorDecl *Dtor)
: Field(Field), Dtor(Dtor) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// FIXME: Is this OK for C++0x delegating constructors?
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
struct CallDtorDelete : EHScopeStack::Cleanup {
CallDtorDelete() {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
const CXXRecordDecl *ClassDecl = Dtor->getParent();
CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
: field(field), destroyer(*destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Find the address of the field.
llvm::Value *thisValue = CGF.LoadCXXThis();
LValue LV = CGF.EmitLValueForField(thisValue, field, /*CVRQualifiers=*/0);
assert(LV.isSimple());
CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
- !isForEH && useEHCleanupForArray);
+ flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
}
CXXDtorType Type)
: Dtor(D), Addr(Addr), Type(Type) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
Addr);
}
CallLocalDtor(const CXXDestructorDecl *D, llvm::Value *Addr)
: Dtor(D), Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Addr);
}
static void EmitCleanup(CodeGenFunction &CGF,
EHScopeStack::Cleanup *Fn,
- bool ForEH,
+ EHScopeStack::Cleanup::Flags flags,
llvm::Value *ActiveFlag) {
// EH cleanups always occur within a terminate scope.
- if (ForEH) CGF.EHStack.pushTerminate();
+ if (flags.isForEHCleanup()) CGF.EHStack.pushTerminate();
// If there's an active flag, load it and skip the cleanup if it's
// false.
}
// Ask the cleanup to emit itself.
- Fn->Emit(CGF, ForEH);
+ Fn->Emit(CGF, flags);
assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?");
// Emit the continuation block if there was an active flag.
CGF.EmitBlock(ContBB);
// Leave the terminate scope.
- if (ForEH) CGF.EHStack.popTerminate();
+ if (flags.isForEHCleanup()) CGF.EHStack.popTerminate();
}
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
RequiresNormalCleanup = true;
}
+ EHScopeStack::Cleanup::Flags cleanupFlags;
+ if (Scope.isNormalCleanup())
+ cleanupFlags.setIsNormalCleanupKind();
+ if (Scope.isEHCleanup())
+ cleanupFlags.setIsEHCleanupKind();
+
// Even if we don't need the normal cleanup, we might still have
// prebranched fallthrough to worry about.
if (Scope.isNormalCleanup() && !RequiresNormalCleanup &&
EHStack.popCleanup();
- EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag);
+ EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
// Otherwise, the best approach is to thread everything through
// the cleanup block and then try to clean up after ourselves.
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);
- EmitCleanup(*this, Fn, /*ForEH*/ false, NormalActiveFlag);
+ EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
// Append the prepared cleanup prologue from above.
llvm::BasicBlock *NormalExit = Builder.GetInsertBlock();
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
EmitBlock(EHEntry);
- EmitCleanup(*this, Fn, /*ForEH*/ true, EHActiveFlag);
+
+ cleanupFlags.setIsForEHCleanup();
+ EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
// Append the prepared cleanup prologue from above.
llvm::BasicBlock *EHExit = Builder.GetInsertBlock();
CodeGenFunction::Destroyer &destroyer;
bool useEHCleanupForArray;
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Don't use an EH cleanup recursively from an EH cleanup.
- bool useEHCleanupForArray = !isForEH && this->useEHCleanupForArray;
+ bool useEHCleanupForArray =
+ flags.isForNormalCleanup() && this->useEHCleanupForArray;
CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray);
}
llvm::Value *NRVOFlag;
llvm::Value *Loc;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Along the exceptions path we always execute the dtor.
- bool NRVO = !IsForEH && NRVOFlag;
+ bool NRVO = flags.isForNormalCleanup() && NRVOFlag;
llvm::BasicBlock *SkipDtorBB = 0;
if (NRVO) {
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *V = CGF.Builder.CreateLoad(Stack, "tmp");
llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
CGF.Builder.CreateCall(F, V);
const VarDecl &Var;
ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
- void Emit(CodeGenFunction &CGF, bool forEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Compute the address of the local variable, in case it's a
// byref or something.
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
const VarDecl *Var)
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
SourceLocation());
// Compute the address of the local variable, in case it's a byref
: ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
ElementType(elementType), Destroyer(*destroyer) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
ElementType, Destroyer);
}
: ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
ElementType(elementType), Destroyer(*destroyer) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
ElementType, Destroyer);
llvm::Value *Param;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitARCRelease(Param, /*precise*/ false);
}
};
struct FreeException : EHScopeStack::Cleanup {
llvm::Value *exn;
FreeException(llvm::Value *exn) : exn(exn) {}
- void Emit(CodeGenFunction &CGF, bool forEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn)
->setDoesNotThrow();
}
CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
bool MightThrow;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
return;
namespace {
struct CallRethrow : EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCallOrInvoke(getReThrowFn(CGF), 0, 0);
}
};
CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::Value *EndCatchFn)
: ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch");
llvm::BasicBlock *CleanupContBB =
CGF.createBasicBlock("finally.cleanup.cont");
: Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn),
RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Enter a cleanup to call the end-catch function if one was provided.
if (EndCatchFn)
CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup,
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
QualType ElementType)
: Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
}
};
: Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements),
ElementType(ElementType), CookieSize(CookieSize) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const FunctionProtoType *DeleteFTy =
OperatorDelete->getType()->getAs<FunctionProtoType>();
assert(DeleteFTy->getNumArgs() == 1 || DeleteFTy->getNumArgs() == 2);
namespace {
struct FinishARCDealloc : EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
const ObjCImplementationDecl *impl
= cast<ObjCImplementationDecl>(method->getDeclContext());
: addr(addr), ivar(ivar), destroyer(*destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
- !isForEH && useEHCleanupForArray);
+ flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
}
llvm::Value *ptr;
llvm::Value *condition;
- void Emit(CodeGenFunction &CGF, bool forEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *object;
// If we're in a conditional branch, we had to stash away in an
CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitObjCAutoreleasePoolPop(Token);
}
};
CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
- void Emit(CodeGenFunction &CGF, bool isForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitObjCMRRAutoreleasePoolPop(Token);
}
};
: S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
// Check whether we need to call objc_exception_try_exit.
// In optimized code, this branch will always be folded.
llvm::BasicBlock *FinallyCallExit =
bool MightThrow;
llvm::Value *Fn;
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
return;
CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
: SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
}
};
llvm::Value *addr;
DestroyTemporary(const CXXDestructorDecl *dtor, llvm::Value *addr)
: dtor(dtor), addr(addr) {}
- void Emit(CodeGenFunction &CGF, bool forEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false,
addr);
}
// Anchor the construction vtable.
virtual void anchor();
public:
+ /// Generation flags.
+ class Flags {
+ enum {
+ F_IsForEH = 0x1,
+ F_IsNormalCleanupKind = 0x2,
+ F_IsEHCleanupKind = 0x4
+ };
+ unsigned flags;
+
+ public:
+ Flags() : flags(0) {}
+
+ /// isForEH - true if the current emission is for an EH cleanup.
+ bool isForEHCleanup() const { return flags & F_IsForEH; }
+ bool isForNormalCleanup() const { return !isForEHCleanup(); }
+ void setIsForEHCleanup() { flags |= F_IsForEH; }
+
+ bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
+ void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
+
+ /// isEHCleanupKind - true if the cleanup was pushed as an EH
+ /// cleanup.
+ bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
+ void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
+ };
+
// Provide a virtual destructor to suppress a very common warning
// that unfortunately cannot be suppressed without this. Cleanups
// should not rely on this destructor ever being called.
///
// \param IsForEHCleanup true if this is for an EH cleanup, false
/// if for a normal cleanup.
- virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
+ virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
};
/// ConditionalCleanupN stores the saved form of its N parameters,
typedef typename DominatingValue<A0>::saved_type A0_saved;
A0_saved a0_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
- T(a0).Emit(CGF, IsForEHCleanup);
+ T(a0).Emit(CGF, flags);
}
public:
A0_saved a0_saved;
A1_saved a1_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
- T(a0, a1).Emit(CGF, IsForEHCleanup);
+ T(a0, a1).Emit(CGF, flags);
}
public:
A1_saved a1_saved;
A2_saved a2_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
- T(a0, a1, a2).Emit(CGF, IsForEHCleanup);
+ T(a0, a1, a2).Emit(CGF, flags);
}
public:
A2_saved a2_saved;
A3_saved a3_saved;
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
- T(a0, a1, a2, a3).Emit(CGF, IsForEHCleanup);
+ T(a0, a1, a2, a3).Emit(CGF, flags);
}
public:
llvm::GlobalVariable *Guard;
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
->setDoesNotThrow();
}