llvm-project/clang/lib/Parse/ParseStmt.cpp
John McCall faf5fb4b78 One who seeks knowledge learns something new every day.
One who seeks the Tao unlearns something new every day.
Less and less remains until you arrive at non-action.
When you arrive at non-action,
nothing will be left undone.

llvm-svn: 112244
2010-08-26 23:41:50 +00:00

1622 lines
54 KiB
C++

//===--- 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 "RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.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' ';'
///
StmtResult
Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
const char *SemiError = 0;
StmtResult Res;
ParenBraceBracketBalancer BalancerRAIIObj(*this);
CXX0XAttributeList Attr;
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
Attr = ParseCXX0XAttributes();
llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList);
// 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::code_completion:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
ConsumeCodeCompletionToken();
return ParseStatementOrDeclaration(OnlyStatement);
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
return ParseLabeledStatement(AttrList.take());
}
// PASS THROUGH.
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership.
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
Attr);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::err_expected_statement);
return StmtError();
}
// FIXME: Use the attributes
// expression[opt] ';'
ExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
// If the expression is invalid, skip ahead to the next semicolon or '}'.
// Not doing this opens us up to the possibility of infinite loops if
// ParseExpression does not consume any tokens.
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
}
// Otherwise, eat the semicolon.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
}
case tok::kw_case: // C99 6.8.1: labeled-statement
return ParseCaseStatement(AttrList.take());
case tok::kw_default: // C99 6.8.1: labeled-statement
return ParseDefaultStatement(AttrList.take());
case tok::l_brace: // C99 6.8.2: compound-statement
return ParseCompoundStatement(AttrList.take());
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(AttrList.take());
case tok::kw_switch: // C99 6.8.4.2: switch-statement
return ParseSwitchStatement(AttrList.take());
case tok::kw_while: // C99 6.8.5.1: while-statement
return ParseWhileStatement(AttrList.take());
case tok::kw_do: // C99 6.8.5.2: do-statement
Res = ParseDoStatement(AttrList.take());
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
return ParseForStatement(AttrList.take());
case tok::kw_goto: // C99 6.8.6.1: goto-statement
Res = ParseGotoStatement(AttrList.take());
SemiError = "goto";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
Res = ParseContinueStatement(AttrList.take());
SemiError = "continue";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
Res = ParseBreakStatement(AttrList.take());
SemiError = "break";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
Res = ParseReturnStatement(AttrList.take());
SemiError = "return";
break;
case tok::kw_asm: {
if (Attr.HasAttr)
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
<< Attr.Range;
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
if (msAsm) return move(Res);
SemiError = "asm";
break;
}
case tok::kw_try: // C++ 15: try-block
return ParseCXXTryBlock(AttrList.take());
}
// If we reached this code, the statement must end in a semicolon.
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if (!Res.isInvalid()) {
// If the result was valid, then we do want to diagnose this. Use
// ExpectAndConsume to emit the diagnostic, even though we know it won't
// succeed.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, 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
///
StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
llvm::OwningPtr<AttributeList> AttrList(Attr);
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.
if (Tok.is(tok::kw___attribute))
AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes()));
StmtResult SubStmt(ParseStatement());
// Broken substmt shouldn't prevent the label from being added to the AST.
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
// FIXME: use attributes?
return Actions.ActOnLabelStmt(IdentTok.getLocation(),
IdentTok.getIdentifierInfo(),
ColonLoc, SubStmt.get());
}
/// ParseCaseStatement
/// labeled-statement:
/// 'case' constant-expression ':' statement
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
///
StmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
// FIXME: Use attributes?
delete Attr;
// It is very very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
// case 1:
// case 2:
// case 3:
// case 4:
// case 5: etc.
//
// Parsing this naively works, but is both inefficient and can cause us to run
// out of stack space in our recursive descent parser. As a special case,
// flatten this recursion into an iterative loop. This is complex and gross,
// but all the grossness is constrained to ParseCaseStatement (and some
// wierdness in the actions), so this is just local grossness :).
// TopLevelCase - This is the highest level we have parsed. 'case 1' in the
// example above.
StmtResult TopLevelCase(true);
// DeepestParsedCaseStmt - This is the deepest statement we have parsed, which
// gets updated each time a new case is parsed, and whose body is unset so
// far. When parsing 'case 4', this is the 'case 3' node.
StmtTy *DeepestParsedCaseStmt = 0;
// While we have case statements, eat and stack them.
do {
SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
ConsumeCodeCompletionToken();
}
/// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
/// Disable this form of error recovery while we're parsing the case
/// expression.
ColonProtectionRAIIObject ColonProtection(*this);
ExprResult LHS(ParseConstantExpression());
if (LHS.isInvalid()) {
SkipUntil(tok::colon);
return StmtError();
}
// GNU case range extension.
SourceLocation DotDotDotLoc;
ExprResult RHS;
if (Tok.is(tok::ellipsis)) {
Diag(Tok, diag::ext_gnu_case_range);
DotDotDotLoc = ConsumeToken();
RHS = ParseConstantExpression();
if (RHS.isInvalid()) {
SkipUntil(tok::colon);
return StmtError();
}
}
ColonProtection.restore();
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon_after) << "'case'";
SkipUntil(tok::colon);
return StmtError();
}
SourceLocation ColonLoc = ConsumeToken();
StmtResult Case =
Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc,
RHS.get(), ColonLoc);
// If we had a sema error parsing this case, then just ignore it and
// continue parsing the sub-stmt.
if (Case.isInvalid()) {
if (TopLevelCase.isInvalid()) // No parsed case stmts.
return ParseStatement();
// Otherwise, just don't add it as a nested case.
} else {
// If this is the first case statement we parsed, it becomes TopLevelCase.
// Otherwise we link it into the current chain.
Stmt *NextDeepest = Case.get();
if (TopLevelCase.isInvalid())
TopLevelCase = move(Case);
else
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
DeepestParsedCaseStmt = NextDeepest;
}
// Handle all case statements.
} while (Tok.is(tok::kw_case));
assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
// If we found a non-case statement, start by parsing it.
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
SubStmt = ParseStatement();
} else {
// Nicely diagnose the common error "switch (X) { case 4: }", which is
// not valid.
// FIXME: add insertion hint.
Diag(Tok, diag::err_label_end_of_compound_statement);
SubStmt = true;
}
// Broken sub-stmt shouldn't prevent forming the case statement properly.
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(SourceLocation());
// Install the body into the most deeply-nested case.
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
// Return the top level parsed statement tree.
return move(TopLevelCase);
}
/// ParseDefaultStatement
/// labeled-statement:
/// 'default' ':' statement
/// Note that this does not parse the 'statement' at the end.
///
StmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
//FIXME: Use attributes?
delete Attr;
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();
}
StmtResult SubStmt(ParseStatement());
if (SubStmt.isInvalid())
return StmtError();
return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
SubStmt.get(), getCurScope());
}
/// 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
///
StmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
bool isStmtExpr) {
//FIXME: Use attributes?
delete Attr;
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.
StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
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)) {
StmtResult R;
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.
// FIXME: This loses extension expressions in the AST!
SourceLocation ExtLoc = ConsumeToken();
while (Tok.is(tok::kw___extension__))
ConsumeToken();
CXX0XAttributeList Attr;
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
Attr = ParseCXX0XAttributes();
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
// __extension__ silences extension warnings in the subdeclaration.
// FIXME: Save the __extension__ on the decl as a node somehow?
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
Attr);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
// Otherwise this was a unary __extension__ marker.
ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
if (Res.isInvalid()) {
SkipUntil(tok::semi);
continue;
}
// FIXME: Use attributes?
// 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(Actions.MakeFullExpr(Res.get()));
}
}
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_arg(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(ExprResult &ExprResult,
Decl *&DeclResult,
SourceLocation Loc,
bool ConvertToBoolean) {
bool ParseError = false;
SourceLocation LParenLoc = ConsumeParen();
if (getLang().CPlusPlus)
ParseError = ParseCXXCondition(ExprResult, DeclResult, Loc,
ConvertToBoolean);
else {
ExprResult = ParseExpression();
DeclResult = 0;
// If required, convert to a boolean value.
if (!ExprResult.isInvalid() && ConvertToBoolean)
ExprResult
= Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprResult.get());
}
// 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 (ExprResult.isInvalid() && !DeclResult && 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
///
StmtResult Parser::ParseIfStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
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.
ExprResult CondExp;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true))
return StmtError();
FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get()));
// 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();
StmtResult ThenStmt(ParseStatement());
// Pop the 'if' scope if needed.
InnerScope.Exit();
// If it has an else, parse it.
SourceLocation ElseLoc;
SourceLocation ElseStmtLoc;
StmtResult ElseStmt;
if (Tok.is(tok::kw_else)) {
ElseLoc = ConsumeToken();
ElseStmtLoc = Tok.getLocation();
// 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));
ElseStmt = ParseStatement();
// 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() && !CondVar)
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, FullCondExp, CondVar, ThenStmt.get(),
ElseLoc, ElseStmt.get());
}
/// ParseSwitchStatement
/// switch-statement:
/// 'switch' '(' expression ')' statement
/// [C++] 'switch' '(' condition ')' statement
StmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
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.
ExprResult Cond;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false))
return StmtError();
StmtResult Switch
= Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar);
if (Switch.isInvalid()) {
// Skip the switch body.
// FIXME: This is not optimal recovery, but parsing the body is more
// dangerous due to the presence of case and default statements, which
// will have no place to connect back with the switch.
if (Tok.is(tok::l_brace)) {
ConsumeBrace();
SkipUntil(tok::r_brace, false, false);
} else
SkipUntil(tok::semi);
return move(Switch);
}
// 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.
StmtResult Body(ParseStatement());
// Pop the scopes.
InnerScope.Exit();
SwitchScope.Exit();
if (Body.isInvalid())
// FIXME: Remove the case statement list from the Switch statement.
Body = Actions.ActOnNullStmt(Tok.getLocation());
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
}
/// ParseWhileStatement
/// while-statement: [C99 6.8.5.1]
/// 'while' '(' expression ')' statement
/// [C++] 'while' '(' condition ')' statement
StmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
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.
ExprResult Cond;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true))
return StmtError();
FullExprArg FullCond(Actions.MakeFullExpr(Cond.get()));
// 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.
StmtResult Body(ParseStatement());
// Pop the body scope if needed.
InnerScope.Exit();
WhileScope.Exit();
if ((Cond.isInvalid() && !CondVar) || Body.isInvalid())
return StmtError();
return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get());
}
/// ParseDoStatement
/// do-statement: [C99 6.8.5.2]
/// 'do' statement 'while' '(' expression ')' ';'
/// Note: this lets the caller parse the end ';'.
StmtResult Parser::ParseDoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
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.
StmtResult 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.
SourceLocation LPLoc = ConsumeParen();
ExprResult Cond = ParseExpression();
SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc);
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, LPLoc,
Cond.get(), RPLoc);
}
/// 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
///
StmtResult Parser::ParseForStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
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 C99orCXXorObjC = getLang().C99 || getLang().CPlusPlus || getLang().ObjC1;
// 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 (C99orCXXorObjC)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope ForScope(this, ScopeFlags);
SourceLocation LParenLoc = ConsumeParen();
ExprResult Value;
bool ForEach = false;
StmtResult FirstPart;
bool SecondPartIsInvalid = false;
FullExprArg SecondPart(Actions);
ExprResult Collection;
FullExprArg ThirdPart(Actions);
Decl *SecondVar = 0;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
ConsumeCodeCompletionToken();
}
// 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 (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
AttributeList *AttrList = 0;
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
AttrList = ParseCXX0XAttributes().AttrList;
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
AttrList, false);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
Actions.ActOnForEachDeclStmt(DG);
// ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
ConsumeCodeCompletionToken();
}
Collection = ParseExpression();
} else {
Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
} else {
Value = ParseExpression();
// Turn the expression into a stmt.
if (!Value.isInvalid())
FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get()));
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy());
ConsumeCodeCompletionToken();
}
Collection = 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 {
ExprResult Second;
if (getLang().CPlusPlus)
ParseCXXCondition(Second, SecondVar, ForLoc, true);
else {
Second = ParseExpression();
if (!Second.isInvalid())
Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc,
Second.get());
}
SecondPartIsInvalid = Second.isInvalid();
SecondPart = Actions.MakeFullExpr(Second.get());
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
if (!SecondPartIsInvalid || SecondVar)
Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
// Parse the third part of the for specifier.
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
ExprResult Third = ParseExpression();
ThirdPart = Actions.MakeFullExpr(Third.take());
}
}
// 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,
C99orCXXorObjC && Tok.isNot(tok::l_brace));
// Read the body statement.
StmtResult 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, FirstPart.take(), SecondPart,
SecondVar, ThirdPart, RParenLoc, Body.take());
// FIXME: It isn't clear how to communicate the late destruction of
// C++ temporaries used to create the collection.
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(),
Collection.take(), RParenLoc,
Body.take());
}
/// ParseGotoStatement
/// jump-statement:
/// 'goto' identifier ';'
/// [GNU] 'goto' '*' expression ';'
///
/// Note: this lets the caller parse the end ';'.
///
StmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
StmtResult Res;
if (Tok.is(tok::identifier)) {
Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(),
Tok.getIdentifierInfo());
ConsumeToken();
} else if (Tok.is(tok::star)) {
// GNU indirect goto extension.
Diag(Tok, diag::ext_gnu_indirect_goto);
SourceLocation StarLoc = ConsumeToken();
ExprResult 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, R.take());
} else {
Diag(Tok, diag::err_expected_ident);
return StmtError();
}
return move(Res);
}
/// ParseContinueStatement
/// jump-statement:
/// 'continue' ';'
///
/// Note: this lets the caller parse the end ';'.
///
StmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
return Actions.ActOnContinueStmt(ContinueLoc, getCurScope());
}
/// ParseBreakStatement
/// jump-statement:
/// 'break' ';'
///
/// Note: this lets the caller parse the end ';'.
///
StmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
return Actions.ActOnBreakStmt(BreakLoc, getCurScope());
}
/// ParseReturnStatement
/// jump-statement:
/// 'return' expression[opt] ';'
StmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
// FIXME: Use attributes?
delete Attr;
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
ExprResult R;
if (Tok.isNot(tok::semi)) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteReturn(getCurScope());
ConsumeCodeCompletionToken();
SkipUntil(tok::semi, false, true);
return StmtError();
}
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, R.take());
}
/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this
/// routine is called to skip/ignore tokens that comprise the MS asm statement.
StmtResult 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));
}
Token t;
t.setKind(tok::string_literal);
t.setLiteralData("\"/*FIXME: not done*/\"");
t.clearFlag(Token::NeedsCleaning);
t.setLength(21);
ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0,
move_arg(Constraints), move_arg(Exprs),
AsmString.take(), move_arg(Clobbers),
Tok.getLocation(), true);
}
/// 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]
///
StmtResult 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, true, false);
// 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;
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
SkipUntil(tok::r_paren);
return StmtError();
}
Loc = ConsumeParen();
ExprResult AsmString(ParseAsmStringLiteral());
if (AsmString.isInvalid())
return StmtError();
llvm::SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
if (Tok.is(tok::r_paren)) {
// We have a simple asm expression like 'asm("foo")'.
SourceLocation RParenLoc = ConsumeParen();
return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
/*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
move_arg(Constraints), move_arg(Exprs),
AsmString.take(), move_arg(Clobbers),
RParenLoc);
}
// Parse Outputs, if present.
bool AteExtraColon = false;
if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
// In C++ mode, parse "::" like ": :".
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
if (!AteExtraColon &&
ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
}
unsigned NumOutputs = Names.size();
// Parse Inputs, if present.
if (AteExtraColon ||
Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
// In C++ mode, parse "::" like ": :".
if (AteExtraColon)
AteExtraColon = false;
else {
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
}
if (!AteExtraColon &&
ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
}
assert(Names.size() == Constraints.size() &&
Constraints.size() == Exprs.size() &&
"Input operand size mismatch!");
unsigned NumInputs = Names.size() - NumOutputs;
// Parse the clobbers, if present.
if (AteExtraColon || Tok.is(tok::colon)) {
if (!AteExtraColon)
ConsumeToken();
// Parse the asm-string list for clobbers if present.
if (Tok.isNot(tok::r_paren)) {
while (1) {
ExprResult Clobber(ParseAsmStringLiteral());
if (Clobber.isInvalid())
break;
Clobbers.push_back(Clobber.release());
if (Tok.isNot(tok::comma)) break;
ConsumeToken();
}
}
}
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile,
NumOutputs, NumInputs, Names.data(),
move_arg(Constraints), move_arg(Exprs),
AsmString.take(), move_arg(Clobbers),
RParenLoc);
}
/// ParseAsmOperands - Parse the asm-operands production as used by
/// asm-statement, assuming the leading ':' token was eaten.
///
/// [GNU] asm-operands:
/// asm-operand
/// asm-operands ',' asm-operand
///
/// [GNU] asm-operand:
/// asm-string-literal '(' expression ')'
/// '[' identifier ']' asm-string-literal '(' expression ')'
///
//
// FIXME: Avoid unnecessary std::string trashing.
bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
llvm::SmallVectorImpl<ExprTy *> &Constraints,
llvm::SmallVectorImpl<ExprTy *> &Exprs) {
// '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(II);
MatchRHSPunctuation(tok::r_square, Loc);
} else
Names.push_back(0);
ExprResult 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.
SourceLocation OpenLoc = ConsumeParen();
ExprResult Res(ParseExpression());
MatchRHSPunctuation(tok::r_paren, OpenLoc);
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;
}
Decl *Parser::ParseFunctionStatementBody(Decl *Decl) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
// 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.
StmtResult FnBody(ParseCompoundStatementBody());
// If the function body could not be parsed, make a bogus compoundstmt.
if (FnBody.isInvalid())
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
/// ParseFunctionTryBlock - Parse a C++ function-try-block.
///
/// function-try-block:
/// 'try' ctor-initializer[opt] compound-statement handler-seq
///
Decl *Parser::ParseFunctionTryBlock(Decl *Decl) {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, TryLoc,
"parsing function try block");
// Constructor initializer list?
if (Tok.is(tok::colon))
ParseConstructorInitializer(Decl);
SourceLocation LBraceLoc = Tok.getLocation();
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
// If we failed to parse the try-catch, we just give the function an empty
// compound statement as the body.
if (FnBody.isInvalid())
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
/// ParseCXXTryBlock - Parse a C++ try-block.
///
/// try-block:
/// 'try' compound-statement handler-seq
///
StmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
// FIXME: Add attributes?
delete Attr;
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
return ParseCXXTryBlockCommon(TryLoc);
}
/// 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]
///
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult TryBlock(ParseCompoundStatement(0));
if (TryBlock.isInvalid())
return move(TryBlock);
StmtVector Handlers(Actions);
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
CXX0XAttributeList Attr = ParseCXX0XAttributes();
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
<< Attr.Range;
}
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
while (Tok.is(tok::kw_catch)) {
StmtResult 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, TryBlock.take(), move_arg(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
/// '...'
///
StmtResult 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.
Decl *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS;
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
Declarator ExDecl(DS, Declarator::CXXCatchContext);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), 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));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult Block(ParseCompoundStatement(0));
if (Block.isInvalid())
return move(Block);
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}