From 2e3ecb660ad8d66fffb3a86628f3c952e10f6963 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Tue, 31 Dec 2013 06:26:03 +0000 Subject: [PATCH] Recover from errors in enum definition Previously any error in enum definition body stopped parsing it. With this change parser tries to recover from errors. The patch fixes PR10982. Differential Revision: http://llvm-reviews.chandlerc.com/D2018 llvm-svn: 198259 --- .../clang/Basic/DiagnosticParseKinds.td | 2 ++ clang/lib/Parse/ParseDecl.cpp | 34 ++++++++++++++++--- clang/test/Parser/cxx0x-ambig.cpp | 4 +-- clang/test/Parser/declarators.c | 34 +++++++++++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 2f14a50cf70b..15804e99d9ee 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -354,6 +354,8 @@ def err_paren_after_colon_colon : Error< "unexpected parenthesis after '::'">; def err_function_definition_not_allowed : Error< "function definition is not allowed here">; +def err_expected_end_of_enumerator : Error< + "expected '= constant-expression' or end of enumerator definition">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 27d8531c1fdb..f664cf20409f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3888,7 +3888,16 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { Decl *LastEnumConstDecl = 0; // Parse the enumerator-list. - while (Tok.is(tok::identifier)) { + while (Tok.isNot(tok::r_brace)) { + // Parse enumerator. If failed, try skipping till the start of the next + // enumerator definition. + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch) && + TryConsumeToken(tok::comma)) + continue; + break; + } IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); @@ -3905,7 +3914,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { if (TryConsumeToken(tok::equal, EqualLoc)) { AssignedVal = ParseConstantExpression(); if (AssignedVal.isInvalid()) - SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch); + SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch); } // Install the enumerator constant into EnumDecl. @@ -3927,11 +3936,25 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { continue; } + // Emumerator definition must be finished, only comma or r_brace are + // allowed here. SourceLocation CommaLoc; - if (!TryConsumeToken(tok::comma, CommaLoc)) - break; + if (Tok.isNot(tok::r_brace) && !TryConsumeToken(tok::comma, CommaLoc)) { + if (EqualLoc.isValid()) + Diag(Tok.getLocation(), diag::err_expected_either) << tok::r_brace + << tok::comma; + else + Diag(Tok.getLocation(), diag::err_expected_end_of_enumerator); + if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch)) { + if (TryConsumeToken(tok::comma, CommaLoc)) + continue; + } else { + break; + } + } - if (Tok.isNot(tok::identifier)) { + // If comma is followed by r_brace, emit appropriate warning. + if (Tok.is(tok::r_brace) && CommaLoc.isValid()) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11) Diag(CommaLoc, getLangOpts().CPlusPlus ? diag::ext_enumerator_list_comma_cxx : @@ -3940,6 +3963,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { else if (getLangOpts().CPlusPlus11) Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) << FixItHint::CreateRemoval(CommaLoc); + break; } } diff --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp index 4c22ed3a9bbc..b06f432c4359 100644 --- a/clang/test/Parser/cxx0x-ambig.cpp +++ b/clang/test/Parser/cxx0x-ambig.cpp @@ -48,7 +48,7 @@ namespace bitfield { }; // This could be a bit-field. struct S2 { - enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected '}'}} expected-note {{to match}} + enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected identifier}} }; struct S3 { enum E : int { a = 1, b = 2, c = 3, d }; // ok, defines an enum @@ -64,7 +64,7 @@ namespace bitfield { }; // This could be a bit-field. struct S6 { - enum E : int { 1 }; // expected-error {{expected '}'}} expected-note {{to match}} + enum E : int { 1 }; // expected-error {{expected identifier}} }; struct U { diff --git a/clang/test/Parser/declarators.c b/clang/test/Parser/declarators.c index 210a8e2befc7..f77c2d2192fb 100644 --- a/clang/test/Parser/declarators.c +++ b/clang/test/Parser/declarators.c @@ -113,3 +113,37 @@ struct EnumBitfield { // expected-warning {{struct without named members is a GN struct S { int n; }: // expected-error {{expected ';'}} }; + +// PR10982 +enum E11 { + A1 = 1, +}; + +enum E12 { + , // expected-error{{expected identifier}} + A2 +}; +void func_E12(enum E12 *p) { *p = A2; } + +enum E13 { + 1D, // expected-error{{expected identifier}} + A3 +}; +void func_E13(enum E13 *p) { *p = A3; } + +enum E14 { + A4 12, // expected-error{{expected '= constant-expression' or end of enumerator definition}} + A4a +}; +void func_E14(enum E14 *p) { *p = A4a; } + +enum E15 { + A5=12 4, // expected-error{{expected '}' or ','}} + A5a +}; +void func_E15(enum E15 *p) { *p = A5a; } + +enum E16 { + A6; // expected-error{{expected '= constant-expression' or end of enumerator definition}} + A6a +};