1 //===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the Stmt class and statement subclasses.
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/Stmt.h"
15 #include "clang/AST/ExprCXX.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/AST/StmtCXX.h"
18 #include "clang/AST/StmtObjC.h"
19 #include "clang/AST/Type.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/ASTDiagnostic.h"
22 #include "clang/Basic/TargetInfo.h"
24 using namespace clang;
26 static struct StmtClassNameTable {
30 } StmtClassInfo[Stmt::lastStmtConstant+1];
32 static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
33 static bool Initialized = false;
35 return StmtClassInfo[E];
37 // Intialize the table on the first use.
39 #define ABSTRACT_STMT(STMT)
40 #define STMT(CLASS, PARENT) \
41 StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
42 StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
43 #include "clang/AST/StmtNodes.inc"
45 return StmtClassInfo[E];
48 const char *Stmt::getStmtClassName() const {
49 return getStmtInfoTableEntry((StmtClass)sClass).Name;
52 void Stmt::PrintStats() {
53 // Ensure the table is primed.
54 getStmtInfoTableEntry(Stmt::NullStmtClass);
57 fprintf(stderr, "*** Stmt/Expr Stats:\n");
58 for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
59 if (StmtClassInfo[i].Name == 0) continue;
60 sum += StmtClassInfo[i].Counter;
62 fprintf(stderr, " %d stmts/exprs total.\n", sum);
64 for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
65 if (StmtClassInfo[i].Name == 0) continue;
66 if (StmtClassInfo[i].Counter == 0) continue;
67 fprintf(stderr, " %d %s, %d each (%d bytes)\n",
68 StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
69 StmtClassInfo[i].Size,
70 StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
71 sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
73 fprintf(stderr, "Total bytes = %d\n", sum);
76 void Stmt::addStmtClass(StmtClass s) {
77 ++getStmtInfoTableEntry(s).Counter;
80 static bool StatSwitch = false;
82 bool Stmt::CollectingStats(bool Enable) {
83 if (Enable) StatSwitch = true;
87 void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
90 this->NumStmts = NumStmts;
92 Body = new (C) Stmt*[NumStmts];
93 memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
96 const char *LabelStmt::getName() const {
97 return getID()->getNameStart();
100 // This is defined here to avoid polluting Stmt.h with importing Expr.h
101 SourceRange ReturnStmt::getSourceRange() const {
103 return SourceRange(RetLoc, RetExpr->getLocEnd());
105 return SourceRange(RetLoc);
108 bool Stmt::hasImplicitControlFlow() const {
114 case ConditionalOperatorClass:
115 case ChooseExprClass:
120 case Stmt::BinaryOperatorClass: {
121 const BinaryOperator* B = cast<BinaryOperator>(this);
122 if (B->isLogicalOp() || B->getOpcode() == BO_Comma)
130 Expr *AsmStmt::getOutputExpr(unsigned i) {
131 return cast<Expr>(Exprs[i]);
134 /// getOutputConstraint - Return the constraint string for the specified
135 /// output operand. All output constraints are known to be non-empty (either
137 llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const {
138 return getOutputConstraintLiteral(i)->getString();
141 /// getNumPlusOperands - Return the number of output operands that have a "+"
143 unsigned AsmStmt::getNumPlusOperands() const {
145 for (unsigned i = 0, e = getNumOutputs(); i != e; ++i)
146 if (isOutputPlusConstraint(i))
151 Expr *AsmStmt::getInputExpr(unsigned i) {
152 return cast<Expr>(Exprs[i + NumOutputs]);
155 /// getInputConstraint - Return the specified input constraint. Unlike output
156 /// constraints, these can be empty.
157 llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const {
158 return getInputConstraintLiteral(i)->getString();
162 void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
163 IdentifierInfo **Names,
164 StringLiteral **Constraints,
168 StringLiteral **Clobbers,
169 unsigned NumClobbers) {
170 this->NumOutputs = NumOutputs;
171 this->NumInputs = NumInputs;
172 this->NumClobbers = NumClobbers;
174 unsigned NumExprs = NumOutputs + NumInputs;
176 C.Deallocate(this->Names);
177 this->Names = new (C) IdentifierInfo*[NumExprs];
178 std::copy(Names, Names + NumExprs, this->Names);
180 C.Deallocate(this->Exprs);
181 this->Exprs = new (C) Stmt*[NumExprs];
182 std::copy(Exprs, Exprs + NumExprs, this->Exprs);
184 C.Deallocate(this->Constraints);
185 this->Constraints = new (C) StringLiteral*[NumExprs];
186 std::copy(Constraints, Constraints + NumExprs, this->Constraints);
188 C.Deallocate(this->Clobbers);
189 this->Clobbers = new (C) StringLiteral*[NumClobbers];
190 std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
193 /// getNamedOperand - Given a symbolic operand reference like %[foo],
194 /// translate this into a numeric value needed to reference the same operand.
195 /// This returns -1 if the operand name is invalid.
196 int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
197 unsigned NumPlusOperands = 0;
199 // Check if this is an output operand.
200 for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
201 if (getOutputName(i) == SymbolicName)
205 for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
206 if (getInputName(i) == SymbolicName)
207 return getNumOutputs() + NumPlusOperands + i;
213 /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
214 /// it into pieces. If the asm string is erroneous, emit errors and return
215 /// true, otherwise return false.
216 unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
217 ASTContext &C, unsigned &DiagOffs) const {
218 llvm::StringRef Str = getAsmString()->getString();
219 const char *StrStart = Str.begin();
220 const char *StrEnd = Str.end();
221 const char *CurPtr = StrStart;
223 // "Simple" inline asms have no constraints or operands, just convert the asm
224 // string to escape $'s.
227 for (; CurPtr != StrEnd; ++CurPtr) {
237 Pieces.push_back(AsmStringPiece(Result));
241 // CurStringPiece - The current string that we are building up as we scan the
243 std::string CurStringPiece;
245 bool HasVariants = !C.Target.hasNoAsmVariants();
248 // Done with the string?
249 if (CurPtr == StrEnd) {
250 if (!CurStringPiece.empty())
251 Pieces.push_back(AsmStringPiece(CurStringPiece));
255 char CurChar = *CurPtr++;
257 case '$': CurStringPiece += "$$"; continue;
258 case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
259 case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
260 case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
264 CurStringPiece += CurChar;
268 // Escaped "%" character in asm string.
269 if (CurPtr == StrEnd) {
270 // % at end of string is invalid (no escape).
271 DiagOffs = CurPtr-StrStart-1;
272 return diag::err_asm_invalid_escape;
275 char EscapedChar = *CurPtr++;
276 if (EscapedChar == '%') { // %% -> %
277 // Escaped percentage sign.
278 CurStringPiece += '%';
282 if (EscapedChar == '=') { // %= -> Generate an unique ID.
283 CurStringPiece += "${:uid}";
287 // Otherwise, we have an operand. If we have accumulated a string so far,
288 // add it to the Pieces list.
289 if (!CurStringPiece.empty()) {
290 Pieces.push_back(AsmStringPiece(CurStringPiece));
291 CurStringPiece.clear();
294 // Handle %x4 and %x[foo] by capturing x as the modifier character.
295 char Modifier = '\0';
296 if (isalpha(EscapedChar)) {
297 Modifier = EscapedChar;
298 EscapedChar = *CurPtr++;
301 if (isdigit(EscapedChar)) {
302 // %n - Assembler operand n
306 while (CurPtr != StrEnd && isdigit(*CurPtr))
307 N = N*10 + ((*CurPtr++)-'0');
309 unsigned NumOperands =
310 getNumOutputs() + getNumPlusOperands() + getNumInputs();
311 if (N >= NumOperands) {
312 DiagOffs = CurPtr-StrStart-1;
313 return diag::err_asm_invalid_operand_number;
316 Pieces.push_back(AsmStringPiece(N, Modifier));
320 // Handle %[foo], a symbolic operand reference.
321 if (EscapedChar == '[') {
322 DiagOffs = CurPtr-StrStart-1;
325 const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
327 return diag::err_asm_unterminated_symbolic_operand_name;
328 if (NameEnd == CurPtr)
329 return diag::err_asm_empty_symbolic_operand_name;
331 llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
333 int N = getNamedOperand(SymbolicName);
335 // Verify that an operand with that name exists.
336 DiagOffs = CurPtr-StrStart;
337 return diag::err_asm_unknown_symbolic_operand_name;
339 Pieces.push_back(AsmStringPiece(N, Modifier));
345 DiagOffs = CurPtr-StrStart-1;
346 return diag::err_asm_invalid_escape;
350 QualType CXXCatchStmt::getCaughtType() const {
352 return ExceptionDecl->getType();
356 //===----------------------------------------------------------------------===//
358 //===----------------------------------------------------------------------===//
360 AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
361 bool isvolatile, bool msasm,
362 unsigned numoutputs, unsigned numinputs,
363 IdentifierInfo **names, StringLiteral **constraints,
364 Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
365 StringLiteral **clobbers, SourceLocation rparenloc)
366 : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
367 , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
368 , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
370 unsigned NumExprs = NumOutputs +NumInputs;
372 Names = new (C) IdentifierInfo*[NumExprs];
373 std::copy(names, names + NumExprs, Names);
375 Exprs = new (C) Stmt*[NumExprs];
376 std::copy(exprs, exprs + NumExprs, Exprs);
378 Constraints = new (C) StringLiteral*[NumExprs];
379 std::copy(constraints, constraints + NumExprs, Constraints);
381 Clobbers = new (C) StringLiteral*[NumClobbers];
382 std::copy(clobbers, clobbers + NumClobbers, Clobbers);
385 ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
386 Stmt *Body, SourceLocation FCL,
388 : Stmt(ObjCForCollectionStmtClass) {
389 SubExprs[ELEM] = Elem;
390 SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
391 SubExprs[BODY] = Body;
396 ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
397 Stmt **CatchStmts, unsigned NumCatchStmts,
399 : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
400 NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
402 Stmt **Stmts = getStmts();
403 Stmts[0] = atTryStmt;
404 for (unsigned I = 0; I != NumCatchStmts; ++I)
405 Stmts[I + 1] = CatchStmts[I];
408 Stmts[NumCatchStmts + 1] = atFinallyStmt;
411 ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
412 SourceLocation atTryLoc,
415 unsigned NumCatchStmts,
416 Stmt *atFinallyStmt) {
417 unsigned Size = sizeof(ObjCAtTryStmt) +
418 (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
419 void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
420 return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
424 ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
425 unsigned NumCatchStmts,
427 unsigned Size = sizeof(ObjCAtTryStmt) +
428 (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
429 void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
430 return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
433 SourceRange ObjCAtTryStmt::getSourceRange() const {
434 SourceLocation EndLoc;
436 EndLoc = getFinallyStmt()->getLocEnd();
437 else if (NumCatchStmts)
438 EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
440 EndLoc = getTryBody()->getLocEnd();
442 return SourceRange(AtTryLoc, EndLoc);
445 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
446 Stmt *tryBlock, Stmt **handlers,
447 unsigned numHandlers) {
448 std::size_t Size = sizeof(CXXTryStmt);
449 Size += ((numHandlers + 1) * sizeof(Stmt));
451 void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
452 return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
455 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
456 unsigned numHandlers) {
457 std::size_t Size = sizeof(CXXTryStmt);
458 Size += ((numHandlers + 1) * sizeof(Stmt));
460 void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
461 return new (Mem) CXXTryStmt(Empty, numHandlers);
464 CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
465 Stmt **handlers, unsigned numHandlers)
466 : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
467 Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
469 std::copy(handlers, handlers + NumHandlers, Stmts + 1);
472 IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
473 Stmt *then, SourceLocation EL, Stmt *elsev)
474 : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
476 setConditionVariable(C, var);
477 SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
478 SubExprs[THEN] = then;
479 SubExprs[ELSE] = elsev;
482 VarDecl *IfStmt::getConditionVariable() const {
486 DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
487 return cast<VarDecl>(DS->getSingleDecl());
490 void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
496 SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
497 V->getSourceRange().getBegin(),
498 V->getSourceRange().getEnd());
501 ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
502 Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
504 : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP)
506 SubExprs[INIT] = Init;
507 setConditionVariable(C, condVar);
508 SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
509 SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
510 SubExprs[BODY] = Body;
513 VarDecl *ForStmt::getConditionVariable() const {
514 if (!SubExprs[CONDVAR])
517 DeclStmt *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
518 return cast<VarDecl>(DS->getSingleDecl());
521 void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
523 SubExprs[CONDVAR] = 0;
527 SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V),
528 V->getSourceRange().getBegin(),
529 V->getSourceRange().getEnd());
532 SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond)
533 : Stmt(SwitchStmtClass), FirstCase(0)
535 setConditionVariable(C, Var);
536 SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
537 SubExprs[BODY] = NULL;
540 VarDecl *SwitchStmt::getConditionVariable() const {
544 DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
545 return cast<VarDecl>(DS->getSingleDecl());
548 void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
554 SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
555 V->getSourceRange().getBegin(),
556 V->getSourceRange().getEnd());
559 WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
561 : Stmt(WhileStmtClass)
563 setConditionVariable(C, Var);
564 SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
565 SubExprs[BODY] = body;
569 VarDecl *WhileStmt::getConditionVariable() const {
573 DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
574 return cast<VarDecl>(DS->getSingleDecl());
577 void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
583 SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
584 V->getSourceRange().getBegin(),
585 V->getSourceRange().getEnd());
588 //===----------------------------------------------------------------------===//
589 // Child Iterators for iterating over subexpressions/substatements
590 //===----------------------------------------------------------------------===//
593 Stmt::child_iterator DeclStmt::child_begin() {
594 return StmtIterator(DG.begin(), DG.end());
597 Stmt::child_iterator DeclStmt::child_end() {
598 return StmtIterator(DG.end(), DG.end());
602 Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
603 Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }
606 Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
607 Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; }
610 Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
611 Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
614 Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
615 Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
618 Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
619 Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
622 Stmt::child_iterator IfStmt::child_begin() {
625 Stmt::child_iterator IfStmt::child_end() {
626 return &SubExprs[0]+END_EXPR;
630 Stmt::child_iterator SwitchStmt::child_begin() {
633 Stmt::child_iterator SwitchStmt::child_end() {
634 return &SubExprs[0]+END_EXPR;
638 Stmt::child_iterator WhileStmt::child_begin() {
641 Stmt::child_iterator WhileStmt::child_end() {
642 return &SubExprs[0]+END_EXPR;
646 Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
647 Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
650 Stmt::child_iterator ForStmt::child_begin() {
653 Stmt::child_iterator ForStmt::child_end() {
654 return &SubExprs[0]+END_EXPR;
657 // ObjCForCollectionStmt
658 Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
661 Stmt::child_iterator ObjCForCollectionStmt::child_end() {
662 return &SubExprs[0]+END_EXPR;
666 Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
667 Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }
670 Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
671 const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }
673 Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
674 Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }
677 Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
678 Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }
681 Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
682 Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }
685 const Expr* ReturnStmt::getRetValue() const {
686 return cast_or_null<Expr>(RetExpr);
688 Expr* ReturnStmt::getRetValue() {
689 return cast_or_null<Expr>(RetExpr);
692 Stmt::child_iterator ReturnStmt::child_begin() {
695 Stmt::child_iterator ReturnStmt::child_end() {
696 return RetExpr ? &RetExpr+1 : &RetExpr;
700 Stmt::child_iterator AsmStmt::child_begin() {
701 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0];
703 Stmt::child_iterator AsmStmt::child_end() {
704 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs;
708 Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
709 Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
712 Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
713 Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
716 Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
718 Stmt::child_iterator ObjCAtTryStmt::child_end() {
719 return getStmts() + 1 + NumCatchStmts + HasFinally;
723 Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
727 Stmt::child_iterator ObjCAtThrowStmt::child_end() {
731 // ObjCAtSynchronizedStmt
732 Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
736 Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
737 return &SubStmts[0]+END_EXPR;
741 Stmt::child_iterator CXXCatchStmt::child_begin() {
742 return &HandlerBlock;
745 Stmt::child_iterator CXXCatchStmt::child_end() {
746 return &HandlerBlock + 1;
750 Stmt::child_iterator CXXTryStmt::child_begin() {
751 return reinterpret_cast<Stmt **>(this + 1);
754 Stmt::child_iterator CXXTryStmt::child_end() {
755 return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1;