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