Stmt.cpp revision 206275
1//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// 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// This file implements the Stmt class and statement subclasses. 11// 12//===----------------------------------------------------------------------===// 13 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 <cstdio> 23using namespace clang; 24 25static struct StmtClassNameTable { 26 const char *Name; 27 unsigned Counter; 28 unsigned Size; 29} StmtClassInfo[Stmt::lastExprConstant+1]; 30 31static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { 32 static bool Initialized = false; 33 if (Initialized) 34 return StmtClassInfo[E]; 35 36 // Intialize the table on the first use. 37 Initialized = true; 38#define ABSTRACT_EXPR(CLASS, PARENT) 39#define STMT(CLASS, PARENT) \ 40 StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ 41 StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); 42#include "clang/AST/StmtNodes.def" 43 44 return StmtClassInfo[E]; 45} 46 47const char *Stmt::getStmtClassName() const { 48 return getStmtInfoTableEntry((StmtClass)sClass).Name; 49} 50 51void Stmt::PrintStats() { 52 // Ensure the table is primed. 53 getStmtInfoTableEntry(Stmt::NullStmtClass); 54 55 unsigned sum = 0; 56 fprintf(stderr, "*** Stmt/Expr Stats:\n"); 57 for (int i = 0; i != Stmt::lastExprConstant+1; i++) { 58 if (StmtClassInfo[i].Name == 0) continue; 59 sum += StmtClassInfo[i].Counter; 60 } 61 fprintf(stderr, " %d stmts/exprs total.\n", sum); 62 sum = 0; 63 for (int i = 0; i != Stmt::lastExprConstant+1; i++) { 64 if (StmtClassInfo[i].Name == 0) continue; 65 if (StmtClassInfo[i].Counter == 0) continue; 66 fprintf(stderr, " %d %s, %d each (%d bytes)\n", 67 StmtClassInfo[i].Counter, StmtClassInfo[i].Name, 68 StmtClassInfo[i].Size, 69 StmtClassInfo[i].Counter*StmtClassInfo[i].Size); 70 sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size; 71 } 72 fprintf(stderr, "Total bytes = %d\n", sum); 73} 74 75void Stmt::addStmtClass(StmtClass s) { 76 ++getStmtInfoTableEntry(s).Counter; 77} 78 79static bool StatSwitch = false; 80 81bool Stmt::CollectingStats(bool Enable) { 82 if (Enable) StatSwitch = true; 83 return StatSwitch; 84} 85 86void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { 87 if (this->Body) 88 C.Deallocate(Body); 89 this->NumStmts = NumStmts; 90 91 Body = new (C) Stmt*[NumStmts]; 92 memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts); 93} 94 95const char *LabelStmt::getName() const { 96 return getID()->getNameStart(); 97} 98 99// This is defined here to avoid polluting Stmt.h with importing Expr.h 100SourceRange ReturnStmt::getSourceRange() const { 101 if (RetExpr) 102 return SourceRange(RetLoc, RetExpr->getLocEnd()); 103 else 104 return SourceRange(RetLoc); 105} 106 107bool Stmt::hasImplicitControlFlow() const { 108 switch (sClass) { 109 default: 110 return false; 111 112 case CallExprClass: 113 case ConditionalOperatorClass: 114 case ChooseExprClass: 115 case StmtExprClass: 116 case DeclStmtClass: 117 return true; 118 119 case Stmt::BinaryOperatorClass: { 120 const BinaryOperator* B = cast<BinaryOperator>(this); 121 if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma) 122 return true; 123 else 124 return false; 125 } 126 } 127} 128 129Expr *AsmStmt::getOutputExpr(unsigned i) { 130 return cast<Expr>(Exprs[i]); 131} 132 133/// getOutputConstraint - Return the constraint string for the specified 134/// output operand. All output constraints are known to be non-empty (either 135/// '=' or '+'). 136llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const { 137 return getOutputConstraintLiteral(i)->getString(); 138} 139 140/// getNumPlusOperands - Return the number of output operands that have a "+" 141/// constraint. 142unsigned AsmStmt::getNumPlusOperands() const { 143 unsigned Res = 0; 144 for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) 145 if (isOutputPlusConstraint(i)) 146 ++Res; 147 return Res; 148} 149 150Expr *AsmStmt::getInputExpr(unsigned i) { 151 return cast<Expr>(Exprs[i + NumOutputs]); 152} 153 154/// getInputConstraint - Return the specified input constraint. Unlike output 155/// constraints, these can be empty. 156llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const { 157 return getInputConstraintLiteral(i)->getString(); 158} 159 160 161void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, 162 IdentifierInfo **Names, 163 StringLiteral **Constraints, 164 Stmt **Exprs, 165 unsigned NumOutputs, 166 unsigned NumInputs, 167 StringLiteral **Clobbers, 168 unsigned NumClobbers) { 169 this->NumOutputs = NumOutputs; 170 this->NumInputs = NumInputs; 171 this->NumClobbers = NumClobbers; 172 173 unsigned NumExprs = NumOutputs + NumInputs; 174 175 C.Deallocate(this->Names); 176 this->Names = new (C) IdentifierInfo*[NumExprs]; 177 std::copy(Names, Names + NumExprs, this->Names); 178 179 C.Deallocate(this->Exprs); 180 this->Exprs = new (C) Stmt*[NumExprs]; 181 std::copy(Exprs, Exprs + NumExprs, this->Exprs); 182 183 C.Deallocate(this->Constraints); 184 this->Constraints = new (C) StringLiteral*[NumExprs]; 185 std::copy(Constraints, Constraints + NumExprs, this->Constraints); 186 187 C.Deallocate(this->Clobbers); 188 this->Clobbers = new (C) StringLiteral*[NumClobbers]; 189 std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers); 190} 191 192/// getNamedOperand - Given a symbolic operand reference like %[foo], 193/// translate this into a numeric value needed to reference the same operand. 194/// This returns -1 if the operand name is invalid. 195int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { 196 unsigned NumPlusOperands = 0; 197 198 // Check if this is an output operand. 199 for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) { 200 if (getOutputName(i) == SymbolicName) 201 return i; 202 } 203 204 for (unsigned i = 0, e = getNumInputs(); i != e; ++i) 205 if (getInputName(i) == SymbolicName) 206 return getNumOutputs() + NumPlusOperands + i; 207 208 // Not found. 209 return -1; 210} 211 212/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing 213/// it into pieces. If the asm string is erroneous, emit errors and return 214/// true, otherwise return false. 215unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, 216 ASTContext &C, unsigned &DiagOffs) const { 217 const char *StrStart = getAsmString()->getStrData(); 218 const char *StrEnd = StrStart + getAsmString()->getByteLength(); 219 const char *CurPtr = StrStart; 220 221 // "Simple" inline asms have no constraints or operands, just convert the asm 222 // string to escape $'s. 223 if (isSimple()) { 224 std::string Result; 225 for (; CurPtr != StrEnd; ++CurPtr) { 226 switch (*CurPtr) { 227 case '$': 228 Result += "$$"; 229 break; 230 default: 231 Result += *CurPtr; 232 break; 233 } 234 } 235 Pieces.push_back(AsmStringPiece(Result)); 236 return 0; 237 } 238 239 // CurStringPiece - The current string that we are building up as we scan the 240 // asm string. 241 std::string CurStringPiece; 242 243 while (1) { 244 // Done with the string? 245 if (CurPtr == StrEnd) { 246 if (!CurStringPiece.empty()) 247 Pieces.push_back(AsmStringPiece(CurStringPiece)); 248 return 0; 249 } 250 251 char CurChar = *CurPtr++; 252 switch (CurChar) { 253 case '$': CurStringPiece += "$$"; continue; 254 case '{': CurStringPiece += "$("; continue; 255 case '|': CurStringPiece += "$|"; continue; 256 case '}': CurStringPiece += "$)"; continue; 257 case '%': 258 break; 259 default: 260 CurStringPiece += CurChar; 261 continue; 262 } 263 264 // Escaped "%" character in asm string. 265 if (CurPtr == StrEnd) { 266 // % at end of string is invalid (no escape). 267 DiagOffs = CurPtr-StrStart-1; 268 return diag::err_asm_invalid_escape; 269 } 270 271 char EscapedChar = *CurPtr++; 272 if (EscapedChar == '%') { // %% -> % 273 // Escaped percentage sign. 274 CurStringPiece += '%'; 275 continue; 276 } 277 278 if (EscapedChar == '=') { // %= -> Generate an unique ID. 279 CurStringPiece += "${:uid}"; 280 continue; 281 } 282 283 // Otherwise, we have an operand. If we have accumulated a string so far, 284 // add it to the Pieces list. 285 if (!CurStringPiece.empty()) { 286 Pieces.push_back(AsmStringPiece(CurStringPiece)); 287 CurStringPiece.clear(); 288 } 289 290 // Handle %x4 and %x[foo] by capturing x as the modifier character. 291 char Modifier = '\0'; 292 if (isalpha(EscapedChar)) { 293 Modifier = EscapedChar; 294 EscapedChar = *CurPtr++; 295 } 296 297 if (isdigit(EscapedChar)) { 298 // %n - Assembler operand n 299 unsigned N = 0; 300 301 --CurPtr; 302 while (CurPtr != StrEnd && isdigit(*CurPtr)) 303 N = N*10 + ((*CurPtr++)-'0'); 304 305 unsigned NumOperands = 306 getNumOutputs() + getNumPlusOperands() + getNumInputs(); 307 if (N >= NumOperands) { 308 DiagOffs = CurPtr-StrStart-1; 309 return diag::err_asm_invalid_operand_number; 310 } 311 312 Pieces.push_back(AsmStringPiece(N, Modifier)); 313 continue; 314 } 315 316 // Handle %[foo], a symbolic operand reference. 317 if (EscapedChar == '[') { 318 DiagOffs = CurPtr-StrStart-1; 319 320 // Find the ']'. 321 const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); 322 if (NameEnd == 0) 323 return diag::err_asm_unterminated_symbolic_operand_name; 324 if (NameEnd == CurPtr) 325 return diag::err_asm_empty_symbolic_operand_name; 326 327 llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); 328 329 int N = getNamedOperand(SymbolicName); 330 if (N == -1) { 331 // Verify that an operand with that name exists. 332 DiagOffs = CurPtr-StrStart; 333 return diag::err_asm_unknown_symbolic_operand_name; 334 } 335 Pieces.push_back(AsmStringPiece(N, Modifier)); 336 337 CurPtr = NameEnd+1; 338 continue; 339 } 340 341 DiagOffs = CurPtr-StrStart-1; 342 return diag::err_asm_invalid_escape; 343 } 344} 345 346QualType CXXCatchStmt::getCaughtType() const { 347 if (ExceptionDecl) 348 return ExceptionDecl->getType(); 349 return QualType(); 350} 351 352//===----------------------------------------------------------------------===// 353// Constructors 354//===----------------------------------------------------------------------===// 355 356AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, 357 bool isvolatile, bool msasm, 358 unsigned numoutputs, unsigned numinputs, 359 IdentifierInfo **names, StringLiteral **constraints, 360 Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, 361 StringLiteral **clobbers, SourceLocation rparenloc) 362 : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) 363 , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) 364 , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { 365 366 unsigned NumExprs = NumOutputs +NumInputs; 367 368 Names = new (C) IdentifierInfo*[NumExprs]; 369 std::copy(names, names + NumExprs, Names); 370 371 Exprs = new (C) Stmt*[NumExprs]; 372 std::copy(exprs, exprs + NumExprs, Exprs); 373 374 Constraints = new (C) StringLiteral*[NumExprs]; 375 std::copy(constraints, constraints + NumExprs, Constraints); 376 377 Clobbers = new (C) StringLiteral*[NumClobbers]; 378 std::copy(clobbers, clobbers + NumClobbers, Clobbers); 379} 380 381ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, 382 Stmt *Body, SourceLocation FCL, 383 SourceLocation RPL) 384: Stmt(ObjCForCollectionStmtClass) { 385 SubExprs[ELEM] = Elem; 386 SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect); 387 SubExprs[BODY] = Body; 388 ForLoc = FCL; 389 RParenLoc = RPL; 390} 391 392 393ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, 394 SourceLocation rparenloc, 395 ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, 396 Stmt *atCatchList) 397: Stmt(ObjCAtCatchStmtClass) { 398 ExceptionDecl = catchVarDecl; 399 SubExprs[BODY] = atCatchStmt; 400 SubExprs[NEXT_CATCH] = NULL; 401 // FIXME: O(N^2) in number of catch blocks. 402 if (atCatchList) { 403 ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList); 404 405 while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) 406 AtCatchList = NextCatch; 407 408 AtCatchList->SubExprs[NEXT_CATCH] = this; 409 } 410 AtCatchLoc = atCatchLoc; 411 RParenLoc = rparenloc; 412} 413 414CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, 415 Stmt *tryBlock, Stmt **handlers, 416 unsigned numHandlers) { 417 std::size_t Size = sizeof(CXXTryStmt); 418 Size += ((numHandlers + 1) * sizeof(Stmt)); 419 420 void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); 421 return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); 422} 423 424CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, 425 Stmt **handlers, unsigned numHandlers) 426 : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { 427 Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); 428 Stmts[0] = tryBlock; 429 std::copy(handlers, handlers + NumHandlers, Stmts + 1); 430} 431 432//===----------------------------------------------------------------------===// 433// AST Destruction. 434//===----------------------------------------------------------------------===// 435 436void Stmt::DestroyChildren(ASTContext &C) { 437 for (child_iterator I = child_begin(), E = child_end(); I !=E; ) 438 if (Stmt* Child = *I++) Child->Destroy(C); 439} 440 441static void BranchDestroy(ASTContext &C, Stmt *S, Stmt **SubExprs, 442 unsigned NumExprs) { 443 // We do not use child_iterator here because that will include 444 // the expressions referenced by the condition variable. 445 for (Stmt **I = SubExprs, **E = SubExprs + NumExprs; I != E; ++I) 446 if (Stmt *Child = *I) Child->Destroy(C); 447 448 S->~Stmt(); 449 C.Deallocate((void *) S); 450} 451 452void Stmt::DoDestroy(ASTContext &C) { 453 DestroyChildren(C); 454 this->~Stmt(); 455 C.Deallocate((void *)this); 456} 457 458void CXXCatchStmt::DoDestroy(ASTContext& C) { 459 if (ExceptionDecl) 460 ExceptionDecl->Destroy(C); 461 Stmt::DoDestroy(C); 462} 463 464void DeclStmt::DoDestroy(ASTContext &C) { 465 // Don't use StmtIterator to iterate over the Decls, as that can recurse 466 // into VLA size expressions (which are owned by the VLA). Further, Decls 467 // are owned by the DeclContext, and will be destroyed with them. 468 if (DG.isDeclGroup()) 469 DG.getDeclGroup().Destroy(C); 470} 471 472void IfStmt::DoDestroy(ASTContext &C) { 473 BranchDestroy(C, this, SubExprs, END_EXPR); 474} 475 476void ForStmt::DoDestroy(ASTContext &C) { 477 BranchDestroy(C, this, SubExprs, END_EXPR); 478} 479 480void SwitchStmt::DoDestroy(ASTContext &C) { 481 // Destroy the SwitchCase statements in this switch. In the normal 482 // case, this loop will merely decrement the reference counts from 483 // the Retain() calls in addSwitchCase(); 484 SwitchCase *SC = FirstCase; 485 while (SC) { 486 SwitchCase *Next = SC->getNextSwitchCase(); 487 SC->Destroy(C); 488 SC = Next; 489 } 490 491 BranchDestroy(C, this, SubExprs, END_EXPR); 492} 493 494void WhileStmt::DoDestroy(ASTContext &C) { 495 BranchDestroy(C, this, SubExprs, END_EXPR); 496} 497 498void AsmStmt::DoDestroy(ASTContext &C) { 499 DestroyChildren(C); 500 501 C.Deallocate(Names); 502 C.Deallocate(Constraints); 503 C.Deallocate(Exprs); 504 C.Deallocate(Clobbers); 505 506 this->~AsmStmt(); 507 C.Deallocate((void *)this); 508} 509 510//===----------------------------------------------------------------------===// 511// Child Iterators for iterating over subexpressions/substatements 512//===----------------------------------------------------------------------===// 513 514// DeclStmt 515Stmt::child_iterator DeclStmt::child_begin() { 516 return StmtIterator(DG.begin(), DG.end()); 517} 518 519Stmt::child_iterator DeclStmt::child_end() { 520 return StmtIterator(DG.end(), DG.end()); 521} 522 523// NullStmt 524Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } 525Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } 526 527// CompoundStmt 528Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } 529Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; } 530 531// CaseStmt 532Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } 533Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } 534 535// DefaultStmt 536Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } 537Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } 538 539// LabelStmt 540Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } 541Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } 542 543// IfStmt 544Stmt::child_iterator IfStmt::child_begin() { 545 return child_iterator(Var, &SubExprs[0]); 546} 547Stmt::child_iterator IfStmt::child_end() { 548 return child_iterator(0, &SubExprs[0]+END_EXPR); 549} 550 551// SwitchStmt 552Stmt::child_iterator SwitchStmt::child_begin() { 553 return child_iterator(Var, &SubExprs[0]); 554} 555Stmt::child_iterator SwitchStmt::child_end() { 556 return child_iterator(0, &SubExprs[0]+END_EXPR); 557} 558 559// WhileStmt 560Stmt::child_iterator WhileStmt::child_begin() { 561 return child_iterator(Var, &SubExprs[0]); 562} 563Stmt::child_iterator WhileStmt::child_end() { 564 return child_iterator(0, &SubExprs[0]+END_EXPR); 565} 566 567// DoStmt 568Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } 569Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } 570 571// ForStmt 572Stmt::child_iterator ForStmt::child_begin() { 573 return child_iterator(CondVar, &SubExprs[0]); 574} 575Stmt::child_iterator ForStmt::child_end() { 576 return child_iterator(0, &SubExprs[0]+END_EXPR); 577} 578 579// ObjCForCollectionStmt 580Stmt::child_iterator ObjCForCollectionStmt::child_begin() { 581 return &SubExprs[0]; 582} 583Stmt::child_iterator ObjCForCollectionStmt::child_end() { 584 return &SubExprs[0]+END_EXPR; 585} 586 587// GotoStmt 588Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } 589Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } 590 591// IndirectGotoStmt 592Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); } 593const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); } 594 595Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; } 596Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; } 597 598// ContinueStmt 599Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } 600Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } 601 602// BreakStmt 603Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } 604Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } 605 606// ReturnStmt 607const Expr* ReturnStmt::getRetValue() const { 608 return cast_or_null<Expr>(RetExpr); 609} 610Expr* ReturnStmt::getRetValue() { 611 return cast_or_null<Expr>(RetExpr); 612} 613 614Stmt::child_iterator ReturnStmt::child_begin() { 615 return &RetExpr; 616} 617Stmt::child_iterator ReturnStmt::child_end() { 618 return RetExpr ? &RetExpr+1 : &RetExpr; 619} 620 621// AsmStmt 622Stmt::child_iterator AsmStmt::child_begin() { 623 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0]; 624} 625Stmt::child_iterator AsmStmt::child_end() { 626 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs; 627} 628 629// ObjCAtCatchStmt 630Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } 631Stmt::child_iterator ObjCAtCatchStmt::child_end() { 632 return &SubExprs[0]+END_EXPR; 633} 634 635// ObjCAtFinallyStmt 636Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } 637Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } 638 639// ObjCAtTryStmt 640Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } 641Stmt::child_iterator ObjCAtTryStmt::child_end() { 642 return &SubStmts[0]+END_EXPR; 643} 644 645// ObjCAtThrowStmt 646Stmt::child_iterator ObjCAtThrowStmt::child_begin() { 647 return &Throw; 648} 649 650Stmt::child_iterator ObjCAtThrowStmt::child_end() { 651 return &Throw+1; 652} 653 654// ObjCAtSynchronizedStmt 655Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { 656 return &SubStmts[0]; 657} 658 659Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { 660 return &SubStmts[0]+END_EXPR; 661} 662 663// CXXCatchStmt 664Stmt::child_iterator CXXCatchStmt::child_begin() { 665 return &HandlerBlock; 666} 667 668Stmt::child_iterator CXXCatchStmt::child_end() { 669 return &HandlerBlock + 1; 670} 671 672// CXXTryStmt 673Stmt::child_iterator CXXTryStmt::child_begin() { 674 return reinterpret_cast<Stmt **>(this + 1); 675} 676 677Stmt::child_iterator CXXTryStmt::child_end() { 678 return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1; 679} 680