From ca70f4fa1c4eae6a47c97c773b8e63803a43a90c Mon Sep 17 00:00:00 2001 From: Alp Toker <alp@nuanti.com> Date: Wed, 1 Jan 2014 03:08:43 +0000 Subject: [PATCH] ExpectAndConsume: Diagnose errors automatically 1) Teach ExpectAndConsume() to emit expected and expected-after diagnostics using the generic diagnostic descriptions added in r197972, eliminating another set of trivial err_expected_* variations while maintaining existing behaviour. 2) Lift SkipUntil() recovery out of ExpectAndConsume(). The Expect/Consume family of functions are primitive parser operations that now have the well-defined property of operating on single tokens. Factoring out recovery exposes opportunities for more consistent and tailored error recover at the call sites instead of just relying on a bottled SkipUntil formula. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198270 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticCommonKinds.td | 1 - include/clang/Basic/DiagnosticParseKinds.td | 8 -- include/clang/Parse/Parser.h | 12 +-- lib/Parse/ParseCXXInlineMethods.cpp | 6 +- lib/Parse/ParseDecl.cpp | 33 ++++---- lib/Parse/ParseDeclCXX.cpp | 47 ++++++----- lib/Parse/ParseExpr.cpp | 46 +++++----- lib/Parse/ParseExprCXX.cpp | 10 +-- lib/Parse/ParseObjc.cpp | 72 ++++++---------- lib/Parse/ParseStmt.cpp | 8 +- lib/Parse/ParseTemplate.cpp | 8 +- lib/Parse/Parser.cpp | 89 ++++++++++---------- lib/Parse/RAIIObjectsForParser.h | 4 +- 13 files changed, 164 insertions(+), 180 deletions(-) diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 12c3e759ce4..86c7e5502d8 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -40,7 +40,6 @@ def note_also_found : Note<"also found">; let CategoryName = "Lexical or Preprocessor Issue" in { -def err_expected_colon : Error<"expected ':'">; def err_expected_colon_after_setter_name : Error< "method name referenced in property setter attribute " "must end with ':'">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 15804e99d9e..f5f21391e9b 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -149,10 +149,6 @@ def err_expected_expression : Error<"expected expression">; def err_expected_type : Error<"expected a type">; def err_expected_external_declaration : Error<"expected external declaration">; def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">; -def err_expected_lparen : Error<"expected '('">; -def err_expected_rparen : Error<"expected ')'">; -def err_expected_rsquare : Error<"expected ']'">; -def err_expected_greater : Error<"expected '>'">; def err_expected_semi_declaration : Error< "expected ';' at end of declaration">; def err_expected_semi_decl_list : Error< @@ -182,12 +178,10 @@ def err_invalid_token_after_declarator_suggest_equal : Error< def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; def err_expected_less_after : Error<"expected '<' after '%0'">; -def err_expected_comma : Error<"expected ','">; def err_expected_lbrace_in_compound_literal : Error< "expected '{' in compound literal">; def err_expected_while : Error<"expected 'while' in do/while loop">; -def err_expected_semi_after : Error<"expected ';' after %0">; def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; def err_expected_semi_after_expr : Error<"expected ';' after expression">; def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; @@ -628,8 +622,6 @@ def err_expected_qualified_after_typename : Error< "expected a qualified name after 'typename'">; def warn_expected_qualified_after_typename : ExtWarn< "expected a qualified name after 'typename'">; -def err_expected_semi_after_tagdecl : Error< - "expected ';' after %0">; def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-type template">; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 1383698c3f0..42a0ad67e4a 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -681,12 +681,14 @@ private: /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the /// input. If so, it is consumed and false is returned. /// - /// If the input is malformed, this emits the specified diagnostic. Next, if - /// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is + /// If a trivial punctuator misspelling is encountered, a FixIt error + /// diagnostic is issued and false is returned after recovery. + /// + /// If the input is malformed, this emits the specified diagnostic and true is /// returned. - bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag, - const char *DiagMsg = "", - tok::TokenKind SkipToTok = tok::unknown); + bool ExpectAndConsume(tok::TokenKind ExpectedTok, + unsigned Diag = diag::err_expected, + const char *DiagMsg = ""); /// \brief The parser expects a semicolon and, if present, will consume it. /// diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 95502143b0f..feff7fb724a 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -96,9 +96,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) << Delete; SkipUntil(tok::semi); - } else { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - Delete ? "delete" : "default", tok::semi); + } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, + Delete ? "delete" : "default")) { + SkipUntil(tok::semi); } return FnD; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f664cf20409..60cb48f6760 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -171,10 +171,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, AttributeList::AS_GNU); } } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); SourceLocation Loc = Tok.getLocation(); - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; @@ -322,7 +322,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, } SourceLocation RParen = Tok.getLocation(); - if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + if (!ExpectAndConsume(tok::r_paren)) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Syntax); @@ -826,8 +826,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, IdentifierLoc *Platform = ParseIdentifierLoc(); // Parse the ',' following the platform name. - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return; + } // If we haven't grabbed the pointers for the identifiers // "introduced", "deprecated", and "obsoleted", do so now. @@ -857,11 +859,9 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, } UnavailableLoc = KeywordLoc; - if (Tok.isNot(tok::comma)) - break; - - ConsumeToken(); - continue; + if (TryConsumeToken(tok::comma)) + continue; + break; } if (Tok.isNot(tok::equal)) { @@ -2385,7 +2385,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation KWLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return; SourceLocation EllipsisLoc; @@ -2496,8 +2496,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, return false; Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()), - diag::err_expected_semi_after_tagdecl) - << DeclSpec::getSpecifierName(DS.getTypeSpecType()); + diag::err_expected_after) + << DeclSpec::getSpecifierName(DS.getTypeSpecType()) << tok::semi; // Try to recover from the typo, by dropping the tag definition and parsing // the problematic tokens as a type. @@ -3468,7 +3468,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } ConsumeToken(); - ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); + ExpectAndConsume(tok::l_paren); if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::semi); @@ -3479,7 +3479,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); ConsumeToken(); - ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); + ExpectAndConsume(tok::r_paren); } if (TryConsumeToken(tok::semi)) @@ -3757,8 +3757,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - "enum"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); PP.EnterToken(Tok); Tok.setKind(tok::semi); } @@ -3987,7 +3986,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // was probably forgotten. bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; if (!isValidAfterTypeSpecifier(CanBeBitfield)) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, "enum"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6098c0c8970..d3283eb21bd 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -263,8 +263,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, // Eat the ';'. DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name, - "", tok::semi); + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name)) + SkipUntil(tok::semi); return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc, Alias, SS, IdentLoc, Ident); @@ -428,10 +428,10 @@ Decl *Parser::ParseUsingDirective(unsigned Context, // Eat ';'. DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, - GNUAttr ? diag::err_expected_semi_after_attribute_list - : diag::err_expected_semi_after_namespace_name, - "", tok::semi); + if (ExpectAndConsume(tok::semi, + GNUAttr ? diag::err_expected_semi_after_attribute_list + : diag::err_expected_semi_after_namespace_name)) + SkipUntil(tok::semi); return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS, IdentLoc, NamespcName, attrs.getList()); @@ -588,10 +588,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Eat ';'. DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - !Attrs.empty() ? "attributes list" : - IsAliasDecl ? "alias declaration" : "using declaration", - tok::semi); + if (ExpectAndConsume(tok::semi, diag::err_expected_after, + !Attrs.empty() ? "attributes list" + : IsAliasDecl ? "alias declaration" + : "using declaration")) + SkipUntil(tok::semi); // Diagnose an attempt to declare a templated using-declaration. // In C++11, alias-declarations can be templates: @@ -664,8 +665,10 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ return 0; } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::semi); return 0; + } if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal) @@ -1373,8 +1376,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - DeclSpec::getSpecifierName(TagType)); + ExpectAndConsume(tok::semi, diag::err_expected_after, + DeclSpec::getSpecifierName(TagType)); PP.EnterToken(Tok); Tok.setKind(tok::semi); } @@ -1637,8 +1640,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition && (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { if (Tok.isNot(tok::semi)) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - DeclSpec::getSpecifierName(TagType)); + ExpectAndConsume(tok::semi, diag::err_expected_after, + DeclSpec::getSpecifierName(TagType)); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. @@ -1985,11 +1988,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // TODO: recover from mistakenly-qualified operator declarations. - if (ExpectAndConsume(tok::semi, - diag::err_expected_semi_after, - "access declaration", - tok::semi)) + if (ExpectAndConsume(tok::semi, diag::err_expected_after, + "access declaration")) { + SkipUntil(tok::semi); return; + } Actions.ActOnUsingDeclaration(getCurScope(), AS, /* HasUsingKeyword */ false, @@ -3306,11 +3309,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } } - if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + if (ExpectAndConsume(tok::r_square)) SkipUntil(tok::r_square); if (endLoc) *endLoc = Tok.getLocation(); - if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + if (ExpectAndConsume(tok::r_square)) SkipUntil(tok::r_square); } @@ -3381,7 +3384,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, ConsumeBracket(); SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); if (endLoc) *endLoc = Tok.getLocation(); - ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); + ExpectAndConsume(tok::r_square); } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 96f8f55a738..e7bc682211c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1296,7 +1296,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } if (!LHS.isInvalid()) { - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + if (ExpectAndConsume(tok::l_paren)) LHS = ExprError(); else Loc = PrevTokLocation; @@ -1698,8 +1698,10 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); Expr = ExprError(); + } TypeResult Ty = ParseTypeName(); @@ -1722,8 +1724,10 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { return ExprError(); } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); + } // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { @@ -1798,16 +1802,20 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { SkipUntil(tok::r_paren, StopAtSemi); return Cond; } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); + } ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return Expr1; } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); + } ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { @@ -1829,11 +1837,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", - tok::r_paren)) + + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); - + } + // Second argument is the type to bitcast to. TypeResult DestTy = ParseTypeName(); if (DestTy.isInvalid()) @@ -1857,11 +1866,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", - tok::r_paren)) + + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); - + } + // Second argument is the type to bitcast to. TypeResult DestTy = ParseTypeName(); if (DestTy.isInvalid()) @@ -1938,7 +1948,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Tok.is(tok::kw___bridge_retained) || Tok.is(tok::kw___bridge_retain))); if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { - if (Tok.isNot(tok::kw___bridge)) { + if (!TryConsumeToken(tok::kw___bridge)) { StringRef BridgeCastName = Tok.getName(); SourceLocation BridgeKeywordLoc = ConsumeToken(); if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) @@ -1946,8 +1956,6 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, << BridgeCastName << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); } - else - ConsumeToken(); // consume __bridge BridgeCast = false; } @@ -2195,7 +2203,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { Diag(KeyLoc, diag::ext_c11_generic_selection); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return ExprError(); ExprResult ControllingExpr; @@ -2210,7 +2218,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { } } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { + if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2242,7 +2250,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { } Types.push_back(Ty); - if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { + if (ExpectAndConsume(tok::colon)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 61dfbc6d58c..cef5b270e7b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1186,7 +1186,7 @@ ExprResult Parser::ParseCXXCasts() { SourceLocation RAngleBracketLoc = Tok.getLocation(); - if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) + if (ExpectAndConsume(tok::greater)) return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less); SourceLocation LParenLoc, RParenLoc; @@ -2747,7 +2747,7 @@ ExprResult Parser::ParseTypeTrait() { SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker Parens(*this, tok::l_paren); - if (Parens.expectAndConsume(diag::err_expected_lparen)) + if (Parens.expectAndConsume()) return ExprError(); SmallVector<ParsedType, 2> Args; @@ -2808,7 +2808,7 @@ ExprResult Parser::ParseArrayTypeTrait() { SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return ExprError(); TypeResult Ty = ParseTypeName(); @@ -2825,7 +2825,7 @@ ExprResult Parser::ParseArrayTypeTrait() { T.getCloseLocation()); } case ATT_ArrayExtent: { - if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2851,7 +2851,7 @@ ExprResult Parser::ParseExpressionTrait() { SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return ExprError(); ExprResult Expr = ParseExpression(); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index a36d2ea1b41..c8460c0e808 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -115,14 +115,12 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ClassLocs.push_back(Tok.getLocation()); ConsumeToken(); - if (Tok.isNot(tok::comma)) + if (!TryConsumeToken(tok::comma)) break; - - ConsumeToken(); } // Consume the ';'. - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) + if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class")) return Actions.ConvertDeclToDeclGroup(0); return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), @@ -613,8 +611,10 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter : diag::err_objc_expected_equal_for_getter; - if (ExpectAndConsume(tok::equal, DiagID, "", tok::r_paren)) + if (ExpectAndConsume(tok::equal, DiagID)) { + SkipUntil(tok::r_paren, StopAtSemi); return; + } if (Tok.is(tok::code_completion)) { if (IsSetter) @@ -639,10 +639,11 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); DS.setSetterName(SelIdent); - if (ExpectAndConsume(tok::colon, - diag::err_expected_colon_after_setter_name, "", - tok::r_paren)) + if (ExpectAndConsume(tok::colon, + diag::err_expected_colon_after_setter_name)) { + SkipUntil(tok::r_paren, StopAtSemi); return; + } } else { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); DS.setGetterName(SelIdent); @@ -1057,11 +1058,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Sema::ObjCArgInfo ArgInfo; // Each iteration parses a single keyword argument. - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected) << tok::colon; + if (ExpectAndConsume(tok::colon)) break; - } - ConsumeToken(); // Eat the ':'. ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. @@ -1211,9 +1209,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, ProtocolLocs.push_back(Tok.getLocation()); ConsumeToken(); - if (Tok.isNot(tok::comma)) + if (!TryConsumeToken(tok::comma)) break; - ConsumeToken(); } // Consume the '>'. @@ -1303,9 +1300,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } // Set the default visibility to private. - if (Tok.is(tok::at)) { // parse objc-visibility-spec - ConsumeToken(); // eat the @ sign - + if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtVisibility(getCurScope()); return cutOffParsing(); @@ -1423,9 +1418,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, IdentifierInfo *protocolName = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - if (Tok.is(tok::semi)) { // forward declaration of one protocol. + if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol. IdentifierLocPair ProtoInfo(protocolName, nameLoc); - ConsumeToken(); return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1, attrs.getList()); } @@ -1452,7 +1446,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, break; } // Consume the ';'. - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) + if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol")) return DeclGroupPtrTy(); return Actions.ActOnForwardProtocolDeclaration(AtLoc, @@ -1558,9 +1552,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { // We have a class implementation SourceLocation superClassLoc; IdentifierInfo *superClassId = 0; - if (Tok.is(tok::colon)) { + if (TryConsumeToken(tok::colon)) { // We have a super class - ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; // missing super class name. @@ -1673,8 +1666,7 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { } IdentifierInfo *classId = Tok.getIdentifierInfo(); SourceLocation classLoc = ConsumeToken(); // consume class-name; - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - "@compatibility_alias"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias"); return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc, classId, classLoc); } @@ -1712,10 +1704,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name SourceLocation propertyIvarLoc; - if (Tok.is(tok::equal)) { + if (TryConsumeToken(tok::equal)) { // property '=' ivar-name - ConsumeToken(); // consume '=' - if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId); cutOffParsing(); @@ -1735,7 +1725,7 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { break; ConsumeToken(); // consume ',' } - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@synthesize"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize"); return 0; } @@ -1772,7 +1762,7 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { break; ConsumeToken(); // consume ',' } - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@dynamic"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic"); return 0; } @@ -1790,7 +1780,7 @@ StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { } } // consume ';' - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw"); return Actions.ActOnObjCAtThrowStmt(atLoc, Res.take(), getCurScope()); } @@ -2485,8 +2475,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.push_back(selIdent); KeyLocs.push_back(Loc); - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected) << tok::colon; + if (ExpectAndConsume(tok::colon)) { // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. @@ -2494,7 +2483,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, return ExprError(); } - ConsumeToken(); // Eat the ':'. /// Parse the expression after ':' if (Tok.is(tok::code_completion)) { @@ -2761,8 +2749,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { } } - if (!TryConsumeToken(tok::colon)) { - Diag(Tok, diag::err_expected) << tok::colon; + if (ExpectAndConsume(tok::colon)) { SkipUntil(tok::r_brace, StopAtSemi); return ExprError(); } @@ -2787,10 +2774,8 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None }; Elements.push_back(Element); - - if (Tok.is(tok::comma)) - ConsumeToken(); // Eat the ','. - else if (Tok.isNot(tok::r_brace)) + + if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace)) return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace << tok::comma); } @@ -2880,14 +2865,13 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { unsigned nColons = 0; if (Tok.isNot(tok::r_paren)) { while (1) { - if (Tok.is(tok::coloncolon)) { // Handle :: in C++. + if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++. ++nColons; KeyIdents.push_back(0); - } else if (Tok.isNot(tok::colon)) - return ExprError(Diag(Tok, diag::err_expected) << tok::colon); - + } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'. + return ExprError(); ++nColons; - ConsumeToken(); // Eat the ':' or '::'. + if (Tok.is(tok::r_paren)) break; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 7f3be42fe6c..88d86056af1 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -449,7 +449,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { raii2(Ident___exception_code, false), raii3(Ident_GetExceptionCode, false); - if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen)) + if (ExpectAndConsume(tok::l_paren)) return StmtError(); ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); @@ -470,7 +470,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { if(FilterExpr.isInvalid()) return StmtError(); - if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) + if (ExpectAndConsume(tok::r_paren)) return StmtError(); StmtResult Block(ParseCompoundStatement()); @@ -543,7 +543,7 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { SubStmt = Actions.ProcessStmtAttributes( SubStmt.get(), TempAttrs.getList(), TempAttrs.Range); } else { - Diag(Tok, diag::err_expected_semi_after) << "__attribute__"; + Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi; } } @@ -2627,7 +2627,7 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { SourceLocation CatchLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return StmtError(); // C++ 3.3.2p3: diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 03325db8860..a5471f1294e 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -316,10 +316,8 @@ bool Parser::ParseTemplateParameters(unsigned Depth, Tok.setKind(tok::greater); RAngleLoc = Tok.getLocation(); Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); - } else if (Tok.is(tok::greater)) - RAngleLoc = ConsumeToken(); - else if (Failed) { - Diag(Tok.getLocation(), diag::err_expected_greater); + } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) { + Diag(Tok.getLocation(), diag::err_expected) << tok::greater; return true; } return false; @@ -675,7 +673,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, switch (Tok.getKind()) { default: - Diag(Tok.getLocation(), diag::err_expected_greater); + Diag(Tok.getLocation(), diag::err_expected) << tok::greater; return true; case tok::greater: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d1424899aec..a62d4c3d16a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -152,14 +152,8 @@ static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { } } -/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the -/// input. If so, it is consumed and false is returned. -/// -/// If the input is malformed, this emits the specified diagnostic. Next, if -/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is -/// returned. bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, - const char *Msg, tok::TokenKind SkipToTok) { + const char *Msg) { if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) { ConsumeAnyToken(); return false; @@ -168,29 +162,37 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, // Detect common single-character typos and resume. if (IsCommonTypo(ExpectedTok, Tok)) { SourceLocation Loc = Tok.getLocation(); - Diag(Loc, DiagID) - << Msg - << FixItHint::CreateReplacement(SourceRange(Loc), - getTokenSimpleSpelling(ExpectedTok)); + DiagnosticBuilder DB = Diag(Loc, DiagID); + DB << FixItHint::CreateReplacement(SourceRange(Loc), + getTokenSimpleSpelling(ExpectedTok)); + if (DiagID == diag::err_expected) + DB << ExpectedTok; + else if (DiagID == diag::err_expected_after) + DB << Msg << ExpectedTok; + else + DB << Msg; ConsumeAnyToken(); // Pretend there wasn't a problem. return false; } - const char *Spelling = 0; SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); - if (EndLoc.isValid() && - (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) { - // Show what code to insert to fix this problem. - Diag(EndLoc, DiagID) - << Msg - << FixItHint::CreateInsertion(EndLoc, Spelling); - } else - Diag(Tok, DiagID) << Msg; + const char *Spelling = 0; + if (EndLoc.isValid()) + Spelling = tok::getTokenSimpleSpelling(ExpectedTok); + + DiagnosticBuilder DB = + Spelling + ? Diag(EndLoc, DiagID) << FixItHint::CreateInsertion(EndLoc, Spelling) + : Diag(Tok, DiagID); + if (DiagID == diag::err_expected) + DB << ExpectedTok; + else if (DiagID == diag::err_expected_after) + DB << Msg << ExpectedTok; + else + DB << Msg; - if (SkipToTok != tok::unknown) - SkipUntil(SkipToTok, StopAtSemi); return true; } @@ -725,7 +727,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SourceLocation EndLoc; ExprResult Result(ParseSimpleAsm(&EndLoc)); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + ExpectAndConsume(tok::semi, diag::err_expected_after, "top-level asm block"); if (Result.isInvalid()) @@ -1127,28 +1129,22 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); - if (Tok.is(tok::equal)) { + if (TryConsumeToken(tok::equal)) { assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); - ConsumeToken(); - Actions.ActOnFinishFunctionBody(Res, 0, false); bool Delete = false; SourceLocation KWLoc; - if (Tok.is(tok::kw_delete)) { - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_deleted_function : - diag::ext_deleted_function); - - KWLoc = ConsumeToken(); + if (TryConsumeToken(tok::kw_delete, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_deleted_function + : diag::ext_deleted_function); Actions.SetDeclDeleted(Res, KWLoc); Delete = true; - } else if (Tok.is(tok::kw_default)) { - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_defaulted_function : - diag::ext_defaulted_function); - - KWLoc = ConsumeToken(); + } else if (TryConsumeToken(tok::kw_default, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_defaulted_function + : diag::ext_defaulted_function); Actions.SetDeclDefaulted(Res, KWLoc); } else { llvm_unreachable("function definition after = not 'delete' or 'default'"); @@ -1158,9 +1154,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) << Delete; SkipUntil(tok::semi); - } else { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - Delete ? "delete" : "default", tok::semi); + } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, + Delete ? "delete" : "default")) { + SkipUntil(tok::semi); } return Res; @@ -2033,12 +2029,15 @@ bool BalancedDelimiterTracker::diagnoseOverflow() { } bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, - const char *Msg, - tok::TokenKind SkipToToc ) { + const char *Msg, + tok::TokenKind SkipToTok) { LOpen = P.Tok.getLocation(); - if (P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) + if (P.ExpectAndConsume(Kind, DiagID, Msg)) { + if (SkipToTok != tok::unknown) + P.SkipUntil(SkipToTok, Parser::StopAtSemi); return true; - + } + if (getDepth() < MaxDepth) return false; diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index f68a2e09fe9..711dc2a7c4d 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -415,8 +415,8 @@ namespace clang { return diagnoseOverflow(); } - - bool expectAndConsume(unsigned DiagID, + + bool expectAndConsume(unsigned DiagID = diag::err_expected, const char *Msg = "", tok::TokenKind SkipToTok = tok::unknown); bool consumeClose() { -- GitLab