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
This commit is contained in:
Alp Toker 2014-01-01 03:08:43 +00:00
parent f1c0e48372
commit ca70f4fa1c
13 changed files with 164 additions and 180 deletions

View File

@ -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 ':'">;

View File

@ -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">;

View File

@ -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.
///

View File

@ -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;

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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;

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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() {