Stmt.cpp revision 203955
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 if (CurChar == '$') { 253 CurStringPiece += "$$"; 254 continue; 255 } else if (CurChar != '%') { 256 CurStringPiece += CurChar; 257 continue; 258 } 259 260 // Escaped "%" character in asm string. 261 if (CurPtr == StrEnd) { 262 // % at end of string is invalid (no escape). 263 DiagOffs = CurPtr-StrStart-1; 264 return diag::err_asm_invalid_escape; 265 } 266 267 char EscapedChar = *CurPtr++; 268 if (EscapedChar == '%') { // %% -> % 269 // Escaped percentage sign. 270 CurStringPiece += '%'; 271 continue; 272 } 273 274 if (EscapedChar == '=') { // %= -> Generate an unique ID. 275 CurStringPiece += "${:uid}"; 276 continue; 277 } 278 279 // Otherwise, we have an operand. If we have accumulated a string so far, 280 // add it to the Pieces list. 281 if (!CurStringPiece.empty()) { 282 Pieces.push_back(AsmStringPiece(CurStringPiece)); 283 CurStringPiece.clear(); 284 } 285 286 // Handle %x4 and %x[foo] by capturing x as the modifier character. 287 char Modifier = '\0'; 288 if (isalpha(EscapedChar)) { 289 Modifier = EscapedChar; 290 EscapedChar = *CurPtr++; 291 } 292 293 if (isdigit(EscapedChar)) { 294 // %n - Assembler operand n 295 unsigned N = 0; 296 297 --CurPtr; 298 while (CurPtr != StrEnd && isdigit(*CurPtr)) 299 N = N*10 + ((*CurPtr++)-'0'); 300 301 unsigned NumOperands = 302 getNumOutputs() + getNumPlusOperands() + getNumInputs(); 303 if (N >= NumOperands) { 304 DiagOffs = CurPtr-StrStart-1; 305 return diag::err_asm_invalid_operand_number; 306 } 307 308 Pieces.push_back(AsmStringPiece(N, Modifier)); 309 continue; 310 } 311 312 // Handle %[foo], a symbolic operand reference. 313 if (EscapedChar == '[') { 314 DiagOffs = CurPtr-StrStart-1; 315 316 // Find the ']'. 317 const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); 318 if (NameEnd == 0) 319 return diag::err_asm_unterminated_symbolic_operand_name; 320 if (NameEnd == CurPtr) 321 return diag::err_asm_empty_symbolic_operand_name; 322 323 llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); 324 325 int N = getNamedOperand(SymbolicName); 326 if (N == -1) { 327 // Verify that an operand with that name exists. 328 DiagOffs = CurPtr-StrStart; 329 return diag::err_asm_unknown_symbolic_operand_name; 330 } 331 Pieces.push_back(AsmStringPiece(N, Modifier)); 332 333 CurPtr = NameEnd+1; 334 continue; 335 } 336 337 DiagOffs = CurPtr-StrStart-1; 338 return diag::err_asm_invalid_escape; 339 } 340} 341 342QualType CXXCatchStmt::getCaughtType() const { 343 if (ExceptionDecl) 344 return ExceptionDecl->getType(); 345 return QualType(); 346} 347 348//===----------------------------------------------------------------------===// 349// Constructors 350//===----------------------------------------------------------------------===// 351 352AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, 353 bool isvolatile, bool msasm, 354 unsigned numoutputs, unsigned numinputs, 355 IdentifierInfo **names, StringLiteral **constraints, 356 Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, 357 StringLiteral **clobbers, SourceLocation rparenloc) 358 : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) 359 , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) 360 , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { 361 362 unsigned NumExprs = NumOutputs +NumInputs; 363 364 Names = new (C) IdentifierInfo*[NumExprs]; 365 std::copy(names, names + NumExprs, Names); 366 367 Exprs = new (C) Stmt*[NumExprs]; 368 std::copy(exprs, exprs + NumExprs, Exprs); 369 370 Constraints = new (C) StringLiteral*[NumExprs]; 371 std::copy(constraints, constraints + NumExprs, Constraints); 372 373 Clobbers = new (C) StringLiteral*[NumClobbers]; 374 std::copy(clobbers, clobbers + NumClobbers, Clobbers); 375} 376 377ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, 378 Stmt *Body, SourceLocation FCL, 379 SourceLocation RPL) 380: Stmt(ObjCForCollectionStmtClass) { 381 SubExprs[ELEM] = Elem; 382 SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect); 383 SubExprs[BODY] = Body; 384 ForLoc = FCL; 385 RParenLoc = RPL; 386} 387 388 389ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, 390 SourceLocation rparenloc, 391 ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, 392 Stmt *atCatchList) 393: Stmt(ObjCAtCatchStmtClass) { 394 ExceptionDecl = catchVarDecl; 395 SubExprs[BODY] = atCatchStmt; 396 SubExprs[NEXT_CATCH] = NULL; 397 // FIXME: O(N^2) in number of catch blocks. 398 if (atCatchList) { 399 ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList); 400 401 while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) 402 AtCatchList = NextCatch; 403 404 AtCatchList->SubExprs[NEXT_CATCH] = this; 405 } 406 AtCatchLoc = atCatchLoc; 407 RParenLoc = rparenloc; 408} 409 410CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, 411 Stmt *tryBlock, Stmt **handlers, 412 unsigned numHandlers) { 413 std::size_t Size = sizeof(CXXTryStmt); 414 Size += ((numHandlers + 1) * sizeof(Stmt)); 415 416 void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); 417 return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); 418} 419 420CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, 421 Stmt **handlers, unsigned numHandlers) 422 : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { 423 Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); 424 Stmts[0] = tryBlock; 425 std::copy(handlers, handlers + NumHandlers, Stmts + 1); 426} 427 428//===----------------------------------------------------------------------===// 429// AST Destruction. 430//===----------------------------------------------------------------------===// 431 432void Stmt::DestroyChildren(ASTContext &C) { 433 for (child_iterator I = child_begin(), E = child_end(); I !=E; ) 434 if (Stmt* Child = *I++) Child->Destroy(C); 435} 436 437static void BranchDestroy(ASTContext &C, Stmt *S, Stmt **SubExprs, 438 unsigned NumExprs) { 439 // We do not use child_iterator here because that will include 440 // the expressions referenced by the condition variable. 441 for (Stmt **I = SubExprs, **E = SubExprs + NumExprs; I != E; ++I) 442 if (Stmt *Child = *I) Child->Destroy(C); 443 444 S->~Stmt(); 445 C.Deallocate((void *) S); 446} 447 448void Stmt::DoDestroy(ASTContext &C) { 449 DestroyChildren(C); 450 this->~Stmt(); 451 C.Deallocate((void *)this); 452} 453 454void CXXCatchStmt::DoDestroy(ASTContext& C) { 455 if (ExceptionDecl) 456 ExceptionDecl->Destroy(C); 457 Stmt::DoDestroy(C); 458} 459 460void DeclStmt::DoDestroy(ASTContext &C) { 461 // Don't use StmtIterator to iterate over the Decls, as that can recurse 462 // into VLA size expressions (which are owned by the VLA). Further, Decls 463 // are owned by the DeclContext, and will be destroyed with them. 464 if (DG.isDeclGroup()) 465 DG.getDeclGroup().Destroy(C); 466} 467 468void IfStmt::DoDestroy(ASTContext &C) { 469 BranchDestroy(C, this, SubExprs, END_EXPR); 470} 471 472void ForStmt::DoDestroy(ASTContext &C) { 473 BranchDestroy(C, this, SubExprs, END_EXPR); 474} 475 476void SwitchStmt::DoDestroy(ASTContext &C) { 477 // Destroy the SwitchCase statements in this switch. In the normal 478 // case, this loop will merely decrement the reference counts from 479 // the Retain() calls in addSwitchCase(); 480 SwitchCase *SC = FirstCase; 481 while (SC) { 482 SwitchCase *Next = SC->getNextSwitchCase(); 483 SC->Destroy(C); 484 SC = Next; 485 } 486 487 BranchDestroy(C, this, SubExprs, END_EXPR); 488} 489 490void WhileStmt::DoDestroy(ASTContext &C) { 491 BranchDestroy(C, this, SubExprs, END_EXPR); 492} 493 494void AsmStmt::DoDestroy(ASTContext &C) { 495 DestroyChildren(C); 496 497 C.Deallocate(Names); 498 C.Deallocate(Constraints); 499 C.Deallocate(Exprs); 500 C.Deallocate(Clobbers); 501 502 this->~AsmStmt(); 503 C.Deallocate((void *)this); 504} 505 506//===----------------------------------------------------------------------===// 507// Child Iterators for iterating over subexpressions/substatements 508//===----------------------------------------------------------------------===// 509 510// DeclStmt 511Stmt::child_iterator DeclStmt::child_begin() { 512 return StmtIterator(DG.begin(), DG.end()); 513} 514 515Stmt::child_iterator DeclStmt::child_end() { 516 return StmtIterator(DG.end(), DG.end()); 517} 518 519// NullStmt 520Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } 521Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } 522 523// CompoundStmt 524Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } 525Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; } 526 527// CaseStmt 528Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } 529Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } 530 531// DefaultStmt 532Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } 533Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } 534 535// LabelStmt 536Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } 537Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } 538 539// IfStmt 540Stmt::child_iterator IfStmt::child_begin() { 541 return child_iterator(Var, &SubExprs[0]); 542} 543Stmt::child_iterator IfStmt::child_end() { 544 return child_iterator(0, &SubExprs[0]+END_EXPR); 545} 546 547// SwitchStmt 548Stmt::child_iterator SwitchStmt::child_begin() { 549 return child_iterator(Var, &SubExprs[0]); 550} 551Stmt::child_iterator SwitchStmt::child_end() { 552 return child_iterator(0, &SubExprs[0]+END_EXPR); 553} 554 555// WhileStmt 556Stmt::child_iterator WhileStmt::child_begin() { 557 return child_iterator(Var, &SubExprs[0]); 558} 559Stmt::child_iterator WhileStmt::child_end() { 560 return child_iterator(0, &SubExprs[0]+END_EXPR); 561} 562 563// DoStmt 564Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } 565Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } 566 567// ForStmt 568Stmt::child_iterator ForStmt::child_begin() { 569 return child_iterator(CondVar, &SubExprs[0]); 570} 571Stmt::child_iterator ForStmt::child_end() { 572 return child_iterator(0, &SubExprs[0]+END_EXPR); 573} 574 575// ObjCForCollectionStmt 576Stmt::child_iterator ObjCForCollectionStmt::child_begin() { 577 return &SubExprs[0]; 578} 579Stmt::child_iterator ObjCForCollectionStmt::child_end() { 580 return &SubExprs[0]+END_EXPR; 581} 582 583// GotoStmt 584Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } 585Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } 586 587// IndirectGotoStmt 588Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); } 589const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); } 590 591Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; } 592Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; } 593 594// ContinueStmt 595Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } 596Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } 597 598// BreakStmt 599Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } 600Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } 601 602// ReturnStmt 603const Expr* ReturnStmt::getRetValue() const { 604 return cast_or_null<Expr>(RetExpr); 605} 606Expr* ReturnStmt::getRetValue() { 607 return cast_or_null<Expr>(RetExpr); 608} 609 610Stmt::child_iterator ReturnStmt::child_begin() { 611 return &RetExpr; 612} 613Stmt::child_iterator ReturnStmt::child_end() { 614 return RetExpr ? &RetExpr+1 : &RetExpr; 615} 616 617// AsmStmt 618Stmt::child_iterator AsmStmt::child_begin() { 619 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0]; 620} 621Stmt::child_iterator AsmStmt::child_end() { 622 return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs; 623} 624 625// ObjCAtCatchStmt 626Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } 627Stmt::child_iterator ObjCAtCatchStmt::child_end() { 628 return &SubExprs[0]+END_EXPR; 629} 630 631// ObjCAtFinallyStmt 632Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } 633Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } 634 635// ObjCAtTryStmt 636Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } 637Stmt::child_iterator ObjCAtTryStmt::child_end() { 638 return &SubStmts[0]+END_EXPR; 639} 640 641// ObjCAtThrowStmt 642Stmt::child_iterator ObjCAtThrowStmt::child_begin() { 643 return &Throw; 644} 645 646Stmt::child_iterator ObjCAtThrowStmt::child_end() { 647 return &Throw+1; 648} 649 650// ObjCAtSynchronizedStmt 651Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { 652 return &SubStmts[0]; 653} 654 655Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { 656 return &SubStmts[0]+END_EXPR; 657} 658 659// CXXCatchStmt 660Stmt::child_iterator CXXCatchStmt::child_begin() { 661 return &HandlerBlock; 662} 663 664Stmt::child_iterator CXXCatchStmt::child_end() { 665 return &HandlerBlock + 1; 666} 667 668// CXXTryStmt 669Stmt::child_iterator CXXTryStmt::child_begin() { 670 return reinterpret_cast<Stmt **>(this + 1); 671} 672 673Stmt::child_iterator CXXTryStmt::child_end() { 674 return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1; 675} 676