diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-10-12 16:37:45 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-10-12 16:37:45 +0000 |
commit | 4a8dfb511e8f84b2e38b7a86d8ddf05ac1e1a41b (patch) | |
tree | 51429fab5effd4a81368c423996e314d702e1bad /lib/Parse/Parser.cpp | |
parent | d41679d6881d2b424d8b3600fc774308087735a7 (diff) |
Introduce BalancedDelimiterTracker, to better track open/close
delimiter pairs and detect when we exceed the implementation limit for
nesting depth, from Aaron Ballman!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141782 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/Parser.cpp')
-rw-r--r-- | lib/Parse/Parser.cpp | 107 |
1 files changed, 70 insertions, 37 deletions
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 05a2b15abf..c90964381f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -122,34 +122,6 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, << FixItHint::CreateInsertion(EndLoc, ")"); } -/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), -/// this helper function matches and consumes the specified RHS token if -/// present. If not present, it emits a corresponding diagnostic indicating -/// that the parser failed to match the RHS of the token at LHSLoc. -SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, - SourceLocation LHSLoc) { - - if (Tok.is(RHSTok)) - return ConsumeAnyToken(); - - SourceLocation R = Tok.getLocation(); - const char *LHSName = "unknown"; - diag::kind DID = diag::err_parse_error; - switch (RHSTok) { - default: break; - case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; - case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; - case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; - case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; - case tok::greatergreatergreater: - LHSName = "<<<"; DID = diag::err_expected_ggg; break; - } - Diag(Tok, DID); - Diag(LHSLoc, diag::note_matching) << LHSName; - SkipUntil(RHSTok); - return R; -} - static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { switch (ExpectedTok) { case tok::semi: return Tok.is(tok::colon); // : for ; @@ -1147,13 +1119,12 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { ConsumeToken(); } - if (Tok.isNot(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; return ExprError(); } - Loc = ConsumeParen(); - ExprResult Result(ParseAsmStringLiteral()); if (Result.isInvalid()) { @@ -1162,9 +1133,10 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { *EndLoc = Tok.getLocation(); ConsumeAnyToken(); } else { - Loc = MatchRHSPunctuation(tok::r_paren, Loc); + // Close the paren and get the location of the end bracket + T.consumeClose(); if (EndLoc) - *EndLoc = Loc; + *EndLoc = T.getCloseLocation(); } return move(Result); @@ -1489,13 +1461,12 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { Token Condition = Tok; SourceLocation IfExistsLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - if (Tok.isNot(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; SkipUntil(tok::semi); return true; } - ConsumeParen(); // eat the '('. // Parse nested-name-specifier. CXXScopeSpec SS; @@ -1514,7 +1485,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { return true; } - if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return true; // Check if the symbol exists. @@ -1581,3 +1553,64 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport() { return Actions.ConvertDeclToDeclGroup(Import.get()); } + +bool Parser::BalancedDelimiterTracker::consumeOpen() { + // Try to consume the token we are holding + if (P.Tok.is(Kind)) { + P.QuantityTracker.push(Kind); + Cleanup = true; + if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { + LOpen = P.ConsumeAnyToken(); + return false; + } else { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + } + } + return true; +} + +bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, + const char *Msg, + tok::TokenKind SkipToToc ) { + LOpen = P.Tok.getLocation(); + if (!P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) { + P.QuantityTracker.push(Kind); + Cleanup = true; + if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { + return false; + } else { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + } + } + return true; +} + +bool Parser::BalancedDelimiterTracker::consumeClose() { + if (P.Tok.is(Close)) { + LClose = P.ConsumeAnyToken(); + if (Cleanup) + P.QuantityTracker.pop(Kind); + + Cleanup = false; + return false; + } else { + const char *LHSName = "unknown"; + diag::kind DID = diag::err_parse_error; + switch (Close) { + default: break; + case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; + case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; + case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; + case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; + case tok::greatergreatergreater: + LHSName = "<<<"; DID = diag::err_expected_ggg; break; + } + P.Diag(P.Tok, DID); + P.Diag(LOpen, diag::note_matching) << LHSName; + if (P.SkipUntil(Close)) + LClose = P.Tok.getLocation(); + } + return true; +} |