//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Statement and Block portions of the Parser // interface. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "ExtensionRAIIObject.h" #include "AstGuard.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" using namespace clang; //===----------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. //===----------------------------------------------------------------------===// /// 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 /// [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' ';' /// Parser::OwningStmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { const char *SemiError = 0; OwningStmtResult Res(Actions); // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. tok::TokenKind Kind = Tok.getKind(); SourceLocation AtLoc; switch (Kind) { case tok::at: // May be a @try or @throw statement { AtLoc = ConsumeToken(); // consume @ return ParseObjCAtStatement(AtLoc); } case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement return ParseLabeledStatement(); } // PASS THROUGH. default: if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(); DeclTy *Decl = ParseDeclaration(Declarator::BlockContext); // FIXME: Pass in the right location for the end of the declstmt. return Actions.ActOnDeclStmt(Decl, DeclStart, DeclStart); } else if (Tok.is(tok::r_brace)) { Diag(Tok, diag::err_expected_statement); return StmtError(); } else { // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon. Not // doing this opens us up to the possibility of infinite loops if // ParseExpression does not consume any tokens. SkipUntil(tok::semi); return StmtError(); } // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(move_convert(Expr)); } case tok::kw_case: // C99 6.8.1: labeled-statement return ParseCaseStatement(); case tok::kw_default: // C99 6.8.1: labeled-statement return ParseDefaultStatement(); case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(); case tok::semi: // C99 6.8.3p3: expression[opt] ';' return Actions.ActOnNullStmt(ConsumeToken()); case tok::kw_if: // C99 6.8.4.1: if-statement return ParseIfStatement(); case tok::kw_switch: // C99 6.8.4.2: switch-statement return ParseSwitchStatement(); case tok::kw_while: // C99 6.8.5.1: while-statement return ParseWhileStatement(); case tok::kw_do: // C99 6.8.5.2: do-statement Res = ParseDoStatement(); SemiError = "do/while loop"; break; case tok::kw_for: // C99 6.8.5.3: for-statement return ParseForStatement(); case tok::kw_goto: // C99 6.8.6.1: goto-statement Res = ParseGotoStatement(); SemiError = "goto statement"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement Res = ParseContinueStatement(); SemiError = "continue statement"; break; case tok::kw_break: // C99 6.8.6.3: break-statement Res = ParseBreakStatement(); SemiError = "break statement"; break; case tok::kw_return: // C99 6.8.6.4: return-statement Res = ParseReturnStatement(); SemiError = "return statement"; break; case tok::kw_asm: { bool msAsm = false; Res = ParseAsmStatement(msAsm); if (msAsm) return move(Res); SemiError = "asm statement"; break; } case tok::kw_try: // C++ 15: try-block return ParseCXXTryBlock(); } // If we reached this code, the statement must end in a semicolon. if (Tok.is(tok::semi)) { ConsumeToken(); } else if (!Res.isInvalid()) { Diag(Tok, diag::err_expected_semi_after) << SemiError; // Skip until we see a } or ;, but don't eat it. SkipUntil(tok::r_brace, true, true); } return move(Res); } /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// labeled-statement: /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// Parser::OwningStmtResult Parser::ParseLabeledStatement() { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. assert(Tok.is(tok::colon) && "Not a label!"); // identifier ':' statement SourceLocation ColonLoc = ConsumeToken(); // Read label attributes, if present. DeclTy *AttrList = 0; if (Tok.is(tok::kw___attribute)) // TODO: save these somewhere. AttrList = ParseAttributes(); OwningStmtResult SubStmt(ParseStatement()); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); return Actions.ActOnLabelStmt(IdentTok.getLocation(), IdentTok.getIdentifierInfo(), ColonLoc, move_convert(SubStmt)); } /// ParseCaseStatement /// labeled-statement: /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// /// Note that this does not parse the 'statement' at the end. /// Parser::OwningStmtResult Parser::ParseCaseStatement() { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. OwningExprResult LHS(ParseConstantExpression()); if (LHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); } // GNU case range extension. SourceLocation DotDotDotLoc; OwningExprResult RHS(Actions); if (Tok.is(tok::ellipsis)) { Diag(Tok, diag::ext_gnu_case_range); DotDotDotLoc = ConsumeToken(); RHS = ParseConstantExpression(); if (RHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); } } if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon_after) << "'case'"; SkipUntil(tok::colon); return StmtError(); } SourceLocation ColonLoc = ConsumeToken(); // Diagnose the common error "switch (X) { case 4: }", which is not valid. if (Tok.is(tok::r_brace)) { Diag(Tok, diag::err_label_end_of_compound_statement); return StmtError(); } OwningStmtResult SubStmt(ParseStatement()); // Broken substmt shouldn't prevent the case from being added to the AST. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); return Actions.ActOnCaseStmt(CaseLoc, move_convert(LHS), DotDotDotLoc, move_convert(RHS), ColonLoc, move_convert(SubStmt)); } /// ParseDefaultStatement /// labeled-statement: /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// Parser::OwningStmtResult Parser::ParseDefaultStatement() { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon_after) << "'default'"; SkipUntil(tok::colon); return StmtError(); } SourceLocation ColonLoc = ConsumeToken(); // Diagnose the common error "switch (X) {... default: }", which is not valid. if (Tok.is(tok::r_brace)) { Diag(Tok, diag::err_label_end_of_compound_statement); return StmtError(); } OwningStmtResult SubStmt(ParseStatement()); if (SubStmt.isInvalid()) return StmtError(); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, move_convert(SubStmt), CurScope); } /// 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 /// [OMP] openmp-directive [TODO] /// /// [GNU] label-declarations: /// [GNU] label-declaration /// [GNU] label-declarations label-declaration /// /// [GNU] label-declaration: /// [GNU] '__label__' identifier-list ';' /// /// [OMP] openmp-directive: [TODO] /// [OMP] barrier-directive /// [OMP] flush-directive /// Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound // statements can always hold declarations. ParseScope CompoundScope(this, Scope::DeclScope); // Parse the statements in the body. return ParseCompoundStatementBody(isStmtExpr); } /// ParseCompoundStatementBody - Parse a sequence of statements 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. Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are // only allowed at the start of a compound stmt regardless of the language. typedef StmtVector StmtsTy; StmtsTy Stmts(Actions); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { OwningStmtResult R(Actions); if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(false); } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here // until we can determine which is which. SourceLocation ExtLoc = ConsumeToken(); while (Tok.is(tok::kw___extension__)) ConsumeToken(); // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { // FIXME: Save the __extension__ on the decl as a node somehow. SourceLocation DeclStart = Tok.getLocation(); DeclTy *Res = ParseDeclaration(Declarator::BlockContext); // FIXME: Pass in the right location for the end of the declstmt. R = Actions.ActOnDeclStmt(Res, DeclStart, DeclStart); } else { // Otherwise this was a unary __extension__ marker. Parse the // subexpression and add the __extension__ unary op. OwningExprResult Res(ParseCastExpression(false)); if (Res.isInvalid()) { SkipUntil(tok::semi); continue; } // Add the __extension__ node to the AST. Res = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__, Res.release()); if (Res.isInvalid()) continue; // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); R = Actions.ActOnExprStmt(move_convert(Res)); } } if (R.isUsable()) Stmts.push_back(R.release()); } // We broke out of the while loop because we found a '}' or EOF. if (Tok.isNot(tok::r_brace)) { Diag(Tok, diag::err_expected_rbrace); return StmtError(); } SourceLocation RBraceLoc = ConsumeBrace(); return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, move_convert(Stmts), isStmtExpr); } /// ParseParenExprOrCondition: /// [C ] '(' expression ')' /// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true] /// /// 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. bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, bool OnlyAllowCondition) { SourceLocation LParenLoc = ConsumeParen(); if (getLang().CPlusPlus) CondExp = ParseCXXCondition(); else CondExp = ParseExpression(); // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. if (Tok.isNot(tok::r_paren)) return true; } // Otherwise the condition is valid or the rparen is present. MatchRHSPunctuation(tok::r_paren, LParenLoc); return false; } /// 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 /// Parser::OwningStmtResult Parser::ParseIfStatement() { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "if"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLang().C99 || getLang().CPlusPlus; // C99 6.8.4p3 - In C99, the if statement is a block. This is not // the case for C90. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX); // Parse the condition. OwningExprResult CondExp(Actions); if (ParseParenExprOrCondition(CondExp)) return StmtError(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // // For C++ we create a scope for the condition and a new scope for // substatements because: // -When the 'then' scope exits, we want the condition declaration to still be // active for the 'else' scope too. // -Sema will detect name clashes by considering declarations of a // 'ControlScope' as part of its direct subscope. // -If we wanted the condition and substatement to be in the same scope, we // would have to notify ParseStatement not to create a new scope. It's // simpler to let it create a new scope. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); OwningStmtResult ThenStmt(ParseStatement()); // Pop the 'if' scope if needed. InnerScope.Exit(); // If it has an else, parse it. SourceLocation ElseLoc; SourceLocation ElseStmtLoc; OwningStmtResult ElseStmt(Actions); if (Tok.is(tok::kw_else)) { ElseLoc = ConsumeToken(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do // this if the body isn't a compound statement to avoid push/pop in common // cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); bool WithinElse = CurScope->isWithinElse(); CurScope->setWithinElse(true); ElseStmtLoc = Tok.getLocation(); ElseStmt = ParseStatement(); CurScope->setWithinElse(WithinElse); // Pop the 'else' scope if needed. InnerScope.Exit(); } IfScope.Exit(); // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. if (CondExp.isInvalid()) return StmtError(); // If the then or else stmt is invalid and the other is valid (and present), // make turn the invalid one into a null stmt to avoid dropping the other // part. If both are invalid, return error. if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) || (ThenStmt.isInvalid() && ElseStmt.get() == 0) || (ThenStmt.get() == 0 && ElseStmt.isInvalid())) { // Both invalid, or one is invalid and other is non-present: return error. return StmtError(); } // Now if either are invalid, replace with a ';'. if (ThenStmt.isInvalid()) ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); return Actions.ActOnIfStmt(IfLoc, move_convert(CondExp), move_convert(ThenStmt), ElseLoc, move_convert(ElseStmt)); } /// ParseSwitchStatement /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement Parser::OwningStmtResult Parser::ParseSwitchStatement() { assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "switch"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLang().C99 || getLang().CPlusPlus; // C99 6.8.4p3 - In C99, the switch statement is a block. This is // not the case for C90. Start the switch scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // unsigned ScopeFlags = Scope::BreakScope; if (C99orCXX) ScopeFlags |= Scope::DeclScope | Scope::ControlScope; ParseScope SwitchScope(this, ScopeFlags); // Parse the condition. OwningExprResult Cond(Actions); if (ParseParenExprOrCondition(Cond)) return StmtError(); OwningStmtResult Switch(Actions); if (!Cond.isInvalid()) Switch = Actions.ActOnStartOfSwitchStmt(move_convert(Cond)); // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // // See comments in ParseIfStatement for why we create a scope for the // condition and a new scope for substatement in C++. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. OwningStmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); if (Body.isInvalid()) { Body = Actions.ActOnNullStmt(Tok.getLocation()); // FIXME: Remove the case statement list from the Switch statement. } SwitchScope.Exit(); if (Cond.isInvalid()) return StmtError(); return Actions.ActOnFinishSwitchStmt(SwitchLoc, move_convert(Switch), move_convert(Body)); } /// ParseWhileStatement /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement Parser::OwningStmtResult Parser::ParseWhileStatement() { assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "while"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLang().C99 || getLang().CPlusPlus; // C99 6.8.5p5 - In C99, the while statement is a block. This is not // the case for C90. Start the loop scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // unsigned ScopeFlags; if (C99orCXX) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope | Scope::ControlScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; ParseScope WhileScope(this, ScopeFlags); // Parse the condition. OwningExprResult Cond(Actions); if (ParseParenExprOrCondition(Cond)) return StmtError(); // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // // See comments in ParseIfStatement for why we create a scope for the // condition and a new scope for substatement in C++. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. OwningStmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); WhileScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); return Actions.ActOnWhileStmt(WhileLoc, move_convert(Cond), move_convert(Body)); } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. Parser::OwningStmtResult Parser::ParseDoStatement() { assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. // C99 6.8.5p5 - In C99, the do statement is a block. This is not // the case for C90. Start the loop scope. unsigned ScopeFlags; if (getLang().C99) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; ParseScope DoScope(this, ScopeFlags); // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // ParseScope InnerScope(this, Scope::DeclScope, (getLang().C99 || getLang().CPlusPlus) && Tok.isNot(tok::l_brace)); // Read the body statement. OwningStmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); if (Tok.isNot(tok::kw_while)) { if (!Body.isInvalid()) { Diag(Tok, diag::err_expected_while); Diag(DoLoc, diag::note_matching) << "do"; SkipUntil(tok::semi, false, true); } return StmtError(); } SourceLocation WhileLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "do/while"; SkipUntil(tok::semi, false, true); return StmtError(); } // Parse the parenthesized condition. OwningExprResult Cond(Actions); ParseParenExprOrCondition(Cond, true); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); return Actions.ActOnDoStmt(DoLoc, move_convert(Body), WhileLoc, move_convert(Cond)); } /// 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 /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration /// Parser::OwningStmtResult Parser::ParseForStatement() { assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "for"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLang().C99 || getLang().CPlusPlus; // C99 6.8.5p5 - In C99, the for statement is a block. This is not // the case for C90. Start the loop scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // C++ 6.5.3p1: // Names declared in the for-init-statement are in the same declarative-region // as those declared in the condition. // unsigned ScopeFlags; if (C99orCXX) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope | Scope::ControlScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; ParseScope ForScope(this, ScopeFlags); SourceLocation LParenLoc = ConsumeParen(); OwningExprResult Value(Actions); bool ForEach = false; OwningStmtResult FirstPart(Actions); OwningExprResult SecondPart(Actions), ThirdPart(Actions); // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. ConsumeToken(); } else if (isSimpleDeclaration()) { // for (int X = 4; // Parse declaration, which eats the ';'. if (!C99orCXX) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); SourceLocation DeclStart = Tok.getLocation(); DeclTy *aBlockVarDecl = ParseSimpleDeclaration(Declarator::ForContext); // FIXME: Pass in the right location for the end of the declstmt. FirstPart = Actions.ActOnDeclStmt(aBlockVarDecl, DeclStart, DeclStart); if ((ForEach = isTokIdentifier_in())) { ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); } } else { Value = ParseExpression(); // Turn the expression into a stmt. if (!Value.isInvalid()) FirstPart = Actions.ActOnExprStmt(move_convert(Value)); if (Tok.is(tok::semi)) { ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); } else { if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } } if (!ForEach) { assert(!SecondPart.get() && "Shouldn't have a second expression yet."); // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. } else { SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression(); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } // Parse the third part of the for specifier. if (Tok.is(tok::r_paren)) { // for (...;...;) // no third part. } else { ThirdPart = ParseExpression(); } } // Match the ')'. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // // See comments in ParseIfStatement for why we create a scope for // for-init-statement/condition and a new scope for substatement in C++. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. OwningStmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); // Leave the for-scope. ForScope.Exit(); if (Body.isInvalid()) return StmtError(); if (!ForEach) return Actions.ActOnForStmt(ForLoc, LParenLoc, move_convert(FirstPart), move_convert(SecondPart), move_convert(ThirdPart), RParenLoc, move_convert(Body)); else return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move_convert(FirstPart), move_convert(SecondPart), RParenLoc, move_convert(Body)); } /// ParseGotoStatement /// jump-statement: /// 'goto' identifier ';' /// [GNU] 'goto' '*' expression ';' /// /// Note: this lets the caller parse the end ';'. /// Parser::OwningStmtResult Parser::ParseGotoStatement() { assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. OwningStmtResult Res(Actions); if (Tok.is(tok::identifier)) { Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), Tok.getIdentifierInfo()); ConsumeToken(); } else if (Tok.is(tok::star) && !getLang().NoExtensions) { // GNU indirect goto extension. Diag(Tok, diag::ext_gnu_indirect_goto); SourceLocation StarLoc = ConsumeToken(); OwningExprResult R(ParseExpression()); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. SkipUntil(tok::semi, false, true); return StmtError(); } Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, move_convert(R)); } else { Diag(Tok, diag::err_expected_ident); return StmtError(); } return move(Res); } /// ParseContinueStatement /// jump-statement: /// 'continue' ';' /// /// Note: this lets the caller parse the end ';'. /// Parser::OwningStmtResult Parser::ParseContinueStatement() { SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, CurScope); } /// ParseBreakStatement /// jump-statement: /// 'break' ';' /// /// Note: this lets the caller parse the end ';'. /// Parser::OwningStmtResult Parser::ParseBreakStatement() { SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, CurScope); } /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' Parser::OwningStmtResult Parser::ParseReturnStatement() { assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. OwningExprResult R(Actions); if (Tok.isNot(tok::semi)) { R = ParseExpression(); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. SkipUntil(tok::semi, false, true); return StmtError(); } } return Actions.ActOnReturnStmt(ReturnLoc, move_convert(R)); } /// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this /// routine is called to skip/ignore tokens that comprise the MS asm statement. Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { if (Tok.is(tok::l_brace)) { unsigned short savedBraceCount = BraceCount; do { ConsumeAnyToken(); } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); } else { // From the MS website: If used without braces, the __asm keyword means // that the rest of the line is an assembly-language statement. SourceManager &SrcMgr = PP.getSourceManager(); SourceLocation TokLoc = Tok.getLocation(); unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc); do { ConsumeAnyToken(); TokLoc = Tok.getLocation(); } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) && Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && Tok.isNot(tok::eof)); } return Actions.ActOnNullStmt(Tok.getLocation()); } /// ParseAsmStatement - Parse a GNU extended asm statement. /// asm-statement: /// gnu-asm-statement /// ms-asm-statement /// /// [GNU] gnu-asm-statement: /// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' /// /// [GNU] asm-argument: /// asm-string-literal /// asm-string-literal ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// ':' asm-clobbers /// /// [GNU] asm-clobbers: /// asm-string-literal /// asm-clobbers ',' asm-string-literal /// /// [MS] ms-asm-statement: /// '__asm' assembly-instruction ';'[opt] /// '__asm' '{' assembly-instruction-list '}' ';'[opt] /// /// [MS] assembly-instruction-list: /// assembly-instruction ';'[opt] /// assembly-instruction-list ';' assembly-instruction ';'[opt] /// Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { msAsm = true; return FuzzyParseMicrosoftAsmStatement(); } DeclSpec DS; SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS); // GNU asms accept, but warn, about type-qualifiers other than volatile. if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; bool isSimple = false; if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; SkipUntil(tok::r_paren); return StmtError(); } Loc = ConsumeParen(); OwningExprResult AsmString(ParseAsmStringLiteral()); if (AsmString.isInvalid()) return StmtError(); llvm::SmallVector Names; ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); unsigned NumInputs = 0, NumOutputs = 0; SourceLocation RParenLoc; if (Tok.is(tok::r_paren)) { // We have a simple asm expression isSimple = true; RParenLoc = ConsumeParen(); } else { // Parse Outputs, if present. if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); NumOutputs = Names.size(); // Parse Inputs, if present. if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); assert(Names.size() == Constraints.size() && Constraints.size() == Exprs.size() && "Input operand size mismatch!"); NumInputs = Names.size() - NumOutputs; // Parse the clobbers, if present. if (Tok.is(tok::colon)) { ConsumeToken(); // Parse the asm-string list for clobbers. while (1) { OwningExprResult Clobber(ParseAsmStringLiteral()); if (Clobber.isInvalid()) break; Clobbers.push_back(Clobber.release()); if (Tok.isNot(tok::comma)) break; ConsumeToken(); } } RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); } return Owned(Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile, NumOutputs, NumInputs, &Names[0], Constraints.take(), Exprs.take(), AsmString.release(), Clobbers.size(), Clobbers.take(), RParenLoc)); } /// ParseAsmOperands - Parse the asm-operands production as used by /// asm-statement. We also parse a leading ':' token. If the leading colon is /// not present, we do not parse anything. /// /// [GNU] asm-operands: /// asm-operand /// asm-operands ',' asm-operand /// /// [GNU] asm-operand: /// asm-string-literal '(' expression ')' /// '[' identifier ']' asm-string-literal '(' expression ')' /// bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, llvm::SmallVectorImpl &Constraints, llvm::SmallVectorImpl &Exprs) { // Only do anything if this operand is present. if (Tok.isNot(tok::colon)) return false; ConsumeToken(); // 'asm-operands' isn't present? if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; while (1) { // Read the [id] if present. if (Tok.is(tok::l_square)) { SourceLocation Loc = ConsumeBracket(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return true; } IdentifierInfo *II = Tok.getIdentifierInfo(); ConsumeToken(); Names.push_back(std::string(II->getName(), II->getLength())); MatchRHSPunctuation(tok::r_square, Loc); } else Names.push_back(std::string()); OwningExprResult Constraint(ParseAsmStringLiteral()); if (Constraint.isInvalid()) { SkipUntil(tok::r_paren); return true; } Constraints.push_back(Constraint.release()); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; SkipUntil(tok::r_paren); return true; } // Read the parenthesized expression. OwningExprResult Res(ParseSimpleParenExpression()); if (Res.isInvalid()) { SkipUntil(tok::r_paren); return true; } Exprs.push_back(Res.release()); // Eat the comma and continue parsing if it exists. if (Tok.isNot(tok::comma)) return false; ConsumeToken(); } return true; } Parser::DeclTy *Parser::ParseFunctionStatementBody(DeclTy *Decl, SourceLocation L, SourceLocation R) { // Do not enter a scope for the brace, as the arguments are in the same scope // (the function body) as the body itself. Instead, just read the statement // list and put it into a CompoundStmt for safe keeping. OwningStmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) FnBody = Actions.ActOnCompoundStmt(L, R, MultiStmtArg(Actions), false); return Actions.ActOnFinishFunctionBody(Decl, move_convert(FnBody)); } /// ParseCXXTryBlock - Parse a C++ try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// /// handler-seq: /// handler handler-seq[opt] /// Parser::OwningStmtResult Parser::ParseCXXTryBlock() { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); OwningStmtResult TryBlock(ParseCompoundStatement()); if (TryBlock.isInvalid()) return move(TryBlock); StmtVector Handlers(Actions); if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { OwningStmtResult Handler(ParseCXXCatchBlock()); if (!Handler.isInvalid()) Handlers.push_back(Handler.release()); } // Don't bother creating the full statement if we don't have any usable // handlers. if (Handlers.empty()) return StmtError(); return Actions.ActOnCXXTryBlock(TryLoc, move_convert(TryBlock), move_convert(Handlers)); } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard /// /// handler: /// 'catch' '(' exception-declaration ')' compound-statement /// /// exception-declaration: /// type-specifier-seq declarator /// type-specifier-seq abstract-declarator /// type-specifier-seq /// '...' /// Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); SourceLocation CatchLoc = ConsumeToken(); SourceLocation LParenLoc = Tok.getLocation(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) return StmtError(); // C++ 3.3.2p3: // The name in a catch exception-declaration is local to the handler and // shall not be redeclared in the outermost block of the handler. ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope); // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. DeclTy *ExceptionDecl = 0; if (Tok.isNot(tok::ellipsis)) { DeclSpec DS; if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); Declarator ExDecl(DS, Declarator::CXXCatchContext); ParseDeclarator(ExDecl); ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl); } else ConsumeToken(); if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) return StmtError(); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); OwningStmtResult Block(ParseCompoundStatement()); if (Block.isInvalid()) return move(Block); return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, move_convert(Block)); }