#include "clang/Parse/Parser.h"
#include "ExtensionRAIIObject.h"
#include "AstGuard.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
Parser::OwningStmtResult
Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
const char *SemiError = 0;
OwningStmtResult Res(Actions);
tok::TokenKind Kind = Tok.getKind();
SourceLocation AtLoc;
switch (Kind) {
case tok::at: {
AtLoc = ConsumeToken(); return ParseObjCAtStatement(AtLoc);
}
case tok::identifier:
if (NextToken().is(tok::colon)) { return ParseLabeledStatement();
}
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::err_expected_statement);
return StmtError();
}
OwningExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
SkipUntil(tok::semi);
return StmtError();
}
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(move(Expr));
}
case tok::kw_case: return ParseCaseStatement();
case tok::kw_default: return ParseDefaultStatement();
case tok::l_brace: return ParseCompoundStatement();
case tok::semi: return Actions.ActOnNullStmt(ConsumeToken());
case tok::kw_if: return ParseIfStatement();
case tok::kw_switch: return ParseSwitchStatement();
case tok::kw_while: return ParseWhileStatement();
case tok::kw_do: Res = ParseDoStatement();
SemiError = "do/while";
break;
case tok::kw_for: return ParseForStatement();
case tok::kw_goto: Res = ParseGotoStatement();
SemiError = "goto";
break;
case tok::kw_continue: Res = ParseContinueStatement();
SemiError = "continue";
break;
case tok::kw_break: Res = ParseBreakStatement();
SemiError = "break";
break;
case tok::kw_return: Res = ParseReturnStatement();
SemiError = "return";
break;
case tok::kw_asm: {
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
if (msAsm) return move(Res);
SemiError = "asm";
break;
}
case tok::kw_try: return ParseCXXTryBlock();
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if (!Res.isInvalid()) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError);
SkipUntil(tok::r_brace, true, true);
}
return move(Res);
}
Parser::OwningStmtResult Parser::ParseLabeledStatement() {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
Token IdentTok = Tok; ConsumeToken();
assert(Tok.is(tok::colon) && "Not a label!");
SourceLocation ColonLoc = ConsumeToken();
Action::AttrTy *AttrList = 0;
if (Tok.is(tok::kw___attribute))
AttrList = ParseAttributes();
OwningStmtResult SubStmt(ParseStatement());
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
return Actions.ActOnLabelStmt(IdentTok.getLocation(),
IdentTok.getIdentifierInfo(),
ColonLoc, move(SubStmt));
}
Parser::OwningStmtResult Parser::ParseCaseStatement() {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
OwningStmtResult TopLevelCase(Actions, true);
StmtTy *DeepestParsedCaseStmt = 0;
do {
SourceLocation CaseLoc = ConsumeToken();
OwningExprResult LHS(ParseConstantExpression());
if (LHS.isInvalid()) {
SkipUntil(tok::colon);
return StmtError();
}
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();
OwningStmtResult Case =
Actions.ActOnCaseStmt(CaseLoc, move(LHS), DotDotDotLoc,
move(RHS), ColonLoc);
if (Case.isInvalid()) {
if (TopLevelCase.isInvalid()) return ParseStatement();
} else {
StmtTy *NextDeepest = Case.get();
if (TopLevelCase.isInvalid())
TopLevelCase = move(Case);
else
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(Case));
DeepestParsedCaseStmt = NextDeepest;
}
} while (Tok.is(tok::kw_case));
assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
OwningStmtResult SubStmt(Actions);
if (Tok.isNot(tok::r_brace)) {
SubStmt = ParseStatement();
} else {
Diag(Tok, diag::err_label_end_of_compound_statement);
SubStmt = true;
}
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(SourceLocation());
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(SubStmt));
return move(TopLevelCase);
}
Parser::OwningStmtResult Parser::ParseDefaultStatement() {
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken();
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon_after) << "'default'";
SkipUntil(tok::colon);
return StmtError();
}
SourceLocation ColonLoc = ConsumeToken();
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(SubStmt), CurScope);
}
Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
ParseScope CompoundScope(this, Scope::DeclScope);
return ParseCompoundStatementBody(isStmtExpr);
}
Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
SourceLocation LBraceLoc = ConsumeBrace();
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 {
SourceLocation ExtLoc = ConsumeToken();
while (Tok.is(tok::kw___extension__))
ConsumeToken();
ExtensionRAIIObject O(Diags);
if (isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
OwningExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
if (Res.isInvalid()) {
SkipUntil(tok::semi);
continue;
}
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
R = Actions.ActOnExprStmt(move(Res));
}
}
if (R.isUsable())
Stmts.push_back(R.release());
}
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);
}
bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
bool OnlyAllowCondition) {
SourceLocation LParenLoc = ConsumeParen();
if (getLang().CPlusPlus)
CondExp = ParseCXXCondition();
else
CondExp = ParseExpression();
if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
SkipUntil(tok::semi);
if (Tok.isNot(tok::r_paren))
return true;
}
MatchRHSPunctuation(tok::r_paren, LParenLoc);
return false;
}
Parser::OwningStmtResult Parser::ParseIfStatement() {
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
SourceLocation IfLoc = ConsumeToken();
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;
ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
OwningExprResult CondExp(Actions);
if (ParseParenExprOrCondition(CondExp))
return StmtError();
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
SourceLocation ThenStmtLoc = Tok.getLocation();
OwningStmtResult ThenStmt(ParseStatement());
InnerScope.Exit();
SourceLocation ElseLoc;
SourceLocation ElseStmtLoc;
OwningStmtResult ElseStmt(Actions);
if (Tok.is(tok::kw_else)) {
ElseLoc = ConsumeToken();
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);
InnerScope.Exit();
}
IfScope.Exit();
if (CondExp.isInvalid())
return StmtError();
if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
(ThenStmt.isInvalid() && ElseStmt.get() == 0) ||
(ThenStmt.get() == 0 && ElseStmt.isInvalid())) {
return StmtError();
}
if (ThenStmt.isInvalid())
ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc);
if (ElseStmt.isInvalid())
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
return Actions.ActOnIfStmt(IfLoc, move(CondExp), move(ThenStmt),
ElseLoc, move(ElseStmt));
}
Parser::OwningStmtResult Parser::ParseSwitchStatement() {
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
SourceLocation SwitchLoc = ConsumeToken();
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;
unsigned ScopeFlags = Scope::BreakScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
OwningExprResult Cond(Actions);
if (ParseParenExprOrCondition(Cond))
return StmtError();
OwningStmtResult Switch(Actions);
if (!Cond.isInvalid())
Switch = Actions.ActOnStartOfSwitchStmt(move(Cond));
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
OwningStmtResult Body(ParseStatement());
InnerScope.Exit();
if (Body.isInvalid()) {
Body = Actions.ActOnNullStmt(Tok.getLocation());
}
SwitchScope.Exit();
if (Cond.isInvalid())
return StmtError();
return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
}
Parser::OwningStmtResult Parser::ParseWhileStatement() {
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
SourceLocation WhileLoc = Tok.getLocation();
ConsumeToken();
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;
unsigned ScopeFlags;
if (C99orCXX)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope WhileScope(this, ScopeFlags);
OwningExprResult Cond(Actions);
if (ParseParenExprOrCondition(Cond))
return StmtError();
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
OwningStmtResult Body(ParseStatement());
InnerScope.Exit();
WhileScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
return Actions.ActOnWhileStmt(WhileLoc, move(Cond), move(Body));
}
Parser::OwningStmtResult Parser::ParseDoStatement() {
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken();
unsigned ScopeFlags;
if (getLang().C99)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope DoScope(this, ScopeFlags);
ParseScope InnerScope(this, Scope::DeclScope,
(getLang().C99 || getLang().CPlusPlus) &&
Tok.isNot(tok::l_brace));
OwningStmtResult Body(ParseStatement());
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();
}
OwningExprResult Cond(Actions);
ParseParenExprOrCondition(Cond, true);
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, move(Cond));
}
Parser::OwningStmtResult Parser::ParseForStatement() {
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken();
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;
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();
OwningExprResult Value(Actions);
bool ForEach = false;
OwningStmtResult FirstPart(Actions);
OwningExprResult SecondPart(Actions), ThirdPart(Actions);
if (Tok.is(tok::semi)) { ConsumeToken();
} else if (isSimpleDeclaration()) { if (!C99orCXXorObjC) Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
false);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
ConsumeToken(); SecondPart = ParseExpression();
} else {
Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
} else {
Value = ParseExpression();
if (!Value.isInvalid())
FirstPart = Actions.ActOnExprStmt(move(Value));
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
ConsumeToken(); 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.");
if (Tok.is(tok::semi)) { } 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);
}
if (Tok.isNot(tok::r_paren)) ThirdPart = ParseExpression();
}
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXXorObjC && Tok.isNot(tok::l_brace));
OwningStmtResult Body(ParseStatement());
InnerScope.Exit();
ForScope.Exit();
if (Body.isInvalid())
return StmtError();
if (!ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
move(SecondPart), move(ThirdPart),
RParenLoc, move(Body));
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
move(FirstPart),
move(SecondPart),
RParenLoc, move(Body));
}
Parser::OwningStmtResult Parser::ParseGotoStatement() {
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken();
OwningStmtResult Res(Actions);
if (Tok.is(tok::identifier)) {
Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(),
Tok.getIdentifierInfo());
ConsumeToken();
} else if (Tok.is(tok::star)) {
Diag(Tok, diag::ext_gnu_indirect_goto);
SourceLocation StarLoc = ConsumeToken();
OwningExprResult R(ParseExpression());
if (R.isInvalid()) { SkipUntil(tok::semi, false, true);
return StmtError();
}
Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(R));
} else {
Diag(Tok, diag::err_expected_ident);
return StmtError();
}
return move(Res);
}
Parser::OwningStmtResult Parser::ParseContinueStatement() {
SourceLocation ContinueLoc = ConsumeToken(); return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
}
Parser::OwningStmtResult Parser::ParseBreakStatement() {
SourceLocation BreakLoc = ConsumeToken(); return Actions.ActOnBreakStmt(BreakLoc, CurScope);
}
Parser::OwningStmtResult Parser::ParseReturnStatement() {
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken();
OwningExprResult R(Actions);
if (Tok.isNot(tok::semi)) {
R = ParseExpression();
if (R.isInvalid()) { SkipUntil(tok::semi, false, true);
return StmtError();
}
}
return Actions.ActOnReturnStmt(ReturnLoc, move(R));
}
Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
if (Tok.is(tok::l_brace)) {
unsigned short savedBraceCount = BraceCount;
do {
ConsumeAnyToken();
} while (BraceCount > savedBraceCount && Tok.isNot(tok::eof));
} else {
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());
}
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);
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";
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<std::string, 4> Names;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
unsigned NumInputs = 0, NumOutputs = 0;
SourceLocation RParenLoc;
if (Tok.is(tok::r_paren)) {
isSimple = true;
RParenLoc = ConsumeParen();
} else {
if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
NumOutputs = Names.size();
if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
assert(Names.size() == Constraints.size() &&
Constraints.size() == Exprs.size()
&& "Input operand size mismatch!");
NumInputs = Names.size() - NumOutputs;
if (Tok.is(tok::colon)) {
ConsumeToken();
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 Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile,
NumOutputs, NumInputs, &Names[0],
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
RParenLoc);
}
bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
llvm::SmallVectorImpl<ExprTy*> &Constraints,
llvm::SmallVectorImpl<ExprTy*> &Exprs) {
if (Tok.isNot(tok::colon)) return false;
ConsumeToken();
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
while (1) {
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;
}
SourceLocation OpenLoc = ConsumeParen();
OwningExprResult Res(ParseExpression());
MatchRHSPunctuation(tok::r_paren, OpenLoc);
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
return true;
}
Exprs.push_back(Res.release());
if (Tok.isNot(tok::comma)) return false;
ConsumeToken();
}
return true;
}
Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
PrettyStackTraceActionsDecl CrashInfo(Decl, LBraceLoc, Actions,
PP.getSourceManager(),
"parsing function body");
OwningStmtResult FnBody(ParseCompoundStatementBody());
if (FnBody.isInvalid())
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
}
Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
PrettyStackTraceActionsDecl CrashInfo(Decl, TryLoc, Actions,
PP.getSourceManager(),
"parsing function try block");
if (Tok.is(tok::colon))
ParseConstructorInitializer(Decl);
SourceLocation LBraceLoc = Tok.getLocation();
OwningStmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
if (FnBody.isInvalid())
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
}
Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
return ParseCXXTryBlockCommon(TryLoc);
}
Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
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());
}
if (Handlers.empty())
return StmtError();
return Actions.ActOnCXXTryBlock(TryLoc, move(TryBlock), move_arg(Handlers));
}
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();
ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope);
DeclPtrTy ExceptionDecl;
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(Block));
}