]> granicus.if.org Git - clang/commitdiff
Fix PR7617 by not entering ParseFunctionDefinition when
authorChris Lattner <sabre@nondot.org>
Sun, 11 Jul 2010 22:42:07 +0000 (22:42 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 11 Jul 2010 22:42:07 +0000 (22:42 +0000)
a function prototype is followed by a declarator if we
aren't parsing a K&R style identifier list.

Also, avoid skipping randomly after a declaration if a
semicolon is missing.  Before we'd get:

t.c:3:1: error: expected function body after function declarator
void bar();
^

Now we get:

t.c:1:11: error: invalid token after top level declarator
void foo()
          ^
          ;

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108105 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/DeclSpec.h
include/clang/Parse/Parser.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseTemplate.cpp
lib/Parse/Parser.cpp
test/Parser/declarators.c

index a665730341c48b57db520e2d007fffd3ac663f7f..0e6dbecb36d68c344c9246581c65008b5986e9b1 100644 (file)
@@ -888,6 +888,13 @@ struct DeclaratorChunk {
       delete[] Exceptions;
     }
 
+    /// isKNRPrototype - Return true if this is a K&R style identifier list,
+    /// like "void foo(a,b,c)".  In a function definition, this will be followed
+    /// by the argument type definitions.
+    bool isKNRPrototype() const {
+      return !hasPrototype && NumArgs != 0;
+    }
+    
     SourceLocation getEllipsisLoc() const {
       return SourceLocation::getFromRawEncoding(EllipsisLoc);
     }
index 74293a4ba8ddaf7dda0fc818c5c665fea3123a6b..b8c294ada6914c595aff0469b2a9b40e7e41607c 100644 (file)
@@ -834,7 +834,7 @@ private:
   // C99 6.9: External Definitions.
   DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr);
   bool isDeclarationAfterDeclarator() const;
-  bool isStartOfFunctionDefinition();
+  bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
   DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
             AccessSpecifier AS = AS_none);
   DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
index 0334209f5044da42fcf82e9b06e0960779cf6d4b..62ef3ec0179bbce2cb4bb319458672aebf5ee616 100644 (file)
@@ -402,7 +402,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
       // start of a function definition in GCC-extended K&R C.
       !isDeclarationAfterDeclarator()) {
     
-    if (isStartOfFunctionDefinition()) {
+    if (isStartOfFunctionDefinition(D)) {
       if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
         Diag(Tok, diag::err_function_declared_typedef);
 
@@ -412,6 +412,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
 
       DeclPtrTy TheDecl = ParseFunctionDefinition(D);
       return Actions.ConvertDeclToDeclGroup(TheDecl);
+    }
+    
+    if (isDeclarationSpecifier()) {
+      // If there is an invalid declaration specifier right after the function
+      // prototype, then we must be in a missing semicolon case where this isn't
+      // actually a body.  Just fall through into the code that handles it as a
+      // prototype, and let the top-level code handle the erroneous declspec
+      // where it would otherwise expect a comma or semicolon.
     } else {
       Diag(Tok, diag::err_expected_fn_body);
       SkipUntil(tok::semi);
@@ -463,9 +471,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
                        Context == Declarator::FileContext
                          ? diag::err_invalid_token_after_toplevel_declarator
                          : diag::err_expected_semi_declaration)) {
-    SkipUntil(tok::r_brace, true, true);
-    if (Tok.is(tok::semi))
-      ConsumeToken();
+    // Okay, there was no semicolon and one was expected.  If we see a
+    // declaration specifier, just assume it was missing and continue parsing.
+    // Otherwise things are very confused and we skip to recover.
+    if (!isDeclarationSpecifier()) {
+      SkipUntil(tok::r_brace, true, true);
+      if (Tok.is(tok::semi))
+        ConsumeToken();
+    }
   }
 
   return Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
index 1713a4f9553e8336b407a3e22820fd479c2abf70..e1aaf91bd65895f59cfe818da80ad4d9f233d368 100644 (file)
@@ -238,7 +238,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
   }
 
   if (DeclaratorInfo.isFunctionDeclarator() &&
-      isStartOfFunctionDefinition()) {
+      isStartOfFunctionDefinition(DeclaratorInfo)) {
     if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
       Diag(Tok, diag::err_function_declared_typedef);
 
index b51dd26e8259b7aee2b3bb237cd36be0919b84b8..def2ca4088b47135d1f555156390f9e8e44b01ca 100644 (file)
@@ -521,12 +521,17 @@ bool Parser::isDeclarationAfterDeclarator() const {
 
 /// \brief Determine whether the current token, if it occurs after a
 /// declarator, indicates the start of a function definition.
-bool Parser::isStartOfFunctionDefinition() {
+bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
+  assert(Declarator.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+         "Isn't a function declarator");
   if (Tok.is(tok::l_brace))   // int X() {}
     return true;
   
-  if (!getLang().CPlusPlus)
-    return isDeclarationSpecifier();   // int X(f) int f; {}
+  // Handle K&R C argument lists: int X(f) int f; {}
+  if (!getLang().CPlusPlus &&
+      Declarator.getTypeObject(0).Fun.isKNRPrototype()) 
+    return isDeclarationSpecifier();
+  
   return Tok.is(tok::colon) ||         // X() : Base() {} (used for ctors)
          Tok.is(tok::kw_try);          // X() try { ... }
 }
@@ -649,7 +654,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
   // If this declaration was formed with a K&R-style identifier list for the
   // arguments, parse declarations for all of the args next.
   // int foo(a,b) int a; float b; {}
-  if (!FTI.hasPrototype && FTI.NumArgs != 0)
+  if (FTI.isKNRPrototype())
     ParseKNRParamDeclarations(D);
 
   // We should have either an opening brace or, in a C++ constructor,
index a82122ec35fbddd4b3f0b6ff936fdf1cb7f2a2f2..0e6f8bcf28f93dae1f557b89e1a9d1bf57e743b6 100644 (file)
@@ -86,3 +86,11 @@ struct test13 { int a; } (test13x);
 
 // <rdar://problem/8044088>
 struct X<foo::int> { }; // expected-error{{expected identifier or '('}}
+
+
+// PR7617 - error recovery on missing ;.
+
+void test14()  // expected-error {{invalid token after top level declarator}}
+
+void test14a();
+void *test14b = (void*)test14a; // Make sure test14a didn't get skipped.