blob: f1294746a42deb14e023b60774dadd8be01364b2 [file] [log] [blame]
John McCallf1549f62010-07-06 01:34:17 +00001//===-- CGException.h - Classes for exceptions IR generation ----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These classes support the generation of LLVM IR for exceptions in
11// C++ and Objective C.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef CLANG_CODEGEN_CGEXCEPTION_H
16#define CLANG_CODEGEN_CGEXCEPTION_H
17
18/// EHScopeStack is defined in CodeGenFunction.h, but its
19/// implementation is in this file and in CGException.cpp.
20#include "CodeGenFunction.h"
21
22namespace llvm {
23 class Value;
24 class BasicBlock;
25}
26
27namespace clang {
28namespace CodeGen {
29
John McCall8262b6a2010-07-17 00:43:08 +000030/// The exceptions personality for a function. When
31class EHPersonality {
32 const char *PersonalityFn;
33
34 // If this is non-null, this personality requires a non-standard
35 // function for rethrowing an exception after a catchall cleanup.
36 // This function must have prototype void(void*).
37 const char *CatchallRethrowFn;
38
39 EHPersonality(const char *PersonalityFn,
40 const char *CatchallRethrowFn = 0)
41 : PersonalityFn(PersonalityFn),
42 CatchallRethrowFn(CatchallRethrowFn) {}
43
44public:
45 static const EHPersonality &get(const LangOptions &Lang);
46 static const EHPersonality GNU_C;
47 static const EHPersonality GNU_ObjC;
48 static const EHPersonality NeXT_ObjC;
49 static const EHPersonality GNU_CPlusPlus;
50 static const EHPersonality GNU_CPlusPlus_SJLJ;
51
52 const char *getPersonalityFnName() const { return PersonalityFn; }
53 const char *getCatchallRethrowFnName() const { return CatchallRethrowFn; }
54};
55
John McCallf1549f62010-07-06 01:34:17 +000056/// A protected scope for zero-cost EH handling.
57class EHScope {
58 llvm::BasicBlock *CachedLandingPad;
59
John McCall7495f222010-07-21 07:11:21 +000060 unsigned K : 2;
John McCallf1549f62010-07-06 01:34:17 +000061
62protected:
John McCall7495f222010-07-21 07:11:21 +000063 enum { BitsRemaining = 30 };
John McCallf1549f62010-07-06 01:34:17 +000064
65public:
John McCall1f0fca52010-07-21 07:22:38 +000066 enum Kind { Cleanup, Catch, Terminate, Filter };
John McCallf1549f62010-07-06 01:34:17 +000067
68 EHScope(Kind K) : CachedLandingPad(0), K(K) {}
69
70 Kind getKind() const { return static_cast<Kind>(K); }
71
72 llvm::BasicBlock *getCachedLandingPad() const {
73 return CachedLandingPad;
74 }
75
76 void setCachedLandingPad(llvm::BasicBlock *Block) {
77 CachedLandingPad = Block;
78 }
79};
80
81/// A scope which attempts to handle some, possibly all, types of
82/// exceptions.
83///
84/// Objective C @finally blocks are represented using a cleanup scope
85/// after the catch scope.
86class EHCatchScope : public EHScope {
87 unsigned NumHandlers : BitsRemaining;
88
89 // In effect, we have a flexible array member
90 // Handler Handlers[0];
91 // But that's only standard in C99, not C++, so we have to do
92 // annoying pointer arithmetic instead.
93
94public:
95 struct Handler {
96 /// A type info value, or null (C++ null, not an LLVM null pointer)
97 /// for a catch-all.
98 llvm::Value *Type;
99
100 /// The catch handler for this type.
101 llvm::BasicBlock *Block;
102
John McCallff8e1152010-07-23 21:56:41 +0000103 /// The unwind destination index for this handler.
104 unsigned Index;
John McCallf1549f62010-07-06 01:34:17 +0000105 };
106
107private:
John McCallff8e1152010-07-23 21:56:41 +0000108 friend class EHScopeStack;
109
John McCallf1549f62010-07-06 01:34:17 +0000110 Handler *getHandlers() {
111 return reinterpret_cast<Handler*>(this+1);
112 }
113
114 const Handler *getHandlers() const {
115 return reinterpret_cast<const Handler*>(this+1);
116 }
117
118public:
119 static size_t getSizeForNumHandlers(unsigned N) {
120 return sizeof(EHCatchScope) + N * sizeof(Handler);
121 }
122
123 EHCatchScope(unsigned NumHandlers)
124 : EHScope(Catch), NumHandlers(NumHandlers) {
125 }
126
127 unsigned getNumHandlers() const {
128 return NumHandlers;
129 }
130
131 void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
132 setHandler(I, /*catchall*/ 0, Block);
133 }
134
135 void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
136 assert(I < getNumHandlers());
John McCallff8e1152010-07-23 21:56:41 +0000137 getHandlers()[I].Type = Type;
138 getHandlers()[I].Block = Block;
John McCallf1549f62010-07-06 01:34:17 +0000139 }
140
141 const Handler &getHandler(unsigned I) const {
142 assert(I < getNumHandlers());
143 return getHandlers()[I];
144 }
145
146 typedef const Handler *iterator;
147 iterator begin() const { return getHandlers(); }
148 iterator end() const { return getHandlers() + getNumHandlers(); }
149
150 static bool classof(const EHScope *Scope) {
151 return Scope->getKind() == Catch;
152 }
153};
154
John McCallda65ea82010-07-13 20:32:21 +0000155/// A cleanup scope which generates the cleanup blocks lazily.
John McCall1f0fca52010-07-21 07:22:38 +0000156class EHCleanupScope : public EHScope {
John McCallda65ea82010-07-13 20:32:21 +0000157 /// Whether this cleanup needs to be run along normal edges.
158 bool IsNormalCleanup : 1;
159
160 /// Whether this cleanup needs to be run along exception edges.
161 bool IsEHCleanup : 1;
162
John McCallcd2d2b72010-08-13 21:20:51 +0000163 /// Whether this cleanup was activated before all normal uses.
164 bool ActivatedBeforeNormalUse : 1;
165
166 /// Whether this cleanup was activated before all EH uses.
167 bool ActivatedBeforeEHUse : 1;
168
John McCall1f0fca52010-07-21 07:22:38 +0000169 /// The amount of extra storage needed by the Cleanup.
John McCallda65ea82010-07-13 20:32:21 +0000170 /// Always a multiple of the scope-stack alignment.
171 unsigned CleanupSize : 12;
172
173 /// The number of fixups required by enclosing scopes (not including
174 /// this one). If this is the top cleanup scope, all the fixups
175 /// from this index onwards belong to this scope.
John McCallcd2d2b72010-08-13 21:20:51 +0000176 unsigned FixupDepth : BitsRemaining - 16;
John McCallda65ea82010-07-13 20:32:21 +0000177
178 /// The nearest normal cleanup scope enclosing this one.
179 EHScopeStack::stable_iterator EnclosingNormal;
180
181 /// The nearest EH cleanup scope enclosing this one.
182 EHScopeStack::stable_iterator EnclosingEH;
183
184 /// The dual entry/exit block along the normal edge. This is lazily
185 /// created if needed before the cleanup is popped.
186 llvm::BasicBlock *NormalBlock;
187
188 /// The dual entry/exit block along the EH edge. This is lazily
189 /// created if needed before the cleanup is popped.
190 llvm::BasicBlock *EHBlock;
191
John McCallcd2d2b72010-08-13 21:20:51 +0000192 /// An optional i1 variable indicating whether this cleanup has been
193 /// activated yet. This has one of three states:
194 /// - it is null if the cleanup is inactive
195 /// - it is activeSentinel() if the cleanup is active and was not
196 /// required before activation
197 /// - it points to a valid variable
198 llvm::AllocaInst *ActiveVar;
199
John McCallff8e1152010-07-23 21:56:41 +0000200 /// Extra information required for cleanups that have resolved
201 /// branches through them. This has to be allocated on the side
202 /// because everything on the cleanup stack has be trivially
203 /// movable.
204 struct ExtInfo {
205 /// The destinations of normal branch-afters and branch-throughs.
206 llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
207
208 /// Normal branch-afters.
209 llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
210 BranchAfters;
211
212 /// The destinations of EH branch-afters and branch-throughs.
213 /// TODO: optimize for the extremely common case of a single
214 /// branch-through.
215 llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
216
217 /// EH branch-afters.
218 llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
219 EHBranchAfters;
220 };
221 mutable struct ExtInfo *ExtInfo;
222
223 struct ExtInfo &getExtInfo() {
224 if (!ExtInfo) ExtInfo = new struct ExtInfo();
225 return *ExtInfo;
226 }
227
228 const struct ExtInfo &getExtInfo() const {
229 if (!ExtInfo) ExtInfo = new struct ExtInfo();
230 return *ExtInfo;
231 }
232
John McCallda65ea82010-07-13 20:32:21 +0000233public:
234 /// Gets the size required for a lazy cleanup scope with the given
235 /// cleanup-data requirements.
236 static size_t getSizeForCleanupSize(size_t Size) {
John McCall1f0fca52010-07-21 07:22:38 +0000237 return sizeof(EHCleanupScope) + Size;
John McCallda65ea82010-07-13 20:32:21 +0000238 }
239
240 size_t getAllocatedSize() const {
John McCall1f0fca52010-07-21 07:22:38 +0000241 return sizeof(EHCleanupScope) + CleanupSize;
John McCallda65ea82010-07-13 20:32:21 +0000242 }
243
John McCallcd2d2b72010-08-13 21:20:51 +0000244 EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive,
245 unsigned CleanupSize, unsigned FixupDepth,
John McCall1f0fca52010-07-21 07:22:38 +0000246 EHScopeStack::stable_iterator EnclosingNormal,
247 EHScopeStack::stable_iterator EnclosingEH)
248 : EHScope(EHScope::Cleanup),
John McCallda65ea82010-07-13 20:32:21 +0000249 IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
John McCallcd2d2b72010-08-13 21:20:51 +0000250 ActivatedBeforeNormalUse(IsActive),
251 ActivatedBeforeEHUse(IsActive),
John McCallda65ea82010-07-13 20:32:21 +0000252 CleanupSize(CleanupSize), FixupDepth(FixupDepth),
253 EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
John McCallcd2d2b72010-08-13 21:20:51 +0000254 NormalBlock(0), EHBlock(0),
255 ActiveVar(IsActive ? activeSentinel() : 0),
256 ExtInfo(0)
John McCallff8e1152010-07-23 21:56:41 +0000257 {
258 assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
259 }
260
261 ~EHCleanupScope() {
262 delete ExtInfo;
263 }
John McCallda65ea82010-07-13 20:32:21 +0000264
265 bool isNormalCleanup() const { return IsNormalCleanup; }
266 llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
267 void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
268
269 bool isEHCleanup() const { return IsEHCleanup; }
270 llvm::BasicBlock *getEHBlock() const { return EHBlock; }
271 void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
272
John McCallcd2d2b72010-08-13 21:20:51 +0000273 static llvm::AllocaInst *activeSentinel() {
274 return reinterpret_cast<llvm::AllocaInst*>(1);
275 }
276
277 bool isActive() const { return ActiveVar != 0; }
278 llvm::AllocaInst *getActiveVar() const { return ActiveVar; }
279 void setActiveVar(llvm::AllocaInst *Var) { ActiveVar = Var; }
280
281 bool wasActivatedBeforeNormalUse() const { return ActivatedBeforeNormalUse; }
282 void setActivatedBeforeNormalUse(bool B) { ActivatedBeforeNormalUse = B; }
283
284 bool wasActivatedBeforeEHUse() const { return ActivatedBeforeEHUse; }
285 void setActivatedBeforeEHUse(bool B) { ActivatedBeforeEHUse = B; }
286
John McCallda65ea82010-07-13 20:32:21 +0000287 unsigned getFixupDepth() const { return FixupDepth; }
288 EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
289 return EnclosingNormal;
290 }
291 EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
292 return EnclosingEH;
293 }
294
295 size_t getCleanupSize() const { return CleanupSize; }
296 void *getCleanupBuffer() { return this + 1; }
297
John McCall1f0fca52010-07-21 07:22:38 +0000298 EHScopeStack::Cleanup *getCleanup() {
299 return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
John McCallda65ea82010-07-13 20:32:21 +0000300 }
301
John McCallff8e1152010-07-23 21:56:41 +0000302 /// True if this cleanup scope has any branch-afters or branch-throughs.
303 bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
304
305 /// Add a branch-after to this cleanup scope. A branch-after is a
306 /// branch from a point protected by this (normal) cleanup to a
307 /// point in the normal cleanup scope immediately containing it.
308 /// For example,
309 /// for (;;) { A a; break; }
310 /// contains a branch-after.
311 ///
312 /// Branch-afters each have their own destination out of the
313 /// cleanup, guaranteed distinct from anything else threaded through
314 /// it. Therefore branch-afters usually force a switch after the
315 /// cleanup.
316 void addBranchAfter(llvm::ConstantInt *Index,
317 llvm::BasicBlock *Block) {
318 struct ExtInfo &ExtInfo = getExtInfo();
319 if (ExtInfo.Branches.insert(Block))
320 ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
321 }
322
323 /// Return the number of unique branch-afters on this scope.
324 unsigned getNumBranchAfters() const {
325 return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
326 }
327
328 llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
329 assert(I < getNumBranchAfters());
330 return ExtInfo->BranchAfters[I].first;
331 }
332
333 llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
334 assert(I < getNumBranchAfters());
335 return ExtInfo->BranchAfters[I].second;
336 }
337
338 /// Add a branch-through to this cleanup scope. A branch-through is
339 /// a branch from a scope protected by this (normal) cleanup to an
340 /// enclosing scope other than the immediately-enclosing normal
341 /// cleanup scope.
342 ///
343 /// In the following example, the branch through B's scope is a
344 /// branch-through, while the branch through A's scope is a
345 /// branch-after:
346 /// for (;;) { A a; B b; break; }
347 ///
348 /// All branch-throughs have a common destination out of the
349 /// cleanup, one possibly shared with the fall-through. Therefore
350 /// branch-throughs usually don't force a switch after the cleanup.
351 ///
352 /// \return true if the branch-through was new to this scope
353 bool addBranchThrough(llvm::BasicBlock *Block) {
354 return getExtInfo().Branches.insert(Block);
355 }
356
357 /// Determines if this cleanup scope has any branch throughs.
358 bool hasBranchThroughs() const {
359 if (!ExtInfo) return false;
360 return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
361 }
362
363 // Same stuff, only for EH branches instead of normal branches.
364 // It's quite possible that we could find a better representation
365 // for this.
366
367 bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
368 void addEHBranchAfter(llvm::ConstantInt *Index,
369 llvm::BasicBlock *Block) {
370 struct ExtInfo &ExtInfo = getExtInfo();
371 if (ExtInfo.EHBranches.insert(Block))
372 ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
373 }
374
375 unsigned getNumEHBranchAfters() const {
376 return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
377 }
378
379 llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
380 assert(I < getNumEHBranchAfters());
381 return ExtInfo->EHBranchAfters[I].first;
382 }
383
384 llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
385 assert(I < getNumEHBranchAfters());
386 return ExtInfo->EHBranchAfters[I].second;
387 }
388
389 bool addEHBranchThrough(llvm::BasicBlock *Block) {
390 return getExtInfo().EHBranches.insert(Block);
391 }
392
393 bool hasEHBranchThroughs() const {
394 if (!ExtInfo) return false;
395 return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
396 }
397
John McCallda65ea82010-07-13 20:32:21 +0000398 static bool classof(const EHScope *Scope) {
John McCall1f0fca52010-07-21 07:22:38 +0000399 return (Scope->getKind() == Cleanup);
John McCallda65ea82010-07-13 20:32:21 +0000400 }
401};
402
John McCallf1549f62010-07-06 01:34:17 +0000403/// An exceptions scope which filters exceptions thrown through it.
404/// Only exceptions matching the filter types will be permitted to be
405/// thrown.
406///
407/// This is used to implement C++ exception specifications.
408class EHFilterScope : public EHScope {
409 unsigned NumFilters : BitsRemaining;
410
411 // Essentially ends in a flexible array member:
412 // llvm::Value *FilterTypes[0];
413
414 llvm::Value **getFilters() {
415 return reinterpret_cast<llvm::Value**>(this+1);
416 }
417
418 llvm::Value * const *getFilters() const {
419 return reinterpret_cast<llvm::Value* const *>(this+1);
420 }
421
422public:
423 EHFilterScope(unsigned NumFilters) :
424 EHScope(Filter), NumFilters(NumFilters) {}
425
426 static size_t getSizeForNumFilters(unsigned NumFilters) {
427 return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
428 }
429
430 unsigned getNumFilters() const { return NumFilters; }
431
432 void setFilter(unsigned I, llvm::Value *FilterValue) {
433 assert(I < getNumFilters());
434 getFilters()[I] = FilterValue;
435 }
436
437 llvm::Value *getFilter(unsigned I) const {
438 assert(I < getNumFilters());
439 return getFilters()[I];
440 }
441
442 static bool classof(const EHScope *Scope) {
443 return Scope->getKind() == Filter;
444 }
445};
446
447/// An exceptions scope which calls std::terminate if any exception
448/// reaches it.
449class EHTerminateScope : public EHScope {
John McCallff8e1152010-07-23 21:56:41 +0000450 unsigned DestIndex : BitsRemaining;
John McCallf1549f62010-07-06 01:34:17 +0000451public:
John McCallff8e1152010-07-23 21:56:41 +0000452 EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
John McCallf1549f62010-07-06 01:34:17 +0000453 static size_t getSize() { return sizeof(EHTerminateScope); }
454
John McCallff8e1152010-07-23 21:56:41 +0000455 unsigned getDestIndex() const { return DestIndex; }
456
John McCallf1549f62010-07-06 01:34:17 +0000457 static bool classof(const EHScope *Scope) {
458 return Scope->getKind() == Terminate;
459 }
460};
461
462/// A non-stable pointer into the scope stack.
463class EHScopeStack::iterator {
464 char *Ptr;
465
466 friend class EHScopeStack;
467 explicit iterator(char *Ptr) : Ptr(Ptr) {}
468
469public:
470 iterator() : Ptr(0) {}
471
472 EHScope *get() const {
473 return reinterpret_cast<EHScope*>(Ptr);
474 }
475
476 EHScope *operator->() const { return get(); }
477 EHScope &operator*() const { return *get(); }
478
479 iterator &operator++() {
480 switch (get()->getKind()) {
481 case EHScope::Catch:
482 Ptr += EHCatchScope::getSizeForNumHandlers(
483 static_cast<const EHCatchScope*>(get())->getNumHandlers());
484 break;
485
486 case EHScope::Filter:
487 Ptr += EHFilterScope::getSizeForNumFilters(
488 static_cast<const EHFilterScope*>(get())->getNumFilters());
489 break;
490
John McCall1f0fca52010-07-21 07:22:38 +0000491 case EHScope::Cleanup:
492 Ptr += static_cast<const EHCleanupScope*>(get())
John McCallda65ea82010-07-13 20:32:21 +0000493 ->getAllocatedSize();
494 break;
495
John McCallf1549f62010-07-06 01:34:17 +0000496 case EHScope::Terminate:
497 Ptr += EHTerminateScope::getSize();
498 break;
499 }
500
501 return *this;
502 }
503
504 iterator next() {
505 iterator copy = *this;
506 ++copy;
507 return copy;
508 }
509
510 iterator operator++(int) {
511 iterator copy = *this;
512 operator++();
513 return copy;
514 }
515
John McCallff8e1152010-07-23 21:56:41 +0000516 bool encloses(iterator other) const { return Ptr >= other.Ptr; }
517 bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
518
John McCallf1549f62010-07-06 01:34:17 +0000519 bool operator==(iterator other) const { return Ptr == other.Ptr; }
520 bool operator!=(iterator other) const { return Ptr != other.Ptr; }
521};
522
523inline EHScopeStack::iterator EHScopeStack::begin() const {
524 return iterator(StartOfData);
525}
526
527inline EHScopeStack::iterator EHScopeStack::end() const {
528 return iterator(EndOfBuffer);
529}
530
531inline void EHScopeStack::popCatch() {
532 assert(!empty() && "popping exception stack when not empty");
533
534 assert(isa<EHCatchScope>(*begin()));
535 StartOfData += EHCatchScope::getSizeForNumHandlers(
536 cast<EHCatchScope>(*begin()).getNumHandlers());
537
John McCallff8e1152010-07-23 21:56:41 +0000538 if (empty()) NextEHDestIndex = FirstEHDestIndex;
539
John McCallf1549f62010-07-06 01:34:17 +0000540 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
541 CatchDepth--;
542}
543
544inline void EHScopeStack::popTerminate() {
545 assert(!empty() && "popping exception stack when not empty");
546
547 assert(isa<EHTerminateScope>(*begin()));
548 StartOfData += EHTerminateScope::getSize();
549
John McCallff8e1152010-07-23 21:56:41 +0000550 if (empty()) NextEHDestIndex = FirstEHDestIndex;
551
John McCallf1549f62010-07-06 01:34:17 +0000552 assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
553 CatchDepth--;
554}
555
556inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
557 assert(sp.isValid() && "finding invalid savepoint");
558 assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
559 return iterator(EndOfBuffer - sp.Size);
560}
561
562inline EHScopeStack::stable_iterator
563EHScopeStack::stabilize(iterator ir) const {
564 assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
565 return stable_iterator(EndOfBuffer - ir.Ptr);
566}
567
John McCall838d7962010-08-14 07:46:19 +0000568inline EHScopeStack::stable_iterator
569EHScopeStack::getInnermostActiveNormalCleanup() const {
570 for (EHScopeStack::stable_iterator
571 I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) {
572 EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
573 if (S.isActive()) return I;
574 I = S.getEnclosingNormalCleanup();
575 }
576 return stable_end();
577}
578
579inline EHScopeStack::stable_iterator
580EHScopeStack::getInnermostActiveEHCleanup() const {
581 for (EHScopeStack::stable_iterator
582 I = getInnermostEHCleanup(), E = stable_end(); I != E; ) {
583 EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
584 if (S.isActive()) return I;
585 I = S.getEnclosingEHCleanup();
586 }
587 return stable_end();
588}
589
John McCallf1549f62010-07-06 01:34:17 +0000590}
591}
592
593#endif