//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the Statement and Block portions of the Parser // interface. // //===----------------------------------------------------------------------===// #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenACC.h" #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" #include <optional> usingnamespaceclang; //===----------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. //===----------------------------------------------------------------------===// /// Parse a standalone statement (for instance, as the body of an 'if', /// 'while', or 'for'). StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc, ParsedStmtContext StmtCtx) { … } /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. /// StatementOrDeclaration: /// statement /// declaration /// /// statement: /// labeled-statement /// compound-statement /// expression-statement /// selection-statement /// iteration-statement /// jump-statement /// [C++] declaration-statement /// [C++] try-block /// [MS] seh-try-block /// [OBC] objc-throw-statement /// [OBC] objc-try-catch-statement /// [OBC] objc-synchronized-statement /// [GNU] asm-statement /// [OMP] openmp-construct [TODO] /// /// labeled-statement: /// identifier ':' statement /// 'case' constant-expression ':' statement /// 'default' ':' statement /// /// selection-statement: /// if-statement /// switch-statement /// /// iteration-statement: /// while-statement /// do-statement /// for-statement /// /// expression-statement: /// expression[opt] ';' /// /// jump-statement: /// 'goto' identifier ';' /// 'continue' ';' /// 'break' ';' /// 'return' expression[opt] ';' /// [GNU] 'goto' '*' expression ';' /// /// [OBC] objc-throw-statement: /// [OBC] '@' 'throw' expression ';' /// [OBC] '@' 'throw' ';' /// StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc) { … } namespace { class StatementFilterCCC final : public CorrectionCandidateCallback { … }; } StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributes &CXX11Attrs, ParsedAttributes &GNUAttrs) { … } /// Parse an expression statement. StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { … } /// ParseSEHTryBlockCommon /// /// seh-try-block: /// '__try' compound-statement seh-handler /// /// seh-handler: /// seh-except-block /// seh-finally-block /// StmtResult Parser::ParseSEHTryBlock() { … } /// ParseSEHExceptBlock - Handle __except /// /// seh-except-block: /// '__except' '(' seh-filter-expression ')' compound-statement /// StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { … } /// ParseSEHFinallyBlock - Handle __finally /// /// seh-finally-block: /// '__finally' compound-statement /// StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) { … } /// Handle __leave /// /// seh-leave-statement: /// '__leave' ';' /// StmtResult Parser::ParseSEHLeaveStatement() { … } static void DiagnoseLabelFollowedByDecl(Parser &P, const Stmt *SubStmt) { … } /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// label: /// identifier ':' /// [GNU] identifier ':' attributes[opt] /// /// labeled-statement: /// label statement /// StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx) { … } /// ParseCaseStatement /// labeled-statement: /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase, ExprResult Expr) { … } /// ParseDefaultStatement /// labeled-statement: /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { … } StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { … } /// ParseCompoundStatement - Parse a "{}" block. /// /// compound-statement: [C99 6.8.2] /// { block-item-list[opt] } /// [GNU] { label-declarations block-item-list } [TODO] /// /// block-item-list: /// block-item /// block-item-list block-item /// /// block-item: /// declaration /// [GNU] '__extension__' declaration /// statement /// /// [GNU] label-declarations: /// [GNU] label-declaration /// [GNU] label-declarations label-declaration /// /// [GNU] label-declaration: /// [GNU] '__label__' identifier-list ';' /// StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags) { … } /// Parse any pragmas at the start of the compound expression. We handle these /// separately since some pragmas (FP_CONTRACT) must appear before any C /// statement in the compound, but may be intermingled with other pragmas. void Parser::ParseCompoundStatementLeadingPragmas() { … } void Parser::DiagnoseLabelAtEndOfCompoundStatement() { … } /// Consume any extra semi-colons resulting in null statements, /// returning true if any tok::semi were consumed. bool Parser::ConsumeNullStmt(StmtVector &Stmts) { … } StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { … } /// ParseCompoundStatementBody - Parse a sequence of statements optionally /// followed by a label and invoke the ActOnCompoundStmt action. This expects /// the '{' to be the current token, and consume the '}' at the end of the /// block. It does not manipulate the scope stack. StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { … } /// ParseParenExprOrCondition: /// [C ] '(' expression ')' /// [C++] '(' condition ')' /// [C++1z] '(' init-statement[opt] condition ')' /// /// This function parses and performs error recovery on the specified condition /// or expression (depending on whether we're in C++ or C mode). This function /// goes out of its way to recover well. It returns true if there was a parser /// error (the right paren couldn't be found), which indicates that the caller /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. /// Additionally, it will assign the location of the outer-most '(' and ')', /// to LParenLoc and RParenLoc, respectively. bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc, Sema::ConditionKind CK, SourceLocation &LParenLoc, SourceLocation &RParenLoc) { … } namespace { enum MisleadingStatementKind { … }; struct MisleadingIndentationChecker { … }; } /// ParseIfStatement /// if-statement: [C99 6.8.4.1] /// 'if' '(' expression ')' statement /// 'if' '(' expression ')' statement 'else' statement /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// [C++23] 'if' '!' [opt] consteval compound-statement /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement /// StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { … } /// ParseSwitchStatement /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { … } /// ParseWhileStatement /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { … } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. StmtResult Parser::ParseDoStatement() { … } bool Parser::isForRangeIdentifier() { … } /// ParseForStatement /// for-statement: [C99 6.8.5.3] /// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' /// [C++] statement /// [C++0x] 'for' /// 'co_await'[opt] [Coroutines] /// '(' for-range-declaration ':' for-range-initializer ')' /// statement /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration /// [C++23] alias-declaration /// /// [C++0x] for-range-declaration: /// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { … } /// ParseGotoStatement /// jump-statement: /// 'goto' identifier ';' /// [GNU] 'goto' '*' expression ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseGotoStatement() { … } /// ParseContinueStatement /// jump-statement: /// 'continue' ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseContinueStatement() { … } /// ParseBreakStatement /// jump-statement: /// 'break' ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseBreakStatement() { … } /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' /// 'return' braced-init-list ';' /// 'co_return' expression[opt] ';' /// 'co_return' braced-init-list ';' StmtResult Parser::ParseReturnStatement() { … } StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs) { … } Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { … } /// ParseFunctionTryBlock - Parse a C++ function-try-block. /// /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { … } bool Parser::trySkippingFunctionBody() { … } /// ParseCXXTryBlock - Parse a C++ try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// StmtResult Parser::ParseCXXTryBlock() { … } /// ParseCXXTryBlockCommon - Parse the common part of try-block and /// function-try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// /// handler-seq: /// handler handler-seq[opt] /// /// [Borland] try-block: /// 'try' compound-statement seh-except-block /// 'try' compound-statement seh-finally-block /// StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { … } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard /// /// handler: /// 'catch' '(' exception-declaration ')' compound-statement /// /// exception-declaration: /// attribute-specifier-seq[opt] type-specifier-seq declarator /// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt] /// '...' /// StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { … } void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { … }