aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Parse/DeclSpec.h7
-rw-r--r--include/clang/Parse/Parser.h2
-rw-r--r--lib/Parse/ParseDecl.cpp21
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/Parser.cpp13
-rw-r--r--test/Parser/declarators.c8
6 files changed, 43 insertions, 10 deletions
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index a665730341..0e6dbecb36 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -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);
}
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 74293a4ba8..b8c294ada6 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0334209f50..62ef3ec017 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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,
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 1713a4f955..e1aaf91bd6 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -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);
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index b51dd26e82..def2ca4088 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -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,
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index a82122ec35..0e6f8bcf28 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -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.