1 //===--- StmtCXX.h - Classes for representing C++ statements ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the C++ statement AST node classes. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_AST_STMTCXX_H 14 #define LLVM_CLANG_AST_STMTCXX_H 15 16 #include "clang/AST/DeclarationName.h" 17 #include "clang/AST/Expr.h" 18 #include "clang/AST/NestedNameSpecifier.h" 19 #include "clang/AST/Stmt.h" 20 #include "llvm/Support/Compiler.h" 21 22 namespace clang { 23 24 class VarDecl; 25 26 /// CXXCatchStmt - This represents a C++ catch block. 27 /// 28 class CXXCatchStmt : public Stmt { 29 SourceLocation CatchLoc; 30 /// The exception-declaration of the type. 31 VarDecl *ExceptionDecl; 32 /// The handler block. 33 Stmt *HandlerBlock; 34 35 public: CXXCatchStmt(SourceLocation catchLoc,VarDecl * exDecl,Stmt * handlerBlock)36 CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) 37 : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), 38 HandlerBlock(handlerBlock) {} 39 CXXCatchStmt(EmptyShell Empty)40 CXXCatchStmt(EmptyShell Empty) 41 : Stmt(CXXCatchStmtClass), ExceptionDecl(nullptr), HandlerBlock(nullptr) {} 42 getBeginLoc()43 SourceLocation getBeginLoc() const LLVM_READONLY { return CatchLoc; } getEndLoc()44 SourceLocation getEndLoc() const LLVM_READONLY { 45 return HandlerBlock->getEndLoc(); 46 } 47 getCatchLoc()48 SourceLocation getCatchLoc() const { return CatchLoc; } getExceptionDecl()49 VarDecl *getExceptionDecl() const { return ExceptionDecl; } 50 QualType getCaughtType() const; getHandlerBlock()51 Stmt *getHandlerBlock() const { return HandlerBlock; } 52 classof(const Stmt * T)53 static bool classof(const Stmt *T) { 54 return T->getStmtClass() == CXXCatchStmtClass; 55 } 56 children()57 child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); } 58 children()59 const_child_range children() const { 60 return const_child_range(&HandlerBlock, &HandlerBlock + 1); 61 } 62 63 friend class ASTStmtReader; 64 }; 65 66 /// CXXTryStmt - A C++ try block, including all handlers. 67 /// 68 class CXXTryStmt final : public Stmt, 69 private llvm::TrailingObjects<CXXTryStmt, Stmt *> { 70 71 friend TrailingObjects; 72 friend class ASTStmtReader; 73 74 SourceLocation TryLoc; 75 unsigned NumHandlers; numTrailingObjects(OverloadToken<Stmt * >)76 size_t numTrailingObjects(OverloadToken<Stmt *>) const { return NumHandlers; } 77 78 CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt*> handlers); CXXTryStmt(EmptyShell Empty,unsigned numHandlers)79 CXXTryStmt(EmptyShell Empty, unsigned numHandlers) 80 : Stmt(CXXTryStmtClass), NumHandlers(numHandlers) { } 81 getStmts()82 Stmt *const *getStmts() const { return getTrailingObjects<Stmt *>(); } getStmts()83 Stmt **getStmts() { return getTrailingObjects<Stmt *>(); } 84 85 public: 86 static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc, 87 Stmt *tryBlock, ArrayRef<Stmt*> handlers); 88 89 static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty, 90 unsigned numHandlers); 91 getBeginLoc()92 SourceLocation getBeginLoc() const LLVM_READONLY { return getTryLoc(); } 93 getTryLoc()94 SourceLocation getTryLoc() const { return TryLoc; } getEndLoc()95 SourceLocation getEndLoc() const { 96 return getStmts()[NumHandlers]->getEndLoc(); 97 } 98 getTryBlock()99 CompoundStmt *getTryBlock() { 100 return cast<CompoundStmt>(getStmts()[0]); 101 } getTryBlock()102 const CompoundStmt *getTryBlock() const { 103 return cast<CompoundStmt>(getStmts()[0]); 104 } 105 getNumHandlers()106 unsigned getNumHandlers() const { return NumHandlers; } getHandler(unsigned i)107 CXXCatchStmt *getHandler(unsigned i) { 108 return cast<CXXCatchStmt>(getStmts()[i + 1]); 109 } getHandler(unsigned i)110 const CXXCatchStmt *getHandler(unsigned i) const { 111 return cast<CXXCatchStmt>(getStmts()[i + 1]); 112 } 113 classof(const Stmt * T)114 static bool classof(const Stmt *T) { 115 return T->getStmtClass() == CXXTryStmtClass; 116 } 117 children()118 child_range children() { 119 return child_range(getStmts(), getStmts() + getNumHandlers() + 1); 120 } 121 children()122 const_child_range children() const { 123 return const_child_range(getStmts(), getStmts() + getNumHandlers() + 1); 124 } 125 }; 126 127 /// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for 128 /// statement, represented as 'for (range-declarator : range-expression)' 129 /// or 'for (init-statement range-declarator : range-expression)'. 130 /// 131 /// This is stored in a partially-desugared form to allow full semantic 132 /// analysis of the constituent components. The original syntactic components 133 /// can be extracted using getLoopVariable and getRangeInit. 134 class CXXForRangeStmt : public Stmt { 135 SourceLocation ForLoc; 136 enum { INIT, RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END }; 137 // SubExprs[RANGE] is an expression or declstmt. 138 // SubExprs[COND] and SubExprs[INC] are expressions. 139 Stmt *SubExprs[END]; 140 SourceLocation CoawaitLoc; 141 SourceLocation ColonLoc; 142 SourceLocation RParenLoc; 143 144 friend class ASTStmtReader; 145 public: 146 CXXForRangeStmt(Stmt *InitStmt, DeclStmt *Range, DeclStmt *Begin, 147 DeclStmt *End, Expr *Cond, Expr *Inc, DeclStmt *LoopVar, 148 Stmt *Body, SourceLocation FL, SourceLocation CAL, 149 SourceLocation CL, SourceLocation RPL); CXXForRangeStmt(EmptyShell Empty)150 CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { } 151 getInit()152 Stmt *getInit() { return SubExprs[INIT]; } 153 VarDecl *getLoopVariable(); 154 Expr *getRangeInit(); 155 getInit()156 const Stmt *getInit() const { return SubExprs[INIT]; } 157 const VarDecl *getLoopVariable() const; 158 const Expr *getRangeInit() const; 159 160 getRangeStmt()161 DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); } getBeginStmt()162 DeclStmt *getBeginStmt() { 163 return cast_or_null<DeclStmt>(SubExprs[BEGINSTMT]); 164 } getEndStmt()165 DeclStmt *getEndStmt() { return cast_or_null<DeclStmt>(SubExprs[ENDSTMT]); } getCond()166 Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); } getInc()167 Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); } getLoopVarStmt()168 DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); } getBody()169 Stmt *getBody() { return SubExprs[BODY]; } 170 getRangeStmt()171 const DeclStmt *getRangeStmt() const { 172 return cast<DeclStmt>(SubExprs[RANGE]); 173 } getBeginStmt()174 const DeclStmt *getBeginStmt() const { 175 return cast_or_null<DeclStmt>(SubExprs[BEGINSTMT]); 176 } getEndStmt()177 const DeclStmt *getEndStmt() const { 178 return cast_or_null<DeclStmt>(SubExprs[ENDSTMT]); 179 } getCond()180 const Expr *getCond() const { 181 return cast_or_null<Expr>(SubExprs[COND]); 182 } getInc()183 const Expr *getInc() const { 184 return cast_or_null<Expr>(SubExprs[INC]); 185 } getLoopVarStmt()186 const DeclStmt *getLoopVarStmt() const { 187 return cast<DeclStmt>(SubExprs[LOOPVAR]); 188 } getBody()189 const Stmt *getBody() const { return SubExprs[BODY]; } 190 setInit(Stmt * S)191 void setInit(Stmt *S) { SubExprs[INIT] = S; } setRangeInit(Expr * E)192 void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); } setRangeStmt(Stmt * S)193 void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; } setBeginStmt(Stmt * S)194 void setBeginStmt(Stmt *S) { SubExprs[BEGINSTMT] = S; } setEndStmt(Stmt * S)195 void setEndStmt(Stmt *S) { SubExprs[ENDSTMT] = S; } setCond(Expr * E)196 void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } setInc(Expr * E)197 void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } setLoopVarStmt(Stmt * S)198 void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; } setBody(Stmt * S)199 void setBody(Stmt *S) { SubExprs[BODY] = S; } 200 getForLoc()201 SourceLocation getForLoc() const { return ForLoc; } getCoawaitLoc()202 SourceLocation getCoawaitLoc() const { return CoawaitLoc; } getColonLoc()203 SourceLocation getColonLoc() const { return ColonLoc; } getRParenLoc()204 SourceLocation getRParenLoc() const { return RParenLoc; } 205 getBeginLoc()206 SourceLocation getBeginLoc() const LLVM_READONLY { return ForLoc; } getEndLoc()207 SourceLocation getEndLoc() const LLVM_READONLY { 208 return SubExprs[BODY]->getEndLoc(); 209 } 210 classof(const Stmt * T)211 static bool classof(const Stmt *T) { 212 return T->getStmtClass() == CXXForRangeStmtClass; 213 } 214 215 // Iterators children()216 child_range children() { 217 return child_range(&SubExprs[0], &SubExprs[END]); 218 } 219 children()220 const_child_range children() const { 221 return const_child_range(&SubExprs[0], &SubExprs[END]); 222 } 223 }; 224 225 /// Representation of a Microsoft __if_exists or __if_not_exists 226 /// statement with a dependent name. 227 /// 228 /// The __if_exists statement can be used to include a sequence of statements 229 /// in the program only when a particular dependent name does not exist. For 230 /// example: 231 /// 232 /// \code 233 /// template<typename T> 234 /// void call_foo(T &t) { 235 /// __if_exists (T::foo) { 236 /// t.foo(); // okay: only called when T::foo exists. 237 /// } 238 /// } 239 /// \endcode 240 /// 241 /// Similarly, the __if_not_exists statement can be used to include the 242 /// statements when a particular name does not exist. 243 /// 244 /// Note that this statement only captures __if_exists and __if_not_exists 245 /// statements whose name is dependent. All non-dependent cases are handled 246 /// directly in the parser, so that they don't introduce a new scope. Clang 247 /// introduces scopes in the dependent case to keep names inside the compound 248 /// statement from leaking out into the surround statements, which would 249 /// compromise the template instantiation model. This behavior differs from 250 /// Visual C++ (which never introduces a scope), but is a fairly reasonable 251 /// approximation of the VC++ behavior. 252 class MSDependentExistsStmt : public Stmt { 253 SourceLocation KeywordLoc; 254 bool IsIfExists; 255 NestedNameSpecifierLoc QualifierLoc; 256 DeclarationNameInfo NameInfo; 257 Stmt *SubStmt; 258 259 friend class ASTReader; 260 friend class ASTStmtReader; 261 262 public: MSDependentExistsStmt(SourceLocation KeywordLoc,bool IsIfExists,NestedNameSpecifierLoc QualifierLoc,DeclarationNameInfo NameInfo,CompoundStmt * SubStmt)263 MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, 264 NestedNameSpecifierLoc QualifierLoc, 265 DeclarationNameInfo NameInfo, 266 CompoundStmt *SubStmt) 267 : Stmt(MSDependentExistsStmtClass), 268 KeywordLoc(KeywordLoc), IsIfExists(IsIfExists), 269 QualifierLoc(QualifierLoc), NameInfo(NameInfo), 270 SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { } 271 272 /// Retrieve the location of the __if_exists or __if_not_exists 273 /// keyword. getKeywordLoc()274 SourceLocation getKeywordLoc() const { return KeywordLoc; } 275 276 /// Determine whether this is an __if_exists statement. isIfExists()277 bool isIfExists() const { return IsIfExists; } 278 279 /// Determine whether this is an __if_exists statement. isIfNotExists()280 bool isIfNotExists() const { return !IsIfExists; } 281 282 /// Retrieve the nested-name-specifier that qualifies this name, if 283 /// any. getQualifierLoc()284 NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } 285 286 /// Retrieve the name of the entity we're testing for, along with 287 /// location information getNameInfo()288 DeclarationNameInfo getNameInfo() const { return NameInfo; } 289 290 /// Retrieve the compound statement that will be included in the 291 /// program only if the existence of the symbol matches the initial keyword. getSubStmt()292 CompoundStmt *getSubStmt() const { 293 return reinterpret_cast<CompoundStmt *>(SubStmt); 294 } 295 getBeginLoc()296 SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; } getEndLoc()297 SourceLocation getEndLoc() const LLVM_READONLY { 298 return SubStmt->getEndLoc(); 299 } 300 children()301 child_range children() { 302 return child_range(&SubStmt, &SubStmt+1); 303 } 304 children()305 const_child_range children() const { 306 return const_child_range(&SubStmt, &SubStmt + 1); 307 } 308 classof(const Stmt * T)309 static bool classof(const Stmt *T) { 310 return T->getStmtClass() == MSDependentExistsStmtClass; 311 } 312 }; 313 314 /// Represents the body of a coroutine. This wraps the normal function 315 /// body and holds the additional semantic context required to set up and tear 316 /// down the coroutine frame. 317 class CoroutineBodyStmt final 318 : public Stmt, 319 private llvm::TrailingObjects<CoroutineBodyStmt, Stmt *> { 320 enum SubStmt { 321 Body, ///< The body of the coroutine. 322 Promise, ///< The promise statement. 323 InitSuspend, ///< The initial suspend statement, run before the body. 324 FinalSuspend, ///< The final suspend statement, run after the body. 325 OnException, ///< Handler for exceptions thrown in the body. 326 OnFallthrough, ///< Handler for control flow falling off the body. 327 Allocate, ///< Coroutine frame memory allocation. 328 Deallocate, ///< Coroutine frame memory deallocation. 329 ReturnValue, ///< Return value for thunk function: p.get_return_object(). 330 ResultDecl, ///< Declaration holding the result of get_return_object. 331 ReturnStmt, ///< Return statement for the thunk function. 332 ReturnStmtOnAllocFailure, ///< Return statement if allocation failed. 333 FirstParamMove ///< First offset for move construction of parameter copies. 334 }; 335 unsigned NumParams; 336 337 friend class ASTStmtReader; 338 friend class ASTReader; 339 friend TrailingObjects; 340 getStoredStmts()341 Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); } 342 getStoredStmts()343 Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); } 344 345 public: 346 347 struct CtorArgs { 348 Stmt *Body = nullptr; 349 Stmt *Promise = nullptr; 350 Expr *InitialSuspend = nullptr; 351 Expr *FinalSuspend = nullptr; 352 Stmt *OnException = nullptr; 353 Stmt *OnFallthrough = nullptr; 354 Expr *Allocate = nullptr; 355 Expr *Deallocate = nullptr; 356 Expr *ReturnValue = nullptr; 357 Stmt *ResultDecl = nullptr; 358 Stmt *ReturnStmt = nullptr; 359 Stmt *ReturnStmtOnAllocFailure = nullptr; 360 ArrayRef<Stmt *> ParamMoves; 361 }; 362 363 private: 364 365 CoroutineBodyStmt(CtorArgs const& Args); 366 367 public: 368 static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args); 369 static CoroutineBodyStmt *Create(const ASTContext &C, EmptyShell, 370 unsigned NumParams); 371 hasDependentPromiseType()372 bool hasDependentPromiseType() const { 373 return getPromiseDecl()->getType()->isDependentType(); 374 } 375 376 /// Retrieve the body of the coroutine as written. This will be either 377 /// a CompoundStmt or a TryStmt. getBody()378 Stmt *getBody() const { 379 return getStoredStmts()[SubStmt::Body]; 380 } 381 getPromiseDeclStmt()382 Stmt *getPromiseDeclStmt() const { 383 return getStoredStmts()[SubStmt::Promise]; 384 } getPromiseDecl()385 VarDecl *getPromiseDecl() const { 386 return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl()); 387 } 388 getInitSuspendStmt()389 Stmt *getInitSuspendStmt() const { 390 return getStoredStmts()[SubStmt::InitSuspend]; 391 } getFinalSuspendStmt()392 Stmt *getFinalSuspendStmt() const { 393 return getStoredStmts()[SubStmt::FinalSuspend]; 394 } 395 getExceptionHandler()396 Stmt *getExceptionHandler() const { 397 return getStoredStmts()[SubStmt::OnException]; 398 } getFallthroughHandler()399 Stmt *getFallthroughHandler() const { 400 return getStoredStmts()[SubStmt::OnFallthrough]; 401 } 402 getAllocate()403 Expr *getAllocate() const { 404 return cast_or_null<Expr>(getStoredStmts()[SubStmt::Allocate]); 405 } getDeallocate()406 Expr *getDeallocate() const { 407 return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]); 408 } getReturnValueInit()409 Expr *getReturnValueInit() const { 410 return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]); 411 } getResultDecl()412 Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; } getReturnStmt()413 Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; } getReturnStmtOnAllocFailure()414 Stmt *getReturnStmtOnAllocFailure() const { 415 return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure]; 416 } getParamMoves()417 ArrayRef<Stmt const *> getParamMoves() const { 418 return {getStoredStmts() + SubStmt::FirstParamMove, NumParams}; 419 } 420 getBeginLoc()421 SourceLocation getBeginLoc() const LLVM_READONLY { 422 return getBody() ? getBody()->getBeginLoc() 423 : getPromiseDecl()->getBeginLoc(); 424 } getEndLoc()425 SourceLocation getEndLoc() const LLVM_READONLY { 426 return getBody() ? getBody()->getEndLoc() : getPromiseDecl()->getEndLoc(); 427 } 428 children()429 child_range children() { 430 return child_range(getStoredStmts(), 431 getStoredStmts() + SubStmt::FirstParamMove + NumParams); 432 } 433 children()434 const_child_range children() const { 435 return const_child_range(getStoredStmts(), getStoredStmts() + 436 SubStmt::FirstParamMove + 437 NumParams); 438 } 439 classof(const Stmt * T)440 static bool classof(const Stmt *T) { 441 return T->getStmtClass() == CoroutineBodyStmtClass; 442 } 443 }; 444 445 /// Represents a 'co_return' statement in the C++ Coroutines TS. 446 /// 447 /// This statament models the initialization of the coroutine promise 448 /// (encapsulating the eventual notional return value) from an expression 449 /// (or braced-init-list), followed by termination of the coroutine. 450 /// 451 /// This initialization is modeled by the evaluation of the operand 452 /// followed by a call to one of: 453 /// <promise>.return_value(<operand>) 454 /// <promise>.return_void() 455 /// which we name the "promise call". 456 class CoreturnStmt : public Stmt { 457 SourceLocation CoreturnLoc; 458 459 enum SubStmt { Operand, PromiseCall, Count }; 460 Stmt *SubStmts[SubStmt::Count]; 461 462 bool IsImplicit : 1; 463 464 friend class ASTStmtReader; 465 public: 466 CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall, 467 bool IsImplicit = false) Stmt(CoreturnStmtClass)468 : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc), 469 IsImplicit(IsImplicit) { 470 SubStmts[SubStmt::Operand] = Operand; 471 SubStmts[SubStmt::PromiseCall] = PromiseCall; 472 } 473 CoreturnStmt(EmptyShell)474 CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {} 475 getKeywordLoc()476 SourceLocation getKeywordLoc() const { return CoreturnLoc; } 477 478 /// Retrieve the operand of the 'co_return' statement. Will be nullptr 479 /// if none was specified. getOperand()480 Expr *getOperand() const { return static_cast<Expr*>(SubStmts[Operand]); } 481 482 /// Retrieve the promise call that results from this 'co_return' 483 /// statement. Will be nullptr if either the coroutine has not yet been 484 /// finalized or the coroutine has no eventual return type. getPromiseCall()485 Expr *getPromiseCall() const { 486 return static_cast<Expr*>(SubStmts[PromiseCall]); 487 } 488 isImplicit()489 bool isImplicit() const { return IsImplicit; } 490 void setIsImplicit(bool value = true) { IsImplicit = value; } 491 getBeginLoc()492 SourceLocation getBeginLoc() const LLVM_READONLY { return CoreturnLoc; } getEndLoc()493 SourceLocation getEndLoc() const LLVM_READONLY { 494 return getOperand() ? getOperand()->getEndLoc() : getBeginLoc(); 495 } 496 children()497 child_range children() { 498 if (!getOperand()) 499 return child_range(SubStmts + SubStmt::PromiseCall, 500 SubStmts + SubStmt::Count); 501 return child_range(SubStmts, SubStmts + SubStmt::Count); 502 } 503 children()504 const_child_range children() const { 505 if (!getOperand()) 506 return const_child_range(SubStmts + SubStmt::PromiseCall, 507 SubStmts + SubStmt::Count); 508 return const_child_range(SubStmts, SubStmts + SubStmt::Count); 509 } 510 classof(const Stmt * T)511 static bool classof(const Stmt *T) { 512 return T->getStmtClass() == CoreturnStmtClass; 513 } 514 }; 515 516 } // end namespace clang 517 518 #endif 519