#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/Sema/TypoCorrection.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
StmtResult
Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
SourceLocation *TrailingElseLoc) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX0XAttributes(Attrs, 0, true);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
OnlyStatement, TrailingElseLoc, Attrs);
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");
if (Attrs.empty() || Res.isInvalid())
return Res;
return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range);
}
StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
bool OnlyStatement, SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
const char *SemiError = 0;
StmtResult Res;
Retry:
tok::TokenKind Kind = Tok.getKind();
SourceLocation AtLoc;
switch (Kind) {
case tok::at: {
ProhibitAttributes(Attrs); AtLoc = ConsumeToken(); return ParseObjCAtStatement(AtLoc);
}
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
cutOffParsing();
return StmtError();
case tok::identifier: {
Token Next = NextToken();
if (Next.is(tok::colon)) { return ParseLabeledStatement(Attrs);
}
if (Next.isNot(tok::coloncolon)) {
CorrectionCandidateCallback DefaultValidator;
DefaultValidator.WantTypeSpecifiers =
Next.is(tok::l_paren) || Next.is(tok::less) ||
Next.is(tok::identifier) || Next.is(tok::star) ||
Next.is(tok::amp) || Next.is(tok::l_square);
DefaultValidator.WantExpressionKeywords =
Next.is(tok::l_paren) || Next.is(tok::identifier) ||
Next.is(tok::arrow) || Next.is(tok::period);
DefaultValidator.WantRemainingKeywords =
Next.is(tok::l_paren) || Next.is(tok::semi) ||
Next.is(tok::identifier) || Next.is(tok::l_brace);
DefaultValidator.WantCXXNamedCasts = false;
if (TryAnnotateName(false, &DefaultValidator)
== ANK_Error) {
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
}
if (Tok.isNot(tok::identifier))
goto Retry;
}
}
default: {
if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
DeclEnd, Attrs);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::err_expected_statement);
return StmtError();
}
return ParseExprStatement();
}
case tok::kw_case: return ParseCaseStatement();
case tok::kw_default: return ParseDefaultStatement();
case tok::l_brace: return ParseCompoundStatement();
case tok::semi: { bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro);
}
case tok::kw_if: return ParseIfStatement(TrailingElseLoc);
case tok::kw_switch: return ParseSwitchStatement(TrailingElseLoc);
case tok::kw_while: return ParseWhileStatement(TrailingElseLoc);
case tok::kw_do: Res = ParseDoStatement();
SemiError = "do/while";
break;
case tok::kw_for: return ParseForStatement(TrailingElseLoc);
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: {
ProhibitAttributes(Attrs);
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
Res = Actions.ActOnFinishFullStmt(Res.get());
if (msAsm) return Res;
SemiError = "asm";
break;
}
case tok::kw_try: return ParseCXXTryBlock();
case tok::kw___try:
ProhibitAttributes(Attrs); return ParseSEHTryBlock();
case tok::annot_pragma_vis:
ProhibitAttributes(Attrs);
HandlePragmaVisibility();
return StmtEmpty();
case tok::annot_pragma_pack:
ProhibitAttributes(Attrs);
HandlePragmaPack();
return StmtEmpty();
case tok::annot_pragma_msstruct:
ProhibitAttributes(Attrs);
HandlePragmaMSStruct();
return StmtEmpty();
case tok::annot_pragma_align:
ProhibitAttributes(Attrs);
HandlePragmaAlign();
return StmtEmpty();
case tok::annot_pragma_weak:
ProhibitAttributes(Attrs);
HandlePragmaWeak();
return StmtEmpty();
case tok::annot_pragma_weakalias:
ProhibitAttributes(Attrs);
HandlePragmaWeakAlias();
return StmtEmpty();
case tok::annot_pragma_redefine_extname:
ProhibitAttributes(Attrs);
HandlePragmaRedefineExtname();
return StmtEmpty();
case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs);
HandlePragmaFPContract();
return StmtEmpty();
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
return StmtEmpty();
}
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 Res;
}
StmtResult Parser::ParseExprStatement() {
Token OldToken = Tok;
ExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
}
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
Actions.CheckCaseExpression(Expr.get())) {
Diag(OldToken, diag::err_expected_case_before_expression)
<< FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
return ParseCaseStatement(true, Expr);
}
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
}
StmtResult Parser::ParseSEHTryBlock() {
assert(Tok.is(tok::kw___try) && "Expected '__try'");
SourceLocation Loc = ConsumeToken();
return ParseSEHTryBlockCommon(Loc);
}
StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
if(Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok,diag::err_expected_lbrace));
StmtResult TryBlock(ParseCompoundStatement());
if(TryBlock.isInvalid())
return TryBlock;
StmtResult Handler;
if (Tok.is(tok::identifier) &&
Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHExceptBlock(Loc);
} else if (Tok.is(tok::kw___finally)) {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHFinallyBlock(Loc);
} else {
return StmtError(Diag(Tok,diag::err_seh_expected_handler));
}
if(Handler.isInvalid())
return Handler;
return Actions.ActOnSEHTryBlock(false ,
TryLoc,
TryBlock.take(),
Handler.take());
}
StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
PoisonIdentifierRAIIObject raii(Ident__exception_code, false),
raii2(Ident___exception_code, false),
raii3(Ident_GetExceptionCode, false);
if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen))
return StmtError();
ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(false);
Ident___exception_info->setIsPoisoned(false);
Ident_GetExceptionInfo->setIsPoisoned(false);
}
ExprResult FilterExpr(ParseExpression());
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(true);
Ident___exception_info->setIsPoisoned(true);
Ident_GetExceptionInfo->setIsPoisoned(true);
}
if(FilterExpr.isInvalid())
return StmtError();
if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen))
return StmtError();
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
return Block;
return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
}
StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
raii2(Ident___abnormal_termination, false),
raii3(Ident_AbnormalTermination, false);
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
return Block;
return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
}
StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) {
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();
MaybeParseGNUAttributes(attrs);
StmtResult SubStmt(ParseStatement());
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
IdentTok.getLocation());
if (AttributeList *Attrs = attrs.getList()) {
Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
attrs.clear();
}
return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc,
SubStmt.get());
}
StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
StmtResult TopLevelCase(true);
Stmt *DeepestParsedCaseStmt = 0;
SourceLocation ColonLoc;
do {
SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
cutOffParsing();
return StmtError();
}
ColonProtectionRAIIObject ColonProtection(*this);
ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
MissingCase = false;
if (LHS.isInvalid()) {
SkipUntil(tok::colon);
return StmtError();
}
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.is(tok::colon)) {
ColonLoc = ConsumeToken();
} else if (Tok.is(tok::semi)) {
ColonLoc = ConsumeToken();
Diag(ColonLoc, diag::err_expected_colon_after) << "'case'"
<< FixItHint::CreateReplacement(ColonLoc, ":");
} else {
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
Diag(ExpectedLoc, diag::err_expected_colon_after) << "'case'"
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
StmtResult Case =
Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc,
RHS.get(), ColonLoc);
if (Case.isInvalid()) {
if (TopLevelCase.isInvalid()) return ParseStatement();
} else {
Stmt *NextDeepest = Case.get();
if (TopLevelCase.isInvalid())
TopLevelCase = Case;
else
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
DeepestParsedCaseStmt = NextDeepest;
}
} while (Tok.is(tok::kw_case));
assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
SubStmt = ParseStatement();
} else {
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
<< FixItHint::CreateInsertion(AfterColonLoc, " ;");
SubStmt = true;
}
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(SourceLocation());
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
return TopLevelCase;
}
StmtResult Parser::ParseDefaultStatement() {
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken();
SourceLocation ColonLoc;
if (Tok.is(tok::colon)) {
ColonLoc = ConsumeToken();
} else if (Tok.is(tok::semi)) {
ColonLoc = ConsumeToken();
Diag(ColonLoc, diag::err_expected_colon_after) << "'default'"
<< FixItHint::CreateReplacement(ColonLoc, ":");
} else {
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
Diag(ExpectedLoc, diag::err_expected_colon_after) << "'default'"
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
SubStmt = ParseStatement();
} else {
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
<< FixItHint::CreateInsertion(AfterColonLoc, " ;");
SubStmt = true;
}
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
SubStmt.get(), getCurScope());
}
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
return ParseCompoundStatement(isStmtExpr, Scope::DeclScope);
}
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags) {
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
ParseScope CompoundScope(this, ScopeFlags);
return ParseCompoundStatementBody(isStmtExpr);
}
StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
Sema::FPContractStateRAII SaveFPContractState(Actions);
InMessageExpressionRAIIObject InMessage(*this, false);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen())
return StmtError();
Sema::CompoundScopeRAII CompoundScope(Actions);
StmtVector Stmts;
while (Tok.is(tok::kw___label__)) {
SourceLocation LabelLoc = ConsumeToken();
Diag(LabelLoc, diag::ext_gnu_local_label);
SmallVector<Decl *, 8> DeclsInGroup;
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
break;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
if (!Tok.is(tok::comma))
break;
ConsumeToken();
}
DeclSpec DS(AttrFactory);
DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
DeclsInGroup.data(), DeclsInGroup.size());
StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
if (R.isUsable())
Stmts.push_back(R.release());
}
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
}
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsStatement(Stmts);
continue;
}
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
} else {
SourceLocation ExtLoc = ConsumeToken();
while (Tok.is(tok::kw___extension__))
ConsumeToken();
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs, 0, true);
if (isDeclarationStatement()) {
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Res = ParseDeclaration(Stmts,
Declarator::BlockContext, DeclEnd,
attrs);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
if (Res.isInvalid()) {
SkipUntil(tok::semi);
continue;
}
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get()));
}
}
if (R.isUsable())
Stmts.push_back(R.release());
}
SourceLocation CloseLoc = Tok.getLocation();
if (Tok.isNot(tok::r_brace)) {
Diag(Tok, diag::err_expected_rbrace);
Diag(T.getOpenLocation(), diag::note_matching) << "{";
} else {
if (!T.consumeClose())
CloseLoc = T.getCloseLocation();
}
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
Stmts, isStmtExpr);
}
bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
SourceLocation Loc,
bool ConvertToBoolean) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
if (getLangOpts().CPlusPlus)
ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean);
else {
ExprResult = ParseExpression();
DeclResult = 0;
if (!ExprResult.isInvalid() && ConvertToBoolean)
ExprResult
= Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprResult.get());
}
if (ExprResult.isInvalid() && !DeclResult && Tok.isNot(tok::r_paren)) {
SkipUntil(tok::semi);
if (Tok.isNot(tok::r_paren))
return true;
}
T.consumeClose();
while (Tok.is(tok::r_paren)) {
Diag(Tok, diag::err_extraneous_rparen_in_condition)
<< FixItHint::CreateRemoval(Tok.getLocation());
ConsumeParen();
}
return false;
}
StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
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 = getLangOpts().C99 || getLangOpts().CPlusPlus;
ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
ExprResult CondExp;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true))
return StmtError();
FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get(), IfLoc));
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
SourceLocation ThenStmtLoc = Tok.getLocation();
SourceLocation InnerStatementTrailingElseLoc;
StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc));
InnerScope.Exit();
SourceLocation ElseLoc;
SourceLocation ElseStmtLoc;
StmtResult ElseStmt;
if (Tok.is(tok::kw_else)) {
if (TrailingElseLoc)
*TrailingElseLoc = Tok.getLocation();
ElseLoc = ConsumeToken();
ElseStmtLoc = Tok.getLocation();
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
ElseStmt = ParseStatement();
InnerScope.Exit();
} else if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteAfterIf(getCurScope());
cutOffParsing();
return StmtError();
} else if (InnerStatementTrailingElseLoc.isValid()) {
Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
}
IfScope.Exit();
if (CondExp.isInvalid() && !CondVar)
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, FullCondExp, CondVar, ThenStmt.get(),
ElseLoc, ElseStmt.get());
}
StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
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 = getLangOpts().C99 || getLangOpts().CPlusPlus;
unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
ExprResult Cond;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false))
return StmtError();
StmtResult Switch
= Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar);
if (Switch.isInvalid()) {
if (Tok.is(tok::l_brace)) {
ConsumeBrace();
SkipUntil(tok::r_brace, false, false);
} else
SkipUntil(tok::semi);
return Switch;
}
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
StmtResult Body(ParseStatement(TrailingElseLoc));
InnerScope.Exit();
SwitchScope.Exit();
if (Body.isInvalid()) {
SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd();
Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation);
}
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
}
StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
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 = getLangOpts().C99 || getLangOpts().CPlusPlus;
unsigned ScopeFlags;
if (C99orCXX)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope WhileScope(this, ScopeFlags);
ExprResult Cond;
Decl *CondVar = 0;
if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true))
return StmtError();
FullExprArg FullCond(Actions.MakeFullExpr(Cond.get(), WhileLoc));
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
StmtResult Body(ParseStatement(TrailingElseLoc));
InnerScope.Exit();
WhileScope.Exit();
if ((Cond.isInvalid() && !CondVar) || Body.isInvalid())
return StmtError();
return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get());
}
StmtResult Parser::ParseDoStatement() {
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken();
unsigned ScopeFlags;
if (getLangOpts().C99)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope DoScope(this, ScopeFlags);
ParseScope InnerScope(this, Scope::DeclScope,
(getLangOpts().C99 || getLangOpts().CPlusPlus) &&
Tok.isNot(tok::l_brace));
StmtResult 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();
}
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
ProhibitAttributes(attrs);
ExprResult Cond = ParseExpression();
T.consumeClose();
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
return StmtError();
return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(),
Cond.get(), T.getCloseLocation());
}
StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
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 = getLangOpts().C99 || getLangOpts().CPlusPlus ||
getLangOpts().ObjC1;
unsigned ScopeFlags;
if (C99orCXXorObjC)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope ForScope(this, ScopeFlags);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ExprResult Value;
bool ForEach = false, ForRange = false;
StmtResult FirstPart;
bool SecondPartIsInvalid = false;
FullExprArg SecondPart(Actions);
ExprResult Collection;
ForRangeInit ForRangeInit;
FullExprArg ThirdPart(Actions);
Decl *SecondVar = 0;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
cutOffParsing();
return StmtError();
}
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
if (Tok.is(tok::semi)) { ProhibitAttributes(attrs);
ConsumeToken();
} else if (isForInitDeclaration()) { if (!C99orCXXorObjC) Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
StmtVector Stmts;
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
DeclEnd, attrs, false,
MightBeForRangeStmt ?
&ForRangeInit : 0);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
ForRange = true;
} else if (Tok.is(tok::semi)) { ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
Actions.ActOnForEachDeclStmt(DG);
ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
cutOffParsing();
return StmtError();
}
Collection = ParseExpression();
} else {
Diag(Tok, diag::err_expected_semi_for);
}
} else {
ProhibitAttributes(attrs);
Value = ParseExpression();
ForEach = isTokIdentifier_in();
if (!Value.isInvalid()) {
if (ForEach)
FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
else
FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get()));
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if (ForEach) {
ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy());
cutOffParsing();
return StmtError();
}
Collection = ParseExpression();
} else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) {
Diag(Tok, diag::err_for_range_expected_decl)
<< FirstPart.get()->getSourceRange();
SkipUntil(tok::r_paren, false, true);
SecondPartIsInvalid = true;
} else {
if (!Value.isInvalid()) {
Diag(Tok, diag::err_expected_semi_for);
} else {
SkipUntil(tok::r_paren, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
}
}
}
if (!ForEach && !ForRange) {
assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
if (Tok.is(tok::semi)) { } else if (Tok.is(tok::r_paren)) {
} else {
ExprResult Second;
if (getLangOpts().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(), ForLoc);
}
if (Tok.isNot(tok::semi)) {
if (!SecondPartIsInvalid || SecondVar)
Diag(Tok, diag::err_expected_semi_for);
else
SkipUntil(tok::r_paren, true, true);
}
if (Tok.is(tok::semi)) {
ConsumeToken();
}
if (Tok.isNot(tok::r_paren)) { ExprResult Third = ParseExpression();
ThirdPart = Actions.MakeFullExpr(Third.take());
}
}
T.consumeClose();
StmtResult ForRangeStmt;
StmtResult ForEachStmt;
if (ForRange) {
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
T.getCloseLocation(),
Sema::BFRK_Build);
} else if (ForEach) {
ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc,
FirstPart.take(),
Collection.take(),
T.getCloseLocation());
}
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXXorObjC && Tok.isNot(tok::l_brace));
StmtResult Body(ParseStatement(TrailingElseLoc));
InnerScope.Exit();
ForScope.Exit();
if (Body.isInvalid())
return StmtError();
if (ForEach)
return Actions.FinishObjCForCollectionStmt(ForEachStmt.take(),
Body.take());
if (ForRange)
return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.take(),
SecondPart, SecondVar, ThirdPart,
T.getCloseLocation(), Body.take());
}
StmtResult Parser::ParseGotoStatement() {
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken();
StmtResult Res;
if (Tok.is(tok::identifier)) {
LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
Tok.getLocation());
Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD);
ConsumeToken();
} else if (Tok.is(tok::star)) {
Diag(Tok, diag::ext_gnu_indirect_goto);
SourceLocation StarLoc = ConsumeToken();
ExprResult R(ParseExpression());
if (R.isInvalid()) { SkipUntil(tok::semi, false, true);
return StmtError();
}
Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take());
} else {
Diag(Tok, diag::err_expected_ident);
return StmtError();
}
return Res;
}
StmtResult Parser::ParseContinueStatement() {
SourceLocation ContinueLoc = ConsumeToken(); return Actions.ActOnContinueStmt(ContinueLoc, getCurScope());
}
StmtResult Parser::ParseBreakStatement() {
SourceLocation BreakLoc = ConsumeToken(); return Actions.ActOnBreakStmt(BreakLoc, getCurScope());
}
StmtResult Parser::ParseReturnStatement() {
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken();
ExprResult R;
if (Tok.isNot(tok::semi)) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteReturn(getCurScope());
cutOffParsing();
return StmtError();
}
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
R = ParseInitializer();
if (R.isUsable())
Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ?
diag::warn_cxx98_compat_generalized_initializer_lists :
diag::ext_generalized_initializer_lists)
<< R.get()->getSourceRange();
} else
R = ParseExpression();
if (R.isInvalid()) { SkipUntil(tok::semi, false, true);
return StmtError();
}
}
return Actions.ActOnReturnStmt(ReturnLoc, R.take());
}
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
Diag(AsmLoc, diag::warn_unsupported_msasm);
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
bool InBraces = false;
unsigned short savedBraceCount = 0;
bool InAsmComment = false;
FileID FID;
unsigned LineNo = 0;
unsigned NumTokensRead = 0;
SourceLocation LBraceLoc;
if (Tok.is(tok::l_brace)) {
InBraces = true;
savedBraceCount = BraceCount;
EndLoc = LBraceLoc = ConsumeBrace();
++NumTokensRead;
} else {
std::pair<FileID, unsigned> ExpAsmLoc =
SrcMgr.getDecomposedExpansionLoc(EndLoc);
FID = ExpAsmLoc.first;
LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
}
SourceLocation TokLoc = Tok.getLocation();
do {
if (Tok.is(tok::eof))
break;
if (!InAsmComment && Tok.is(tok::semi)) {
InAsmComment = true;
if (InBraces) {
std::pair<FileID, unsigned> ExpSemiLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
FID = ExpSemiLoc.first;
LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
}
} else if (!InBraces || InAsmComment) {
std::pair<FileID, unsigned> ExpLoc =
SrcMgr.getDecomposedExpansionLoc(TokLoc);
if (ExpLoc.first != FID ||
SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
if (!InBraces)
break;
InAsmComment = false;
} else if (!InAsmComment && Tok.is(tok::r_brace)) {
break;
}
}
if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&
BraceCount == (savedBraceCount + 1)) {
EndLoc = ConsumeBrace();
break;
}
EndLoc = TokLoc;
if (InAsmComment)
PP.Lex(Tok);
else {
AsmToks.push_back(Tok);
ConsumeAnyToken();
}
TokLoc = Tok.getLocation();
++NumTokensRead;
} while (1);
if (InBraces && BraceCount != savedBraceCount) {
Diag(Tok, diag::err_expected_rbrace);
Diag(LBraceLoc, diag::note_matching) << "{";
return StmtError();
} else if (NumTokensRead == 0) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
if (!getLangOpts().EmitMicrosoftInlineAsm) {
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;
ExprVector Exprs;
ExprVector Clobbers;
return Actions.ActOnGCCAsmStmt(AsmLoc, true, true, 0, 0, 0, Constraints,
Exprs, AsmString.take(), Clobbers, EndLoc);
}
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc,
llvm::makeArrayRef(AsmToks), EndLoc);
}
StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
!isTypeQualifier()) {
msAsm = true;
return ParseMicrosoftAsmStatement(AsmLoc);
}
DeclSpec DS(AttrFactory);
SourceLocation Loc = Tok.getLocation();
ParseTypeQualifierListOpt(DS, true, false);
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;
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
SkipUntil(tok::r_paren);
return StmtError();
}
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ExprResult AsmString(ParseAsmStringLiteral());
if (AsmString.isInvalid()) {
T.skipToEnd();
return StmtError();
}
SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints;
ExprVector Exprs;
ExprVector Clobbers;
if (Tok.is(tok::r_paren)) {
T.consumeClose();
return Actions.ActOnGCCAsmStmt(AsmLoc, true, isVolatile,
0, 0, 0,
Constraints, Exprs, AsmString.take(),
Clobbers, T.getCloseLocation());
}
bool AteExtraColon = false;
if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
if (!AteExtraColon &&
ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
}
unsigned NumOutputs = Names.size();
if (AteExtraColon ||
Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
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;
if (AteExtraColon || Tok.is(tok::colon)) {
if (!AteExtraColon)
ConsumeToken();
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();
}
}
}
T.consumeClose();
return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,
NumInputs, Names.data(), Constraints, Exprs,
AsmString.take(), Clobbers,
T.getCloseLocation());
}
bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
SmallVectorImpl<Expr *> &Constraints,
SmallVectorImpl<Expr *> &Exprs) {
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
while (1) {
if (Tok.is(tok::l_square)) {
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
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);
T.consumeClose();
} 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;
}
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ExprResult Res(ParseExpression());
T.consumeClose();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
return true;
}
Exprs.push_back(Res.release());
if (Tok.isNot(tok::comma)) return false;
ConsumeToken();
}
}
Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
if (SkipFunctionBodies && trySkippingFunctionBody()) {
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, 0);
}
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
StmtResult FnBody(ParseCompoundStatementBody());
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(), false);
}
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, TryLoc,
"parsing function try block");
if (Tok.is(tok::colon))
ParseConstructorInitializer(Decl);
else
Actions.ActOnDefaultCtorInitializers(Decl);
if (SkipFunctionBodies && trySkippingFunctionBody()) {
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, 0);
}
SourceLocation LBraceLoc = Tok.getLocation();
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(), false);
}
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
bool Parser::trySkippingFunctionBody() {
assert(Tok.is(tok::l_brace));
assert(SkipFunctionBodies &&
"Should only be called when SkipFunctionBodies is enabled");
TentativeParsingAction PA(*this);
ConsumeBrace();
if (SkipUntil(tok::r_brace, false, false,
PP.isCodeCompletionEnabled())) {
PA.Commit();
return true;
}
PA.Revert();
return false;
}
StmtResult Parser::ParseCXXTryBlock() {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
return ParseCXXTryBlockCommon(TryLoc);
}
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
StmtResult TryBlock(ParseCompoundStatement(false,
Scope::DeclScope|Scope::TryScope));
if (TryBlock.isInvalid())
return TryBlock;
if ((Tok.is(tok::identifier) &&
Tok.getIdentifierInfo() == getSEHExceptKeyword()) ||
Tok.is(tok::kw___finally)) {
StmtResult Handler;
if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHExceptBlock(Loc);
}
else {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHFinallyBlock(Loc);
}
if(Handler.isInvalid())
return Handler;
return Actions.ActOnSEHTryBlock(true ,
TryLoc,
TryBlock.take(),
Handler.take());
}
else {
StmtVector Handlers;
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
ProhibitAttributes(attrs);
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());
}
if (Handlers.empty())
return StmtError();
return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers);
}
}
StmtResult Parser::ParseCXXCatchBlock() {
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
SourceLocation CatchLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen))
return StmtError();
ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope);
Decl *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
Declarator ExDecl(DS, Declarator::CXXCatchContext);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
} else
ConsumeToken();
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return StmtError();
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
StmtResult Block(ParseCompoundStatement());
if (Block.isInvalid())
return Block;
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}
void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
IfExistsCondition Result;
if (ParseMicrosoftIfExistsCondition(Result))
return;
if (Result.Behavior == IEB_Dependent) {
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace);
return;
}
StmtResult Compound = ParseCompoundStatement();
if (Compound.isInvalid())
return;
StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc,
Result.IsIfExists,
Result.SS,
Result.Name,
Compound.get());
if (DepResult.isUsable())
Stmts.push_back(DepResult.get());
return;
}
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
Diag(Tok, diag::err_expected_lbrace);
return;
}
switch (Result.Behavior) {
case IEB_Parse:
break;
case IEB_Dependent:
llvm_unreachable("Dependent case handled above");
case IEB_Skip:
Braces.skipToEnd();
return;
}
while (Tok.isNot(tok::r_brace)) {
StmtResult R = ParseStatementOrDeclaration(Stmts, false);
if (R.isUsable())
Stmts.push_back(R.release());
}
Braces.consumeClose();
}