Recover from errors in enum definition
authorSerge Pavlov <sepavloff@gmail.com>
Tue, 31 Dec 2013 06:26:03 +0000 (06:26 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Tue, 31 Dec 2013 06:26:03 +0000 (06:26 +0000)
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/include/clang/Basic/DiagnosticParseKinds.td
clang/lib/Parse/ParseDecl.cpp
clang/test/Parser/cxx0x-ambig.cpp
clang/test/Parser/declarators.c

index 2f14a50..15804e9 100644 (file)
@@ -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<
index 27d8531..f664cf2 100644 (file)
@@ -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;
     }
   }
 
index 4c22ed3..b06f432 100644 (file)
@@ -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 {
index 210a8e2..f77c2d2 100644 (file)
@@ -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
+};