[cfe-commits] r95042 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td lib/Parse/ParseDeclCXX.cpp test/Sema/declspec.c

Chris Lattner sabre at nondot.org
Mon Feb 1 17:23:29 PST 2010


Author: lattner
Date: Mon Feb  1 19:23:29 2010
New Revision: 95042

URL: http://llvm.org/viewvc/llvm-project?rev=95042&view=rev
Log:
Implement PR6180, substantially improving the diagnostics we get from
forgetting a ';' at the end of a struct.  For something like:

class c {
}
void foo() {}

we now produce:

t.cc:3:2: error: expected ';' after class
}
 ^
 ;

instead of:

t.cc:4:1: error: cannot combine with previous 'class' declaration specifier
void foo() {}
^
t.cc:2:7: error: 'class c' can not be defined in the result type of a function
class c {
      ^

GCC produces:

t.cc:4: error: new types may not be defined in a return type
t.cc:4: note: (perhaps a semicolon is missing after the definition of ‘c’)
t.cc:4: error: two or more data types in declaration of ‘foo’

I *think* I got the follow set right, but if I forgot anything, we'll start 
getting spurious "expected ';' after class" errors, let me know if you see
any.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/test/Sema/declspec.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=95042&r1=95041&r2=95042&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Feb  1 19:23:29 2010
@@ -305,6 +305,9 @@
 
 def err_expected_qualified_after_typename : Error<
   "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-template">;
 def err_expected_type_name_after_typename : Error<

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=95042&r1=95041&r2=95042&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Feb  1 19:23:29 2010
@@ -924,6 +924,42 @@
   if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
                          Result, Owned))
     Diag(StartLoc, DiagID) << PrevSpec;
+  
+  // At this point, we've successfully parsed a class-specifier in 'definition'
+  // form (e.g. "struct foo { int x; }".  While we could just return here, we're
+  // going to look at what comes after it to improve error recovery.  If an
+  // impossible token occurs next, we assume that the programmer forgot a ; at
+  // the end of the declaration and recover that way.
+  //
+  // This switch enumerates the valid "follow" set for definition.
+  if (TUK == Action::TUK_Definition) {
+    switch (Tok.getKind()) {
+    case tok::semi:               // struct foo {...} ;
+    case tok::star:               // struct foo {...} *       P;
+    case tok::amp:                // struct foo {...} &       R = ...
+    case tok::identifier:         // struct foo {...} V       ;
+    case tok::r_paren:            //(struct foo {...} )       {4}
+    case tok::annot_cxxscope:     // struct foo {...} a::     b;
+    case tok::annot_typename:     // struct foo {...} a       ::b;
+    case tok::annot_template_id:  // struct foo {...} a<int>  ::b;
+      break;
+        
+    case tok::r_brace:  // struct bar { struct foo {...} } 
+      // Missing ';' at end of struct is accepted as an extension in C mode.
+      if (!getLang().CPlusPlus) break;
+      // FALL THROUGH.
+    default:
+      ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
+                       TagType == DeclSpec::TST_class ? "class"
+                       : TagType == DeclSpec::TST_struct? "struct" : "union");
+      // 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.
+      PP.EnterToken(Tok);
+      Tok.setKind(tok::semi);  
+      break;
+    }
+  }
 }
 
 /// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
@@ -1168,7 +1204,8 @@
     return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
   }
 
-  // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+  // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
+  // is a bitfield.
   ColonProtectionRAIIObject X(*this);
   
   CXX0XAttributeList AttrList;

Modified: cfe/trunk/test/Sema/declspec.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/declspec.c?rev=95042&r1=95041&r2=95042&view=diff

==============================================================================
--- cfe/trunk/test/Sema/declspec.c (original)
+++ cfe/trunk/test/Sema/declspec.c Mon Feb  1 19:23:29 2010
@@ -7,11 +7,10 @@
 
 int typedef validTypeDecl() { } // expected-error {{function definition declared 'typedef'}}
 
-struct _zend_module_entry { }
-typedef struct _zend_function_entry { } // expected-error {{cannot combine with previous 'struct' declaration specifier}}
-static void buggy(int *x) { } // expected-error {{function definition declared 'typedef'}} \
-                              // expected-error {{cannot combine with previous 'typedef' declaration specifier}} \
-                              // expected-error {{cannot combine with previous 'struct' declaration specifier}}
+struct _zend_module_entry { }    // expected-error {{expected ';' after struct}}
+typedef struct _zend_function_entry { } // expected-error {{expected ';' after struct}} \
+                                        // expected-error {{declaration does not declare anything}}
+static void buggy(int *x) { }
 
 // Type qualifiers.
 typedef int f(void); 
@@ -22,3 +21,10 @@
 f *__restrict__ v4;   // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
 
 restrict struct hallo; // expected-error {{restrict requires a pointer or reference}}
+
+// PR6180
+struct test1 {
+} // expected-error {{expected ';' after struct}}
+
+void test2() {}
+





More information about the cfe-commits mailing list